我想做的是使用自定义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