我的Android应用程序遇到了一个非常奇怪的问题。简单地说,当我将图像内容放入ListView item
时就会出现问题。
例如;让我们说我有一个Fragment
,其布局如下;
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@android:id/list" />
</LinearLayout>
我的&#39;列出项目&#39;;
的以下布局<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp">
<ImageView
android:layout_width="@dimen/list_image_width"
android:layout_height="@dimen/list_image_height"
android:id="@+id/listimage"
android:scaleType="centerCrop" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/listtitle"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/listimage"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:textSize="18sp"
android:textColor="#000" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/listsubtitle"
android:layout_below="@+id/listtitle"
android:layout_alignRight="@+id/listtitle"
android:layout_alignEnd="@+id/listtitle"
android:textSize="17sp"
android:textColor="#333"
android:layout_alignBottom="@+id/listimage"
android:layout_alignLeft="@+id/listtitle"
android:layout_alignStart="@+id/listtitle" />
</RelativeLayout>
一切顺利。该列表就像我想要的那样呈现出来。但是,每当我开始将图像(内容)放入ImageView
时,事情就会变得混乱。无论我做什么,列表加载速度非常慢,滚动几乎是不可能的。
我尝试过多种方式加载图片并将其放入ImageView
。
我尝试过的事情:
ViewHolder
中使用Adapter
,在AsyncTask
文件夹的Drawables
中加载图片并将其放入ImageView
上的.onPostExecute()
{1}} ViewHolder
中使用Adapter
,在不使用Drawables
的情况下从AsyncTask
加载图片。Drawables
上onSetValues()
的图片。Assets
文件夹中的图像所有这些都没有做任何不同的事情,但最后的选择。最后一个选项使列表更容易接受,但仍然加载速度非常慢。 (我按下按钮,fragment
被启动,我尝试使用TransactionManager
打开它,这似乎只是在显示列表之前冻结应用程序约2-5秒。)滚动更多也可以接受,但仍然没有那么好,应该。
如果我将我设置图像的部分注释到ImageView
并再次运行,那么该视图绝对没有任何问题。
这一切归结为,设置Drawables文件夹中的内容是不行的。 (虽然我已经为每个我没有问题的应用程序完成了这项工作)。从Assets文件夹设置图像内容可以极大地提高性能,但仍然没有达到我期望的性能。即使使用EasyAdapter,如下所示也是一个可怕的用户体验:
@LayoutId(R.layout.list_default)
public class ListAdapter extends ItemViewHolder<Item> {
@ViewId(R.id.listimage)
ImageView image;
@ViewId(R.id.listtitle)
TextView title;
@ViewId(R.id.listsubtitle)
TextView subtitle;
public BeetListAdapter(View view) {
super(view);
}
@Override
public void onSetValues(BeetItem item, PositionInfo positionInfo) {
title.setText(item.getTitle());
subtitle.setText(item.getLatinname());
image.setImageBitmap(getBitmapFromAsset(item.getFirstImageName()));
getView().setTag(R.id.itemid, item.getId());
}
private Bitmap getBitmapFromAsset(String strName)
{
AssetManager assetManager = getContext().getAssets();
InputStream istr = null;
try {
istr = assetManager.open("images/" + strName + ".jpg");
} catch (IOException e) {
e.printStackTrace();
}
Bitmap bitmap = BitmapFactory.decodeStream(istr);
return bitmap;
}
}
你们有没有想到为什么会这样?我没有找到任何理由,也没有解决原因。 提前谢谢!
tl; dr :当我将图片放入ListView
时,我的ImageView
非常慢。它们似乎和来自哪里(ram,磁盘,互联网)并不重要。每当我imageView.setImageBitmap()
或imageView.setDrawable()
时,性能下降和滚动几乎是不可能的。
答案 0 :(得分:3)
如果可能,请缓存图片,将其缩小。 Aquery library可以帮助您完成所有这些任务。
答案 1 :(得分:2)
公平地说,以上都没有解决我的问题,我决定实施library that helps with these kinds of problems.
作为参考,这是我初始化 Android Universal Image Loader 的配置;
DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.bitmapConfig(Bitmap.Config.RGB_565)
.imageScaleType(ImageScaleType.EXACTLY)
.build();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
.defaultDisplayImageOptions(defaultOptions)
.threadPoolSize(5)
.threadPriority(Thread.MAX_PRIORITY)
.tasksProcessingOrder(QueueProcessingType.FIFO)
.memoryCache(new LruMemoryCache(2 * 1024 * 1024))
.diskCacheExtraOptions(480, 320, null)
.build();
ImageLoader.getInstance().init(config);
如果没有实现AsyncTask
,我现在在应用程序中有一个非常好的用户体验。
答案 2 :(得分:1)
因为您正在从Main(UI)线程中的资源加载图像,这就是为什么它看起来不稳定。所以像这样在asynktask中加载图像。
public class ListAdapter extends ItemViewHolder<ClipData.Item> {
@ViewId(R.id.listimage)
ImageView image;
@ViewId(R.id.listtitle)
TextView title;
@ViewId(R.id.listsubtitle)
TextView subtitle;
public BeetListAdapter(View view) {
super(view);
}
@Override
public void onSetValues(BeetItem item, PositionInfo positionInfo) {
title.setText(item.getTitle());
subtitle.setText(item.getLatinname());
getBitmapFromAsset(item.getFirstImageName(), image);
getView().setTag(R.id.itemid, item.getId());
}
private void getBitmapFromAsset(final String strName,final ImageView imageView)
{
new AsyncTask<Void,Void,Bitmap>(){
@Override
protected Bitmap doInBackground(Void... voids) {
try{
AssetManager assetManager = getContext().getAssets();
InputStream istr = null;
try {
istr = assetManager.open("images/" + strName + ".jpg");
} catch (IOException e) {
e.printStackTrace();
}
Bitmap bitmap = BitmapFactory.decodeStream(istr);
return bitmap;
}catch (Throwable e){
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
if(result!=null){
image.setImageBitmap(result);
}
}
}.execute();
}
}
答案 3 :(得分:0)
不要硬编码LruMemoryCache
。因为在某些设备上你会收到:
Fatal signal 11 (SIGSEGV) at 0x00000010 (code=1)
以下是加载图像和滚动列表视图的选项:
DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.bitmapConfig(Bitmap.Config.RGB_565)
.imageScaleType(ImageScaleType.EXACTLY)
.build();
int memClass;
memClass = ( (ActivityManager)this.getSystemService( Context.ACTIVITY_SERVICE ) )
.getMemoryClass();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
.defaultDisplayImageOptions(defaultOptions)
.threadPoolSize(1)//from 1-5
.denyCacheImageMultipleSizesInMemory()
.threadPriority(Thread.MAX_PRIORITY)
.tasksProcessingOrder(QueueProcessingType.LIFO)
// .tasksProcessingOrder(QueueProcessingType.FIFO) /or this
.memoryCache(new LruMemoryCache(memClass * 1024 * 1024/8))
.diskCacheExtraOptions(480, 320, null)
.build();
ImageLoader.getInstance() .init(config);