2

我想解決一個有點棘手的問題。我有一個通過自定義BaseAdapter從遠程服務器獲取圖像的GridView。下面的相關代碼。通過ContentProvider的Android位圖緩存

//The gridview 
pictureAdapter = new PictureAdapter(cont, document, thumbWidth); 

GridView gridview = (GridView) findViewById(R.id.pictures_gridview); 
gridview.setColumnWidth(thumbWidth); 
gridview.setAdapter(pictureAdapter); 

在GridView的定義是這個非常簡單的...

//The adapter 
public class PictureAdapter extends BaseAdapter { 
    private Context mContext; 
    private JSONArray mPics; 
    private List<String> mThumbs; 
    private List<String> mViews; 
    private List<Integer> mIds; 
    private int thumbWidth; 
    private SparseArray<Bitmap> imageData; 
    private boolean isFlinging; 


    public PictureAdapter(Context c, JSONArray pics, int thumbWidth) { 
     mContext = c; 
     mPics = pics; 
     this.thumbWidth = thumbWidth; 
     setPicThumbs(); 
     imageData = new SparseArray<Bitmap>(); 

    } 

    public void setFlinging(boolean isFlinging) { 
     this.isFlinging=isFlinging; 
    } 

    public boolean getFlinging() { 
     return this.isFlinging; 
    } 

    private void setPicThumbs() { 
     mThumbs = new Vector<String>(); 
     mViews = new Vector<String>(); 
     mIds = new Vector<Integer>(); 
     for(int i=0; i<mPics.length(); i++) { 
      JSONObject row; 
      try { 
       row = mPics.getJSONObject(i); 
       mThumbs.add(row.getString("thumb")); 
       mViews.add(row.getString("view")); 
       mIds.add(row.getInt("id")); 
      } catch (JSONException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

     } 
    } 

    public int getCount() { 
     return mThumbs.size(); 
    } 

    public Object getItem(int position) { 
     return null; 
    } 

    public long getItemId(int position) { 
     return 0; 
    } 

    public void setThumbWidth(int width) { 
     thumbWidth = width; 
    } 

    public List<String> getViews() { 
     return mViews; 
    } 


    public View getView(final int position, final View convertView, ViewGroup parent) { 
     final PycsellImageView imageView; 
     String imageUrlDirty = mThumbs.get(position); 
     String imageUrlClean = imageUrlDirty.split("\\?")[0]; 

     if (convertView == null) { // if it's not recycled, initialize some attributes 
      imageView = new PycsellImageView(mContext, mIds.get(position)); 
      imageView.setLayoutParams(new GridView.LayoutParams(thumbWidth+3, thumbWidth+3)); 
      imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); 
      imageView.setPadding(0, 0, 0, 0); 
      //imageView.setVisibility(View.INVISIBLE); 
     } else { 
      imageView = (PycsellImageView) convertView; 
      imageView.setPicId(mIds.get(position)); 
      if(imageView.getCurrentDrawable() != mThumbs.get(position) || isFlinging == true) { 
       imageView.setImageDrawable(null); 
       imageView.setCurrentDrawable(""); 
      } 

      // imageView.setVisibility(View.INVISIBLE); 
     } 


     if(imageData.get(position) != null) { 
      if (imageView.getDrawable() == null) { 
       imageView.startFade(); 
      } 
      imageView.setImageBitmap(imageData.get(position)); 
      imageView.setCurrentDrawable(mThumbs.get(position)); 
     } 

     else if (isFlinging == false) { 
      //Log.d("Picture Adapter", "Getting album thumb: "+imageUrlClean); 

      DownloadHelper downloadHelper = new DownloadHelper() { 

       public void OnFailure(String response) { 
        Log.e("Picture Adapter", response); 
       } 

       public void OnSucess(Bitmap bitmap) { 
        if (imageView.getDrawable() == null) { 
         imageView.setImageBitmap(bitmap); 
         imageView.setCurrentDrawable(mThumbs.get(position)); 
         imageView.startFade(); 
        } 
        imageData.put(position, bitmap); 
       } 
      }; 

      new ImageTask(mContext, downloadHelper, imageUrlClean).execute(); 
     } 

     return imageView; 
    } 

} 

大部分在適配器的代碼是不相關的,但我提出了它的全部。您會注意到請求圖像是通過DownloadHelper AsyncTask下載的,並放置在本地SparseArray中。如果圖像必須再次顯示,它將從該陣列中取出而不是被重新下載。

顯然,這是非常糟糕的,因爲可以有大量的圖像。這只是一個佔位符解決方案。我顯然希望實現更強大的圖像緩存,因爲這些圖像必須在下載後才能脫機使用。事情是......我不知道如何。

我已經實現了一個數據庫...

public class PycsellDatabase extends SQLiteOpenHelper { 
    private static final int DB_VERSION = 1; 
    private static final String DB_NAME = "pycsell_data"; 

    public static final String TABLE_ALBUMS_IMAGES = "albums_and_images"; 
    public static final String ID="_id"; 
    public static final String COL_TYPE="type"; 
    public static final String COL_PYCID="pycsell_id"; 
    public static final String COL_THUMB="thumb"; 
    public static final String COL_VIEW="view"; 
    public static final String COL_ALBUM="album"; 
    public static final String COL_TITLE="title"; 
    public static final String COL_PICNUM="picnum"; 
    private static final String CREATE_TABLE_ALBUMS_IMAGES = "create table" + TABLE_ALBUMS_IMAGES + "(" 
      + ID + "integer primary key autoincrement" 
      + COL_TYPE + "integer not null" 
      + COL_PYCID + "integer not null" 
      + COL_THUMB + "text not null" 
      + COL_VIEW + "text" 
      + COL_ALBUM +"integer" 
      + COL_TITLE + "text" 
      + COL_PICNUM + "integer);"; 

