【问题标题】:Android - Listview with custom CursorAdapter, which running asynctask crashesAndroid - 带有自定义 CursorAdapter 的 Listview,运行 asynctask 会崩溃
【发布时间】:2014-03-25 02:19:56
【问题描述】:

我正在尝试使用自定义 CursorAdapter,以便选择要显示的布局以及填充视图项,例如 TextViews 和 ImageView。

现在并不是所有的列表视图项中都会有图片。

我的 CursorAdapter 代码是 -

    private static class ViewHolder {
    TextView mesg;
    TextView mesg2;
    TextView send;
    ImageView myImage;
}

public class ChatCursorAdapter extends CursorAdapter implements OnClickListener {

    public ChatCursorAdapter(Context context, Cursor c) {
        super(context, c, 0);
    }

    @Override
    public int getCount() {
        return getCursor() == null ? 0 : super.getCount();
    }

    @Override
    public int getViewTypeCount() {
        return 2;
    }

    @Override
    public int getItemViewType(int _position) {

        Cursor cursor = (Cursor) getItem(_position);
        return getItemViewType(cursor);
    }

      private int getItemViewType(Cursor cursor) {

            String sender = cursor.getString(2);

                    String saveUser =   user;

                    if (saveUser.equalsIgnoreCase(sender)){

                        return 0;
                    }else{
                        return 1;
                    }

      }



    @Override
    public void bindView(View view, Context context, Cursor cursor) {

    ViewHolder holder = (ViewHolder) view.getTag();

        String msg = cursor.getString(3);
        String msg2 = cursor.getString(4);
        String sender = cursor.getString(2);

        holder.mesg.setText(getSmiledText(Main.this,msg));
        holder.mesg2.setText(getSmiledText(Main.this,msg2));
        holder.send.setText(sender);


        picPath = cursor.getString(8);


        if(picPath == null || picPath.isEmpty()){

                holder.myImage.setVisibility(View.GONE);

             }else{

              File file = new File(picPath);

              if(file.exists()){

                 new AsyncImageSetter(holder.myImage, picPath).execute();
                 holder.myImage.setOnClickListener(this);

            }



             }


    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        ViewHolder holder = new ViewHolder();
        View itemLayout = null;
        switch(getItemViewType(cursor)){
        case 0:
            itemLayout = getLayoutInflater().inflate(R.layout.msg_item1,parent, false);
            break;
        case 1:
            itemLayout =  getLayoutInflater().inflate(R.layout.msg_item13, parent,false);
            break;

        }

        itemLayout.setTag(holder);
        holder.mesg = (TextView) itemLayout.findViewById(R.id.text_start);
        holder.mesg2 = (TextView) itemLayout.findViewById(R.id.text_end);
        holder.send = (TextView) itemLayout.findViewById(R.id.text_from);
        holder.myImage = (ImageView) itemLayout.findViewById(R.id.imageView_msgpic);
        return itemLayout;

    }



}

正如您所见,当需要将图像加载到 ImageView 时,我使用 asynctask 是为了让列表视图滚动的流程更加顺畅。

asynctask 代码是这样的 -

     public class AsyncImageSetter extends AsyncTask<Void, Void, Void> {

     private ImageView img;
     private String path;
     private Bitmap bm;

         public AsyncImageSetter(ImageView img, String path) {
         this.img = img;
         this.path = path;


     }

     @Override
     protected Void doInBackground(Void... params) {

        bm = BitmapFactory.decodeFile(path);
        bm = setImageToImageView(path);

         return null;
     }

     @Override
     protected void onPostExecute(Void result) {

         img.setTag(path);
         img.setImageBitmap(bm);
         //img.setVisibility(View.VISIBLE);

         super.onPostExecute(result);
     }

}

问题是它确实让滚动更加流畅,但它似乎让应用程序崩溃了很多次。

logcat 说下一个 -

    03-24 17:07:34.125: E/AndroidRuntime(15422): FATAL EXCEPTION: AsyncTask #2
