7

Possiedo un provider di contenuti personalizzato per il mio set di applicazioni Android e una delle cose che è necessario esporre è un piccolo array di byte (20-30 KiB). L'URI per questi blob assomiglia:Passaggio blob binario tramite un provider di contenuti

content://my.authority/blob/# 

dove # è il numero di riga; il cursore risultante ha la colonna standard _id e una colonna di dati. Io sto usando un MatrixCursor nel metodo del provider query():

byte[] byteData = getMyByteData(); 
MatrixCursor mc = new MatrixCursor(COLUMNS); 
mc.addRow(new Object[] { id, byteData }); 

Più tardi, nella domanda di consumo dei dati, lo faccio:

Cursor c = managedQuery(uri, null, null, null, null); 
c.moveToFirst(); 
byte[] data = c.getBlob(c.getColumnIndexOrThrow("data")); 

Tuttavia, i dati non contiene il contenuto del mio byte originale matrice; piuttosto, contiene qualcosa come [[email protected], che sembra più l'indirizzo dell'array che il contenuto. Ho provato a racchiudere l'array di byte in un'implementazione di java.sql.Blob, immaginando che potrebbe essere in cerca di questo poiché il sottosistema del content provider è stato scritto per essere facile da usare con SQLite, ma non è stato di aiuto.

Qualcuno ha ottenuto che funzioni? Se i dati erano nel file system, ci sono metodi in ContentProvider che potrei usare per fornire un client InputStream marshalling al client, ma i dati che sto tentando di inviare vivi come risorsa nell'APK del content provider.

+0

BTW Mi rivolgo a una versione piuttosto vecchia (Android-3) se è importante. – user308405

+0

Capisco che tu abbia risolto questo problema. Qualche possibilità che tu condivida con il resto di noi? –

risposta

4

Non è possibile utilizzare uno MatrixCursor per inviare l'array di byte. Questo perché dipende dal metodo AbstractCursor#fillWindow che riempie lo CursorWindow utilizzando Object#toString. Quindi, ciò che sta accadendo è che viene chiamato il metodo dell'array di byte toString e lo memorizza invece del contenuto dell'array di byte che è quello che vuoi. L'unico modo che posso vedere è di implementare il proprio cursore che riempirà lo CursorWindow in modo appropriato per un array di byte.

+0

Grazie, temevo che Strings fosse quello che stava succedendo a un certo livello. Speravo di non dover implementare il mio Cursore, ma questa è la strada che farò. – user308405

+0

Hai implementato il tuo cursore? Sarei molto interessato al tuo lavoro! –

1

È necessario eseguire l'override di fillWindow nell'implementazione di AbstractCursor. Eccone uno che funziona su un fornitore di contenuti per JUST BLOB

 public void fillWindow(int position, CursorWindow window) { 
      if (position < 0 || position >= getCount()) { 
       return; 
      } 
      window.acquireReference(); 
      try { 
       int oldpos = mPos; 
       mPos = position - 1; 
       window.clear(); 
       window.setStartPosition(position); 
       int columnNum = getColumnCount(); 
       window.setNumColumns(columnNum); 
       while (moveToNext() && window.allocRow()) {    
        for (int i = 0; i < columnNum; i++) { 
         byte [] field = getBlob(i); 
         if (field != null) { 
          if (!window.putBlob(field, mPos, i)) { 
           window.freeLastRow(); 
           break; 
          } 
         } else { 
          if (!window.putNull(mPos, i)) { 
           window.freeLastRow(); 
           break; 
          } 
         } 
        } 
       } 

       mPos = oldpos; 
      } catch (IllegalStateException e){ 
       // simply ignore it 
      } finally { 
       window.releaseReference(); 
      } 
     } 
7

Ottieni MatrixCursor da Ice Cream Sandwich. Implementa correttamente getBlob.

Il codice sorgente modificato è di sotto, se si desidera utilizzarlo. Puoi usarlo nei progetti Android 1.6+.

/* 
* Copyright (C) 2007 The Android Open Source Project 
* 
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
*  http://www.apache.org/licenses/LICENSE-2.0 
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an "AS IS" BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License. 
*/ 

package yuku.androidsdk.android.database.icsmatrixcursor; 

import android.database.*; 

import java.util.*; 

/** 
* A mutable cursor implementation backed by an array of {@code Object}s. Use 
* {@link #newRow()} to add rows. Automatically expands internal capacity 
* as needed. 
*/ 
public class MatrixCursor extends AbstractCursor { 

    private final String[] columnNames; 
    private Object[] data; 
    private int rowCount = 0; 
    private final int columnCount; 

    /** 
    * Constructs a new cursor with the given initial capacity. 
    * 
    * @param columnNames names of the columns, the ordering of which 
    * determines column ordering elsewhere in this cursor 
    * @param initialCapacity in rows 
    */ 
    public MatrixCursor(String[] columnNames, int initialCapacity) { 
     this.columnNames = columnNames; 
     this.columnCount = columnNames.length; 

     if (initialCapacity < 1) { 
      initialCapacity = 1; 
     } 

     this.data = new Object[columnCount * initialCapacity]; 
    } 

    /** 
    * Constructs a new cursor. 
    * 
    * @param columnNames names of the columns, the ordering of which 
    * determines column ordering elsewhere in this cursor 
    */ 
    public MatrixCursor(String[] columnNames) { 
     this(columnNames, 16); 
    } 

    /** 
    * Gets value at the given column for the current row. 
    */ 
    private Object get(int column) { 
     if (column < 0 || column >= columnCount) { 
      throw new CursorIndexOutOfBoundsException("Requested column: " 
        + column + ", # of columns: " + columnCount); 
     } 
     if (mPos < 0) { 
      throw new CursorIndexOutOfBoundsException("Before first row."); 
     } 
     if (mPos >= rowCount) { 
      throw new CursorIndexOutOfBoundsException("After last row."); 
     } 
     return data[mPos * columnCount + column]; 
    } 

    /** 
    * Adds a new row to the end and returns a builder for that row. Not safe 
    * for concurrent use. 
    * 
    * @return builder which can be used to set the column values for the new 
    * row 
    */ 
    public RowBuilder newRow() { 
     rowCount++; 
     int endIndex = rowCount * columnCount; 
     ensureCapacity(endIndex); 
     int start = endIndex - columnCount; 
     return new RowBuilder(start, endIndex); 
    } 

    /** 
    * Adds a new row to the end with the given column values. Not safe 
    * for concurrent use. 
    * 
    * @throws IllegalArgumentException if {@code columnValues.length != 
    * columnNames.length} 
    * @param columnValues in the same order as the the column names specified 
    * at cursor construction time 
    */ 
    public void addRow(Object[] columnValues) { 
     if (columnValues.length != columnCount) { 
      throw new IllegalArgumentException("columnNames.length = " 
        + columnCount + ", columnValues.length = " 
        + columnValues.length); 
     } 

     int start = rowCount++ * columnCount; 
     ensureCapacity(start + columnCount); 
     System.arraycopy(columnValues, 0, data, start, columnCount); 
    } 

    /** 
    * Adds a new row to the end with the given column values. Not safe 
    * for concurrent use. 
    * 
    * @throws IllegalArgumentException if {@code columnValues.size() != 
    * columnNames.length} 
    * @param columnValues in the same order as the the column names specified 
    * at cursor construction time 
    */ 
    public void addRow(Iterable<?> columnValues) { 
     int start = rowCount * columnCount; 
     int end = start + columnCount; 
     ensureCapacity(end); 

     if (columnValues instanceof ArrayList<?>) { 
      addRow((ArrayList<?>) columnValues, start); 
      return; 
     } 

     int current = start; 
     Object[] localData = data; 
     for (Object columnValue : columnValues) { 
      if (current == end) { 
       // TODO: null out row? 
       throw new IllegalArgumentException(
         "columnValues.size() > columnNames.length"); 
      } 
      localData[current++] = columnValue; 
     } 

     if (current != end) { 
      // TODO: null out row? 
      throw new IllegalArgumentException(
        "columnValues.size() < columnNames.length"); 
     } 

     // Increase row count here in case we encounter an exception. 
     rowCount++; 
    } 

    /** Optimization for {@link ArrayList}. */ 
    private void addRow(ArrayList<?> columnValues, int start) { 
     int size = columnValues.size(); 
     if (size != columnCount) { 
      throw new IllegalArgumentException("columnNames.length = " 
        + columnCount + ", columnValues.size() = " + size); 
     } 

     rowCount++; 
     Object[] localData = data; 
     for (int i = 0; i < size; i++) { 
      localData[start + i] = columnValues.get(i); 
     } 
    } 

    /** Ensures that this cursor has enough capacity. */ 
    private void ensureCapacity(int size) { 
     if (size > data.length) { 
      Object[] oldData = this.data; 
      int newSize = data.length * 2; 
      if (newSize < size) { 
       newSize = size; 
      } 
      this.data = new Object[newSize]; 
      System.arraycopy(oldData, 0, this.data, 0, oldData.length); 
     } 
    } 

    /** 
    * Builds a row, starting from the left-most column and adding one column 
    * value at a time. Follows the same ordering as the column names specified 
    * at cursor construction time. 
    */ 
    public class RowBuilder { 

     private int index; 
     private final int endIndex; 

     RowBuilder(int index, int endIndex) { 
      this.index = index; 
      this.endIndex = endIndex; 
     } 

     /** 
     * Sets the next column value in this row. 
     * 
     * @throws CursorIndexOutOfBoundsException if you try to add too many 
     * values 
     * @return this builder to support chaining 
     */ 
     public RowBuilder add(Object columnValue) { 
      if (index == endIndex) { 
       throw new CursorIndexOutOfBoundsException(
         "No more columns left."); 
      } 

      data[index++] = columnValue; 
      return this; 
     } 
    } 

    // AbstractCursor implementation. 

    @Override 
    public int getCount() { 
     return rowCount; 
    } 

    @Override 
    public String[] getColumnNames() { 
     return columnNames; 
    } 

    @Override 
    public String getString(int column) { 
     Object value = get(column); 
     if (value == null) return null; 
     return value.toString(); 
    } 

    @Override 
    public short getShort(int column) { 
     Object value = get(column); 
     if (value == null) return 0; 
     if (value instanceof Number) return ((Number) value).shortValue(); 
     return Short.parseShort(value.toString()); 
    } 

    @Override 
    public int getInt(int column) { 
     Object value = get(column); 
     if (value == null) return 0; 
     if (value instanceof Number) return ((Number) value).intValue(); 
     return Integer.parseInt(value.toString()); 
    } 

    @Override 
    public long getLong(int column) { 
     Object value = get(column); 
     if (value == null) return 0; 
     if (value instanceof Number) return ((Number) value).longValue(); 
     return Long.parseLong(value.toString()); 
    } 

    @Override 
    public float getFloat(int column) { 
     Object value = get(column); 
     if (value == null) return 0.0f; 
     if (value instanceof Number) return ((Number) value).floatValue(); 
     return Float.parseFloat(value.toString()); 
    } 

    @Override 
    public double getDouble(int column) { 
     Object value = get(column); 
     if (value == null) return 0.0d; 
     if (value instanceof Number) return ((Number) value).doubleValue(); 
     return Double.parseDouble(value.toString()); 
    } 

    @Override 
    public byte[] getBlob(int column) { 
     Object value = get(column); 
     return (byte[]) value; 
    } 

    @Override 
    public boolean isNull(int column) { 
     return get(column) == null; 
    } 
} 
Problemi correlati