Android -带有自定义CursorAdapter的Listview,运行asynctask会崩溃



我想做的是使用自定义CursorAdapter,以选择要显示的布局,并填充视图项目,如TextViews和ImageView。

现在不是所有的listview项都有图像

我的光标适配器代码是-

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

}

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

日志显示下一个-

    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

我哪里做错了?

感谢您的帮助

在我看来,你试图存储在内存中的Bitmap太大,无法存储在平板电脑/模拟器的内存中。,

bm = BitmapFactory.decodeFile(path);

查看代码是否适用于比来自当前路径的文件小得多的文件(也查看它是否适用于更小的列表)。这也可以是"The straw that broke The camel's back"的一个例子。如果您当前的应用程序已经非常内存密集,您可能需要检查当前代码并优化内存管理。

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

  • 一个获取图片缩略图的例子。

我希望这对你有帮助。


实现示例


只是通过一种可能的方式来实现上面的链接缩略图的例子,我可能会做什么来获得缩略图,我可以通过添加以下作为类变量(并在构造函数中实例化它)来存储传递给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;
}

原因在您的stacktrace: java.lang.OutOfMemoryError中。它看起来像是两种情况之一——要么您的图像太大,要么您正在泄漏内存(或两者都有)。

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

  • https://github.com/nostra13/Android-Universal-Image-Loader
  • https://github.com/square/picasso

相关内容

  • 没有找到相关文章

最新更新