0

要点: カスタム アダプターは、データベース内のファイルパスを介して間接的にファイル リソースを取得します。非効率性/メモリの問題。あなたの意見が求められました。

すべての検索への参照、関連リンク、およびトピックに関して役立つものは、投稿の下部にあります。

以下のコードは機能しますが、いくつかの要因が懸念されます。回避すべき改善や潜在的なエラーを提案するには、これについてより経験豊富な目が必要です。アプリはコンテンツ プロバイダーである必要はありません (アプリのローカル データ ソースのみ)。問題の ListView は非常に軽量で、約 5 ~最大 10 個のエントリしかありません。(動作するため、データベースのものは省略しました。)

概要:

  • データベースには、いくつかのテキストと画像ファイルのパスが含まれています。- わかった
  • 画像ファイルはデバイス (SD カード / 外部ストレージなど) に保存されます。- わかった

ファイルがデータベースにないため、これは通常の SimpleCursorAdapter とは異なります。画像ファイルをプルする必要があります。リストビューに入力する前にサムネイルにするオーバーヘッドが追加されました。

前述のとおり、軽量ですが、エントリが 1 つまたは 2 つしかない場合でも、VM はげっぷをしています。ビットマップに関連するすべてのメモリのジョグリングだと思います。

08-27 19:53:14.273: I/dalvikvm-heap(11900): Grow heap (frag case) to 4.075MB for 1228816-byte allocation
08-27 19:53:14.393: D/dalvikvm(11900): GC_CONCURRENT freed <1K, 5% free 4032K/4244K, paused 13ms+3ms, total 116ms

/* myTextAndImageCursorAdapter.java */

import android.widget.SimpleCursorAdapter;

//import android.support.v4.widget.SimpleCursorAdapter;
import android.content.Context;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import android.database.Cursor;
import java.io.File;

import android.widget.ImageView;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import static android.media.ThumbnailUtils.extractThumbnail;


public class TextAndImageCursorAdapter extends SimpleCursorAdapter { 

    private Context context;
    private int layout;

    public TextAndImageCursorAdapter (Context ctx, int layout, Cursor c, String[] from, int[] to) {
        super(context, layout, c, from, to);
        this.context = ctx;
        this.layout = layout;
    }

    @Override
    public View newView(Context ctx, Cursor cursor, ViewGroup parent) {

        Cursor c = getCursor();

        final LayoutInflater inflater = LayoutInflater.from(ctx);
        View vView = inflater.inflate(layout, parent, false);

        int iCol_Text = c.getColumnIndex(DBCOL_TEXT);
        int iCol_Image = c.getColumnIndex(DBCOL_IMAGE);

        String sText = c.getString(iCol_Text);
        String sFileAndPath_Image = c.getString (iCol_Image);  //// sImage path & file

        TextView tvText = (TextView) v.findViewById(R.id.gui_text);
        if (tvText != null) {
            tvText.setText(sSomeText);
        }

        ImageView ivImage (ImageView) v.findViewById(R.id.gui_image);
        if (ivImage != null) {
            ivImage.setImage (mySetImage (sFileAndPath_Image) );
        }

        return vView;
    }

    @Override
    public void bindView(View v, Context ctx, Cursor c) {
        //// ( like newView(), without an inflater, view, or return ) 
        int iCol_Text = c.getColumnIndex(DBCOL_TEXT);
        int iCol_Image = c.getColumnIndex(DBCOL_IMAGE);

        String sText = c.getString(iCol_Text);
        String sFileAndPath_Image = c.getString (iCol_Image);  //// path & file

        TextView tvText = (TextView) v.findViewById(R.id.gui_text);
        if (tvText != null) {
            tvText.setText(sSomeText);
        }

        ImageView ivImage (ImageView) v.findViewById(R.id.gui_image);
        if (ivImage != null) {
            ivImage.setImageBitmap ( mySetImage ( sFileAndPath_Image ) ) ;
        }
    }
    /////
    /////
    protected Bitmap mySetImage ( String path ) {
        int width = 60; int height = 40 ;

        File imgFile = new File ( path );  //// usually like: \sdcard0\wherever\filename1234.bmp
        Bitmap myBitmap = null;

        if( imgFile.exists() )
        {
                myBitmap = BitmapFactory.decodeFile ( imgFile.getAbsolutePath () );                  
        }
            else                    
                Log.d ("oops", "no image file ... using default.");
                myBitmap = getTheDefaultImage ();  //// not shown - this is arbitrary
        }

        imgFile.close();
        return ( extractThumbnail ( myBitmap, width, height ) ) ;
    }      
}

[編集 - リンクを追加] 検索基準: 「データベース内のパスを含むファイルからの画像を含む Android カスタム simplecursoradapter」

最も近いヒットですが、外部/ sdストアからではなく、resから画像を取得しようとします(未回答): SimpleCursorAdapter画像を表示する方法は?

また、ニア ヒット/ミス - 同様のアルゴ (未回答) 参照 4): ViewBinder を使用して SimpleCursorAdapter から表示されるカスタマイズ リスト

ほとんどですが、OP のコードは機能しません (有効な回答はありません): Load Image in a custom list by SimpleCursorAdapter

