2

少しトリッキーな問題を解決しようとしています。カスタム BaseAdapter を介してリモート サーバーから画像を取得するグリッドビューがあります。以下の関連コード。

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

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

このため、グリッドビューの定義は非常に簡単です...

//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;
    }
}

そして、私はこれらを自分で処理できるとかなり確信しています...私が問題を抱えているのは実際のアダプターです。カーソルアダプターの実装方法は知っていますが、「最初にダウンロードし、後でDBからフェッチする」を実行するのではなく、DBに対してのみチェックできます。ロジックは次のようになると思います。

  • プロバイダー経由で画像をクエリする
  • 戻りカーソルをアダプターに渡します
  • カーソルが空の場合 (つまり、DB にその画像のエントリがない場合)、ダウンロードして DB に配置します。

ただし、これがその方法であると100%確信しているわけではありません。どんな助けでも大歓迎です。

敬具、ダミール H.

4

1 に答える 1

0

画像のダウンロードとキャッシュにはUniversal Image Loaderライブラリを使用することを強くお勧めします

ライブラリは、任意の Android プロジェクトに簡単にインクルードできる JAR ファイルとしてダウンロードできます。

公式ページの特徴:

  • マルチスレッド画像の読み込み
  • ImageLoader の構成を幅広く調整する可能性 (スレッド プール サイズ、HTTP オプション、メモリとディスク キャッシュ、表示イメージ オプションなど)
  • メモリおよび/またはデバイスのファイル システム (または SD カード) での画像キャッシュの可能性
  • 読み込みプロセスを「聞く」可能性
  • 個別のオプションを使用してすべての表示画像呼び出しをカスタマイズする可能性
  • ウィジェットのサポート
于 2012-10-16T14:15:50.523 に答える