    private static final String DB_SCHEMA = CREATE_TABLE_ALBUMS_IMAGES; 

    public PycsellDatabase(Context context) { 
     super(context, DB_NAME, null, DB_VERSION); 
    } 

    @Override 
    public void onCreate(SQLiteDatabase db) { 
     db.execSQL(DB_SCHEMA); 
    } 
    @Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     db.execSQL("DROP TABLE IF EXISTS " + TABLE_ALBUMS_IMAGES); 
     onCreate(db); 
    } 
} 

...和(部分),ContentProvider的...

public class BitmapProvider extends ContentProvider { 
    private PycsellDatabase pDB; 
    private static final String AUTHORITY = "com.atlantbh.pycsell.db.BitmapProvider"; 
    public static final int ALBUMS=100; 
    public static final int IMAGES=110; 
    public static final int SINGLE_IMAGE=120; 
    private static final String ALBUMS_IMAGES_BASE_PATH = "albums_images"; 
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + ALBUMS_IMAGES_BASE_PATH); 
    public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE+"/album_image"; 
    public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE+"/album_image"; 

    private static final UriMatcher sURIMatcher = new UriMatcher(
      UriMatcher.NO_MATCH); 
    static { 
     sURIMatcher.addURI(AUTHORITY, ALBUMS_IMAGES_BASE_PATH, ALBUMS); 
     sURIMatcher.addURI(AUTHORITY, ALBUMS_IMAGES_BASE_PATH + "/#", IMAGES); 
     sURIMatcher.addURI(AUTHORITY, ALBUMS_IMAGES_BASE_PATH + "/#/#", SINGLE_IMAGE); 
    } 

    @Override 
    public boolean onCreate() { 
     pDB = new PycsellDatabase(getContext()); 
     return true; 
    } 

    @Override 
    public Cursor query(Uri uri, String[] projection, String selection, 
      String[] selectionArgs, String sortOrder) { 
     SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); 
     queryBuilder.setTables(PycsellDatabase.TABLE_ALBUMS_IMAGES); 
     int uriType = sURIMatcher.match(uri); 
     switch (uriType) { 
     //1 = albums, 2 = images 
     case ALBUMS: 
      queryBuilder.appendWhere(PycsellDatabase.COL_TYPE+"= 1"); 
      break; 

     case IMAGES: 
      queryBuilder.appendWhere(PycsellDatabase.COL_TYPE+"= 2"); 
      queryBuilder.appendWhere(PycsellDatabase.COL_ALBUM+"="+uri.getLastPathSegment()); 
      break; 

     case SINGLE_IMAGE: 
      List<String> segments = uri.getPathSegments(); 
      queryBuilder.appendWhere(PycsellDatabase.COL_TYPE+"= 2"); 
      queryBuilder.appendWhere(PycsellDatabase.COL_ALBUM+"="+segments.get(0)); 
      queryBuilder.appendWhere(PycsellDatabase.COL_PYCID+"="+segments.get(1)); 
      break; 
     } 

     Cursor cursor = queryBuilder.query(pDB.getReadableDatabase(), projection, selection, selectionArgs, null, null, sortOrder); 
     cursor.setNotificationUri(getContext().getContentResolver(), uri); 
     return cursor; 
    } 

    @Override 
    public int delete(Uri uri, String selection, String[] selectionArgs) { 
     // TODO Auto-generated method stub 
     return 0; 
    } 

    @Override 
    public String getType(Uri uri) { 
     // TODO Auto-generated method stub 
     return null; 
    } 

    @Override 
    public Uri insert(Uri uri, ContentValues values) { 
     // TODO Auto-generated method stub 
     return null; 
    } 

    @Override 
    public int update(Uri uri, ContentValues values, String selection, 
      String[] selectionArgs) { 
     // TODO Auto-generated method stub 
     return 0; 
    } 
} 

和我相當肯定我可以處理這些作爲自己我去...我有一個問題是實際的適配器。我知道如何實現一個遊標適配器,但是我只能檢查數據庫,而不是執行「先下載,稍後從數據庫中獲取」。我想象中的邏輯是這樣的:通過提供

  • 傳回光標到適配器
    • 查詢的圖像如果光標是空的(即在數據庫中對沒有進入圖像),下載並將其放入數據庫

    但是,我不是100%確定這是做到這一點的方法。任何幫助將不勝感激。

    此致敬禮, Damir H.

  • 回答

    0

    我強烈建議使用Universal Image Loader庫下載和緩存圖像

    您可以從官方頁面下載庫作爲,很容易納入任何Android項目中的JAR文件

    特點:

    • 多線程圖像加載
    • 可能性寬調諧ImageLoader的的配置(線程池的大小,HTTP選項,存儲器和盤高速緩衝存儲器,顯示器的圖像選項等)
    • 可能性在存儲器中的圖像緩存和/或設備上的文件sysytem(或SD卡)
    • 可能性「聽」加載過程
    • 可能性定製與分離選項的每個顯示圖像調用
    • 小工具支持
    +0

    我會看看並儘快回覆您。 –

    +0

    不幸的是,這並不能幫助我太多,因爲我明確需要維護一個文件的數據庫。我沒有下載甚至將圖像保存到文件系統的任何問題,而只是遊標適配器的具體實現。 –