OPで作業していますが、ローカルではなくリモート取得にJSONを使用しています(おそらくこれは調整できるかもしれませんが、方法はわかりません)。 シンプルなアダプターでイメージビューに画像を表示するには?

完全ではありませんが、もう一度閉じます: 内部ストレージから画像をロードしている間、ListViewのスクロールが遅くなります

Image Loader の問題 (参照 2): Imageloader が実際のデバイスに画像をロードしない

関連リンク:

Android カスタム カーソル アダプタ

Android: カスタム SimpleCursorAdapter での newView と bindView の問題

同様に名前が付けられたヒットですが、私の特定の質問とは関係ありません-これらは通常、アプリ内のリソースを指します: 画像のパスを保存したデータベースから画像を表示

カスタム SimpleCursorAdapter エラー

カスタム SimpleCursorAdapter、データベース クエリ、および NullPointerException

拡張 SimpleCursorAdapter での nullPointerException

Android SimpleCursorAdapter - 条件付き画像の追加

外部参照:

0) カスタム カーソル アダプターの簡単な紹介 http://thinkandroid.wordpress.com/2010/01/11/custom-cursoradapters/

1) Romain Guy - 基本的なレイアウト ... 2 つのテキスト、1 つの画像 http://www.curious-creature.org/2009/02/22/android-layout-tricks-1/

2) AQuery (Android クエリ) http://code.google.com/p/android-query/wiki/ImageLoading

3) Android のサムネイル http://developer.android.com/reference/android/media/ThumbnailUtils.html

4) お客様。「オン/オフ」スター画像を含むリストビュー: http://enjoyandroid.wordpress.com/2012/03/12/customizing-simple-cursor-adapter/

4

1 に答える 1

5

あなたができる2つのこと:

1) ViewHolder パターンを使用し、LayoutInfalter をキャッシュします。最も重要なのは、データを 2 回バインドしないことです。

/* ... imports */

import static android.media.ThumbnailUtils.extractThumbnail;

public class TextAndImageCursorAdapter extends SimpleCursorAdapter { 

    private LayoutInflater mLayoutInflater;
    private Context context;
    private int layout;


    private class ViewHolder {
        TextView textView;
        ImageView imageView;

        ViewHolder(View v) {
            textView = (TextView) v.findViewById(R.id.gui_text);
            imageView = (ImageView) v.findViewById(R.id.gui_image);
        }
    }

    public TextAndImageCursorAdapter (Context ctx, int layout, Cursor c, String[] from, int[] to) {
        super(ctx, layout, c, from, to);
        this.context = ctx;
        this.layout = layout;
        mLayoutInflater = LayoutInflater.from(ctx);
    }


    @Override
    public View newView(Context ctx, Cursor cursor, ViewGroup parent) {
        View vView = mLayoutInflater.inflate(layout, parent, false);
        vView.setTag( new ViewHolder(vView) );
        // no need to bind data here. you do in later
        return vView;// **EDITED:**need to return the view
    }

    @Override
    public void bindView(View v, Context ctx, Cursor c) {
        // you might want to cache these too
        int iCol_Text = c.getColumnIndex(DBCOL_TEXT);
        int iCol_Image = c.getColumnIndex(DBCOL_IMAGE);

        String sText = c.getString(iCol_Text);
        String sFileAndPath_Image = c.getString (iCol_Image);  //// path & file

        ViewHolder vh = (ViewHolder) v.getTag();

        vh.textView.setText(sSomeText);
        vh.imageView.setImageBitmap ( mySetImage ( sFileAndPath_Image ) );
    }
}

2) これは非常に重要です。バインドごとにサムネイルを作成しないでください。結果をキャッシュする必要があります。

private void setThumbnail(String path, Bitmap b) {
    // save thumbnail to some kind of cache
    // see comment below
}

private Bitmap getThumbnail(String path) {
    Bitmap thumbnail = null;
    // try to fetch the thumbnail from some kind of cache
    // see comment below
    return thumbnail;
}

protected Bitmap mySetImage ( String path ) {
    int width = 60; int height = 40 ;

    Bitmap thumbnail = getThumbnail(path); // try to fetch thumbnail
    if (thumbnail != null) return thumbnail;

    File imgFile = new File ( path );  //// usually like: /sdcard/wherever/filename1234.bmp
    Bitmap myBitmap = null;

    if( imgFile.exists() ) {
            myBitmap = BitmapFactory.decodeFile ( imgFile.getAbsolutePath () );                  
    } else {
            Log.d ("oops", "no image file ... using default.");
            myBitmap = getTheDefaultImage ();  //// not shown - this is arbitrary
    }

    imgFile.close();
    thumbnail = extractThumbnail ( myBitmap, width, height );
    myBitmap.recycle();
    setThumbnail(path, thumbnail); // save thumbnail for later reuse
    return thumbnail;
}     

ユースケースに応じて、ある種の LruCache で埋めたいと思いますgetThumbnail():setThumbnail()

編集 :

  @Override
public View newView(Context ctx, Cursor cursor, ViewGroup parent) {
    View vView = mLayoutInflater.inflate(layout, parent, false);
    vView.setTag( new ViewHolder(vView) );
    // no need to bind data here. you do in later
    return vView;// **EDITED:**need to return the view
}
于 2013-08-30T03:19:31.073 に答える