03-24 17:07:34.125: E/AndroidRuntime(15422): java.lang.RuntimeException: An error occured while executing doInBackground()
03-24 17:07:34.125: E/AndroidRuntime(15422):    at android.os.AsyncTask$3.done(AsyncTask.java:299)
03-24 17:07:34.125: E/AndroidRuntime(15422):    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
03-24 17:07:34.125: E/AndroidRuntime(15422):    at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
03-24 17:07:34.125: E/AndroidRuntime(15422):    at java.util.concurrent.FutureTask.run(FutureTask.java:239)
03-24 17:07:34.125: E/AndroidRuntime(15422):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
03-24 17:07:34.125: E/AndroidRuntime(15422):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
03-24 17:07:34.125: E/AndroidRuntime(15422):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
03-24 17:07:34.125: E/AndroidRuntime(15422):    at java.lang.Thread.run(Thread.java:841)
03-24 17:07:34.125: E/AndroidRuntime(15422): Caused by: java.lang.OutOfMemoryError
03-24 17:07:34.125: E/AndroidRuntime(15422):    at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
03-24 17:07:34.125: E/AndroidRuntime(15422):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:623)
03-24 17:07:34.125: E/AndroidRuntime(15422):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:378)
03-24 17:07:34.125: E/AndroidRuntime(15422):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:417)
03-24 17:07:34.125: E/AndroidRuntime(15422):    at at.vcity.androidim.MainChat$AsyncImageSetter.doInBackground(MainChat.java:3356)
03-24 17:07:34.125: E/AndroidRuntime(15422):    at at.vcity.androidim.MainChat$AsyncImageSetter.doInBackground(MainChat.java:1)
03-24 17:07:34.125: E/AndroidRuntime(15422):    at android.os.AsyncTask$2.call(AsyncTask.java:287)
03-24 17:07:34.125: E/AndroidRuntime(15422):    at java.util.concurrent.FutureTask.run(FutureTask.java:234)
03-24 17:07:34.125: E/AndroidRuntime(15422):    ... 4 more

那么我在这里做错了什么?

感谢您的帮助

【问题讨论】:

  • +1 表示格式正确且包含所有必需信息的问题。

标签: java android listview android-asynctask


【解决方案1】:

在我看来,您尝试存储在内存中的 Bitmap 太大而无法存储在平板电脑/模拟器的内存中。这里;

bm = BitmapFactory.decodeFile(path);

查看代码是否适用于比来自当前路径的文件小得多的文件(也看看它是否适用于更小的列表)。这也可能是“压死骆驼的稻草”的一个实例。如果您当前的应用程序已经非常占用内存,您可能必须检查您当前的代码并优化内存管理。

因为您正在为ListView 中的每个项目创建一个AsyncTask,所以您试图一次将这么多图像保存在内存中。所以你可能需要找到另一种方法来做到这一点。您可能需要尝试将图像的缩略图加载到您的 ImageViews 中。

我希望这会有所帮助。


示例实现


只是通过一种可能的方式来实现上述链接的缩略图示例,我可能会做的是获取缩略图,我可以通过添加以下作为类变量(并实例化它)来存储传递给您的ChatCursorAdapter 的上下文在构造函数中);

Context ourContext;

public ChatCursorAdapter(Context context, Cursor c) {       
    super(context, c, 0);
    ourContext = context;
}

@Override
public void bindView(View view, Context context, Cursor cursor) {
    ...
    new AsyncImageSetter(holder.myImage, picPath, ourContext.getContentResolver()).execute();
    ...
}

然后(如上所述)我可能会使用Context 来获取ContentResolver 实例并通过它的构造函数将该实例传递给您的AsyncTask。然后我们可以在示例代码中添加方法来获取自定义 AsyncTask 中的缩略图,它可能看起来像这样;

ContentResolver cr;

public AsyncImageSetter(ImageView img, String path, ContentResolver cr) {
     this.img = img;
     this.path = path;
     this.cr = cr;
     }
...

@Override
 protected Void doInBackground(Void... params) {
    try{
         bm = getThumbnail(cr, path);
    }catch(Exception e){}

     return null;
 }

private Bitmap getThumbnail(ContentResolver cr, String path) throws Exception {

    Cursor ca = cr.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[] { MediaStore.MediaColumns._ID }, MediaStore.MediaColumns.DATA + "=?", new String[] {path}, null);
    if (ca != null && ca.moveToFirst()) {
        int id = ca.getInt(ca.getColumnIndex(MediaStore.MediaColumns._ID));
        ca.close();
        return MediaStore.Images.Thumbnails.getThumbnail(cr, id, MediaStore.Images.Thumbnails.MICRO_KIND, null );
    }

    ca.close();
    return null;

}

【讨论】:

  • 我是在移动设备(galaxy s3)上运行的,所以如果不是在真机上运行,​​好像没用
  • 准确加载图片缩略图是什么意思?
  • Android 存储每张图片的“缩略图”。这是每个存储图像的分辨率非常低的版本。分辨率对于您可能看到的几乎任何东西都足够好(但足够小,不会耗尽您的所有记忆)。我添加了一个带有示例的链接。
  • @4this - 顺便问一下,您的ListView 中有多少项目?
  • 它是一个列表视图,显示来自数据库的输入 - 所以列表视图项目的数量是无限的,就好像它显示了当前数据库行的数量。顺便说一句,我正试图弄清楚如何使用缩略图代码 - 我肯定会陷入理解那里的一两件事
【解决方案2】:

原因在于您的堆栈跟踪:java.lang.OutOfMemoryError。它看起来像是两种情况之一 - 您的图像太大或您正在泄漏内存(或两者兼而有之)。

我的建议是使用几个库之一来进行背景图像加载。以下是一些建议:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多