Android 在网格视图中显示图像的最佳方法是平滑滚动
首先,我已经做了一些事情来在gridview中显示图像,以便在滚动时平滑 1。在后台线程上从internet加载图像Android 在网格视图中显示图像的最佳方法是平滑滚动,android,performance,bitmap,Android,Performance,Bitmap,首先,我已经做了一些事情来在gridview中显示图像,以便在滚动时平滑 1。在后台线程上从internet加载图像 AsyncTask acyncTask ; HandlerThread handlerThread ; URL imageUrl = new URL(link);<br> HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection(); co
AsyncTask acyncTask ;
HandlerThread handlerThread ;
URL imageUrl = new URL(link);<br>
HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(true);
InputStream is=conn.getInputStream();
final Bitmap bitmap = BitmapFactory.decodeStream(is);
Handler handler = new Handler();
handler.post(new Runnable(){
public void run(){
imageView.setimageBitmap(bitmap);
}
});
3。进行缓存以保存解码的位图
LruCache lruCache = new LruCache<String , Bitmap>();
现在我面临一个大问题,当我滚动时它仍然有点滞后
我在google上看到了一些可以使滚动更好的东西,不知道是否真的有什么可以改进,或者问题是从哪里出来的,我检查了每个getView()只花了我大约2~6ms,它会调用我的代码来异步加载图像表单工作线程,所以我真的不知道为什么一些应用程序可以非常平滑地加载?我的情况是滚动时屏幕看起来不太平滑。是否可以应用一些建议
编辑:当我滚动时,在缓存中找到的位图显示在屏幕上,如果我快速滚动,它看起来像没有足够的滚动来显示图像,这将使我的滚动不那么平滑,即使我在缓存中缓存了位图
以下是适配器代码:
if (convertView == null) {
convertView = layoutInflater.inflate(
R.layout.row_display_image_grid, null);
viewHolder = new DisplayImageGridViewHolder();
viewHolder.background = (RelativeLayout) convertView
.findViewById(R.id.background);
viewHolder.image = (ImageView) convertView.findViewById(R.id.image);
viewHolder.text = (TextView) convertView.findViewById(R.id.text);
viewHolder.position = position;
viewHolder.text.setEllipsize(TruncateAt.END);
viewHolder.text.setTypeface(typeFace);
viewHolder.image.setOnClickListener(this);
viewHolder.image.setOnLongClickListener(this);
convertView.setTag(viewHolder);
} else {
viewHolder = (DisplayImageGridViewHolder) convertView.getTag();
}
viewHolder.position = position;
imageLoader.loadImage(imageLinkList.get(position), viewHolder.image);
return convertView;
下面是我使用的LazyLoader的一个示例。注意:我使用的是位图的软引用,现在使用
LruCache
可以更好地实现这一点
这将从web/SD卡/内存异步加载图像,并从占位符图像创建淡入效果
public class ImageLoader {
private static MemoryCacheNew memoryCache=new MemoryCacheNew();
private static FileCache fileCache;
private static BitmapFactory.Options bitmapOptions;
private static int mInSampleSize;
public ImageLoader(Context context, int inSampleSize){
fileCache=new FileCache(context);
context = null;
bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inSampleSize = mInSampleSize = inSampleSize;
bitmapOptions.inPreferredConfig = Config.RGB_565;
bitmapOptions.inInputShareable = true;
bitmapOptions.inDither = false;
}
final static int PLACEHOLDER_IMAGE = R.drawable.store_placeholder;
public void DisplayImage(String url, ImageView imageView, boolean checkTags){
try{
new AsyncPhotoTask(imageView, url, checkTags).execute();
}catch(Exception e){
e.printStackTrace();
}
}
public void DisplayImage(String url, ImageView imageView)
{
DisplayImage(url, imageView, true);
}
private static Bitmap getBitmap(String url)
{
File f=fileCache.getFile(url);
if(f!= null){
//from SD cache
Bitmap b = decodeFile(f);
if(b!=null)
return b;
}
//from web
try {
Bitmap bitmap=null;
URL imageUrl;
imageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
InputStream is=conn.getInputStream();
OutputStream os = new FileOutputStream(f);
Utils.CopyStream(is, os);
is.close();
os.close();
bitmap = decodeFile(f);
return bitmap;
} catch (Exception ex){
ex.printStackTrace();
return null;
}
}
//decodes image and scales it to reduce memory consumption
private static Bitmap decodeFile(File f){
try {
return BitmapFactory.decodeStream(new FileInputStream(f), null, bitmapOptions);
} catch (FileNotFoundException e) {
} catch (OutOfMemoryError err){
System.gc();
}
return null;
}
private static class AsyncPhotoLoad extends AsyncTask<Void, Void, TransitionDrawable>{
private Bitmap bmp;
private ImageView imageView;
private String url;
private boolean checkTags;
public AsyncPhotoLoad(ImageView imageView, String url, boolean checkTags
){
this.imageView = imageView;
this.url = url;
this.checkTags = checkTags;
}
@Override
protected TransitionDrawable doInBackground(Void... arg0) {
//check that this is the correct imageview
TransitionDrawable transition = null;
try{
if(checkTags){
String tag = (String)imageView.getTag();
if(!tag.equals(url))
return null;
}
bmp = getBitmap(url);
if(bmp != null){
memoryCache.put(url, bmp, mInSampleSize);
Drawable oldDrawable = imageView.getDrawable();
if(!(oldDrawable instanceof TransitionDrawable)){
Drawable layers[] = new Drawable[2];
layers[0] = imageView.getDrawable();
layers[1] = new BitmapDrawable(bmp);
transition = new TransitionDrawable(layers);
}
}
}catch(Exception e){
e.printStackTrace();
}
return transition;
}
@Override
protected void onPostExecute(TransitionDrawable result) {
if(result != null){
try{
if(checkTags){
String tag = (String)imageView.getTag();
if(!tag.equals(url)){
return;
}
}
imageView.setImageDrawable(result);
result.startTransition(300);
} catch(Exception e){
e.printStackTrace();
}
} else {
if(checkTags){
try{
String tag = (String)imageView.getTag();
if(!tag.equals(url))
return;
}catch(Exception e){
e.printStackTrace();
}
}
}
}
}
private static class AsyncPhotoTask extends AsyncTask<Void, Void, Bitmap>{
private ImageView imageView;
private String url;
private boolean checkTags;
public AsyncPhotoTask(ImageView imageView, String url, boolean checkTags){
this.imageView = imageView;
this.url = url;
this.checkTags = checkTags;
}
@Override
protected Bitmap doInBackground(Void... params) {
try{
if(checkTags)
imageView.setTag(url);
}catch(Exception e){
e.printStackTrace();
}
return memoryCache.get(url, mInSampleSize);
}
@Override
protected void onPostExecute(Bitmap result) {
try{
if(result!=null && !result.isRecycled()){
imageView.setImageBitmap(result);
}
else
{
imageView.setImageResource(PLACEHOLDER_IMAGE);
new AsyncPhotoLoad(imageView, url, checkTags).execute();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
public static void clearCache() {
memoryCache.clear();
fileCache.clear();
}
public static void clearMemory(){
memoryCache.clear();
}
public static class MemoryCacheNew {
private HashMap<String, CachedBitmap> cache=new HashMap<String, CachedBitmap>();
public Bitmap get(String id, int sampleSize){
if(!cache.containsKey(id))
return null;
if(cache.get(id) == null)
return null;
if(cache.get(id).sampleSize != sampleSize)
return null;
SoftReference<Bitmap> ref = cache.get(id).softBitmap;
return ref.get();
}
public void put(String id, Bitmap bitmap, int sampleSize){
cache.put(id, new CachedBitmap(bitmap, sampleSize));
}
public void clear() {
cache.clear();
}
private static class CachedBitmap {
public SoftReference<Bitmap> softBitmap;
public int sampleSize;
public CachedBitmap(Bitmap bitmap, int sampleSize){
this.softBitmap = new SoftReference<Bitmap>(bitmap);
this.sampleSize = sampleSize;
}
}
}
}
public class FileCache {
private File cacheDir;
public FileCache(Context context){
//Find the dir to save cached images
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
cacheDir=new File(context.getExternalCacheDir(),Consts.STORE_CACHE);
else
cacheDir=context.getCacheDir();
if(!cacheDir.exists())
cacheDir.mkdirs();
}
public File getFile(String url){
//I identify images by hashcode. Not a perfect solution, good for the demo.
String filename=String.valueOf(url.hashCode());
File f = new File(cacheDir, filename);
return f;
}
public void clear(){
File[] files=cacheDir.listFiles();
for(File f:files)
f.delete();
}
}
尝试确保每个位图的大小都达到最佳。。。它们应该和容器的大小差不多。在通过RemoteView发送它们之前,请尽可能缩小它们的大小。您可以使用OnAppWidgetOptions Changed计算小部件大小
此外,请尝试使用setImageViewUri(与内容提供商一起)而不是SetImageViewBitMap,以获得最佳性能。能否发布适配器代码,特别是getView()方法。这很可能是滚动延迟的原因。添加了,我只是调用一个方法在工作线程上启动加载任务,我在这个getview方法之前和之后进行了检查,它只花了我几秒钟的时间,你认为当滚动GridView时setimagebitmap有问题吗?你的代码仍然有点不清楚。你能发布你的整个ImageLoader类吗。我正在使用非常相似的代码,可能基于同一个示例,并使其无延迟工作。哦,我明白了,您正在使用类似的代码,您如何在gridview上显示图像??如果你快速滚动,是不是会有点滞后??我只是将showing bitmap方法从runonuithread改为handler postdelayed,否则也一样。我只是使用AsyncTasks加载图像。从doInBackground中的web/本地存储器/内存加载图像。然后在onPostExecute中设置映像。是的,您也在使用类似的代码,但它不能帮助我,抱歉
public class ImageLoader {
private static MemoryCacheNew memoryCache=new MemoryCacheNew();
private static FileCache fileCache;
private static BitmapFactory.Options bitmapOptions;
private static int mInSampleSize;
public ImageLoader(Context context, int inSampleSize){
fileCache=new FileCache(context);
context = null;
bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inSampleSize = mInSampleSize = inSampleSize;
bitmapOptions.inPreferredConfig = Config.RGB_565;
bitmapOptions.inInputShareable = true;
bitmapOptions.inDither = false;
}
final static int PLACEHOLDER_IMAGE = R.drawable.store_placeholder;
public void DisplayImage(String url, ImageView imageView, boolean checkTags){
try{
new AsyncPhotoTask(imageView, url, checkTags).execute();
}catch(Exception e){
e.printStackTrace();
}
}
public void DisplayImage(String url, ImageView imageView)
{
DisplayImage(url, imageView, true);
}
private static Bitmap getBitmap(String url)
{
File f=fileCache.getFile(url);
if(f!= null){
//from SD cache
Bitmap b = decodeFile(f);
if(b!=null)
return b;
}
//from web
try {
Bitmap bitmap=null;
URL imageUrl;
imageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
InputStream is=conn.getInputStream();
OutputStream os = new FileOutputStream(f);
Utils.CopyStream(is, os);
is.close();
os.close();
bitmap = decodeFile(f);
return bitmap;
} catch (Exception ex){
ex.printStackTrace();
return null;
}
}
//decodes image and scales it to reduce memory consumption
private static Bitmap decodeFile(File f){
try {
return BitmapFactory.decodeStream(new FileInputStream(f), null, bitmapOptions);
} catch (FileNotFoundException e) {
} catch (OutOfMemoryError err){
System.gc();
}
return null;
}
private static class AsyncPhotoLoad extends AsyncTask<Void, Void, TransitionDrawable>{
private Bitmap bmp;
private ImageView imageView;
private String url;
private boolean checkTags;
public AsyncPhotoLoad(ImageView imageView, String url, boolean checkTags
){
this.imageView = imageView;
this.url = url;
this.checkTags = checkTags;
}
@Override
protected TransitionDrawable doInBackground(Void... arg0) {
//check that this is the correct imageview
TransitionDrawable transition = null;
try{
if(checkTags){
String tag = (String)imageView.getTag();
if(!tag.equals(url))
return null;
}
bmp = getBitmap(url);
if(bmp != null){
memoryCache.put(url, bmp, mInSampleSize);
Drawable oldDrawable = imageView.getDrawable();
if(!(oldDrawable instanceof TransitionDrawable)){
Drawable layers[] = new Drawable[2];
layers[0] = imageView.getDrawable();
layers[1] = new BitmapDrawable(bmp);
transition = new TransitionDrawable(layers);
}
}
}catch(Exception e){
e.printStackTrace();
}
return transition;
}
@Override
protected void onPostExecute(TransitionDrawable result) {
if(result != null){
try{
if(checkTags){
String tag = (String)imageView.getTag();
if(!tag.equals(url)){
return;
}
}
imageView.setImageDrawable(result);
result.startTransition(300);
} catch(Exception e){
e.printStackTrace();
}
} else {
if(checkTags){
try{
String tag = (String)imageView.getTag();
if(!tag.equals(url))
return;
}catch(Exception e){
e.printStackTrace();
}
}
}
}
}
private static class AsyncPhotoTask extends AsyncTask<Void, Void, Bitmap>{
private ImageView imageView;
private String url;
private boolean checkTags;
public AsyncPhotoTask(ImageView imageView, String url, boolean checkTags){
this.imageView = imageView;
this.url = url;
this.checkTags = checkTags;
}
@Override
protected Bitmap doInBackground(Void... params) {
try{
if(checkTags)
imageView.setTag(url);
}catch(Exception e){
e.printStackTrace();
}
return memoryCache.get(url, mInSampleSize);
}
@Override
protected void onPostExecute(Bitmap result) {
try{
if(result!=null && !result.isRecycled()){
imageView.setImageBitmap(result);
}
else
{
imageView.setImageResource(PLACEHOLDER_IMAGE);
new AsyncPhotoLoad(imageView, url, checkTags).execute();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
public static void clearCache() {
memoryCache.clear();
fileCache.clear();
}
public static void clearMemory(){
memoryCache.clear();
}
public static class MemoryCacheNew {
private HashMap<String, CachedBitmap> cache=new HashMap<String, CachedBitmap>();
public Bitmap get(String id, int sampleSize){
if(!cache.containsKey(id))
return null;
if(cache.get(id) == null)
return null;
if(cache.get(id).sampleSize != sampleSize)
return null;
SoftReference<Bitmap> ref = cache.get(id).softBitmap;
return ref.get();
}
public void put(String id, Bitmap bitmap, int sampleSize){
cache.put(id, new CachedBitmap(bitmap, sampleSize));
}
public void clear() {
cache.clear();
}
private static class CachedBitmap {
public SoftReference<Bitmap> softBitmap;
public int sampleSize;
public CachedBitmap(Bitmap bitmap, int sampleSize){
this.softBitmap = new SoftReference<Bitmap>(bitmap);
this.sampleSize = sampleSize;
}
}
}
}
public class FileCache {
private File cacheDir;
public FileCache(Context context){
//Find the dir to save cached images
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
cacheDir=new File(context.getExternalCacheDir(),Consts.STORE_CACHE);
else
cacheDir=context.getCacheDir();
if(!cacheDir.exists())
cacheDir.mkdirs();
}
public File getFile(String url){
//I identify images by hashcode. Not a perfect solution, good for the demo.
String filename=String.valueOf(url.hashCode());
File f = new File(cacheDir, filename);
return f;
}
public void clear(){
File[] files=cacheDir.listFiles();
for(File f:files)
f.delete();
}
}
imageLoader.DisplayImage(url, holder.image);