结合昨天学习的多线程,今天又继续对ListView进行了优化,包括异步加载图片,滑动时暂停加载,滑动停止后再加载显示界面中的item。

综合ListView在使用时参考的多篇博客,这里对ListView的使用进行全面的优化总结。

1. ListView 主界面

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView; public class MainListFragment extends Fragment implements OnItemClickListener, AbsListView.OnScrollListener { private final String TAG = this.getClass().getName().toString();
private View view;
private TextView noMovieTextView;
private ListView movieListView;
private MovieListAdapter mAdapter; private AsyncImageLoader asyncImageLoader = new AsyncImageLoader();
int start;
int end; @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.main_list_fragment, container, false);
return view;
} @Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); noMovieTextView = (TextView) view.findViewById(R.id.movie_list_no_movie_tv);
movieListView = (ListView) view.findViewById(R.id.movie_list_fragment_lv);
if (MovieList.getInstance().getArrayList().size() == 0) {
noMovieTextView.setVisibility(View.VISIBLE);
} else {
setListView();
}
} private void setListView() {
mAdapter = new MovieListAdapter(getActivity(), movieListHandler, asyncImageLoader, start, end);
movieListView.setAdapter(mAdapter);
movieListView.setOnItemClickListener(this);
movieListView.setOnScrollListener(this);
} @Override
public void onScrollStateChanged(AbsListView view, int onScroll) {
switch (onScroll) {
case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
// 手指触屏拉动准备滚动,只触发一次 顺序: 1
asyncImageLoader.lock();
break;
case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
// 持续滚动开始,只触发一次 顺序: 2
asyncImageLoader.lock();
break;
case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
// 整个滚动事件结束,只触发一次 顺序: 4
asyncImageLoader.unlock();
asyncImageLoader.setStartEnd(movieListView.getFirstVisiblePosition(), movieListView.getLastVisiblePosition());
break;
default:
break;
}
} @Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// 一直在滚动中,多次触发 顺序: 3
} @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String file_path = MovieList.getInstance().getArrayList().get(position).file_path;
Intent intent = new Intent(getActivity(), MoviePlayerActivity.class);
intent.putExtra("file_path", file_path);
startActivity(intent);
Log.i(TAG, "onItemClick");
} public Handler movieListHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
refreshListView();
}
}; public void refreshListView() {
if (mAdapter != null) {
mAdapter.notifyDataSetChanged();
} else {
noMovieTextView.setVisibility(View.GONE);
setListView();
}
} @Override
public void onDestroyView() {
super.onDestroyView();
((ViewGroup) view.getParent()).removeView(view);
} }

2. BaseAdapter

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView; import java.io.File; public class MovieListAdapter extends BaseAdapter {
private Context context;
private String record_image_path;
private Handler movieListHandler; int start;
int end; private AsyncImageLoader asyncImageLoader; public MovieListAdapter(Context context, Handler movieListHandler, AsyncImageLoader asyncImageLoader, int start, int end) {
this.context = context;
this.movieListHandler = movieListHandler; this.asyncImageLoader = asyncImageLoader;
this.start = start;
this.end = end; if (record_image_path == null) {
record_image_path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/APP/";
}
} @Override
public int getCount() {
return MovieList.getInstance().getArrayList().size();
} @Override
public Object getItem(int position) {
return null;
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder; if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.movie_list_item, parent, false);
holder = new ViewHolder();
holder.movie_image_iv = (ImageView) convertView.findViewById(R.id.movie_list_item_image_iv);
holder.movie_name_tv = (TextView) convertView.findViewById(R.id.movie_list_item_name_tv);
holder.total_time_tv = (TextView) convertView.findViewById(R.id.movie_list_item_total_time_tv);
holder.movie_size_tv = (TextView) convertView.findViewById(R.id.movie_list_item_size_tv);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
} String imagePath = record_image_path + MovieList.getInstance().getArrayList().get(position).movie_name + ".png";
File file = new File(imagePath);
if (file.exists()) {
// 1. Load Bitmap from SDCard
// holder.movie_image_iv.setImageBitmap(BitmapFactory.decodeFile(imagePath)); // 2. Load Bitmap from threadPool
holder.movie_image_iv.setTag(position);
loadImage(convertView, imagePath, position);
} else {
holder.movie_image_iv.setImageResource(R.drawable.loading);
movieListHandler.sendEmptyMessage(0);
} holder.movie_name_tv.setText(MovieList.getInstance().getArrayList().get(position).display_name); int sec = Integer.valueOf(MovieList.getInstance().getArrayList().get(position).total_time) / 1000 % 60;
int min = Integer.valueOf(MovieList.getInstance().getArrayList().get(position).total_time) / 1000 / 60;
holder.total_time_tv.setText(String.format("%02d:%02d", min, sec)); String movieSize = String.valueOf(Integer.valueOf(MovieList.getInstance().getArrayList().get(position).movie_size) / 1000 / 1000)
+ context.getResources().getString(R.string.movie_list_fragment_size);
holder.movie_size_tv.setText(movieSize); return convertView;
} private void loadImage(final View convertView, String imagePath, final int position) {
Bitmap cacheImage = asyncImageLoader.loadBitmap(imagePath, position, new AsyncImageLoader.ImageCallback() { @Override
public void imageLoaded(Bitmap imageBitmap) {
if ((convertView.findViewWithTag(position)) != null)
((ImageView) convertView.findViewWithTag(position)).setImageBitmap(imageBitmap);
// ((ImageView) convertView.findViewById(id)).setImageBitmap(imageBitmap);
Log.i("test", "1count: " + position);
}
}); if (cacheImage != null) {
((ImageView) convertView.findViewWithTag(position)).setImageBitmap(cacheImage);
// ((ImageView) convertView.findViewById(id)).setImageBitmap(cacheImage);
Log.i("test", "2count: " + position);
} else {
((ImageView) convertView.findViewWithTag(position)).setImageResource(R.drawable.loading);
// ((ImageView) convertView.findViewById(id)).setImageResource(R.drawable.loading);
}
} private class ViewHolder {
public ImageView movie_image_iv;
public TextView movie_name_tv;
public TextView total_time_tv;
public TextView movie_size_tv;
} }

3. AsyncImageLoader异步加载图片

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log; import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* Created by fansen on 2016/02/23.
*/
public class AsyncImageLoader {
// 为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动)
public Map<String, SoftReference<Bitmap>> imageCache = new HashMap<>();
private ExecutorService executorService = Executors.newFixedThreadPool(5);
private Handler handler = new Handler(); private boolean firstLoad = true;
private boolean allow = true;
private int startLoad;
private int endLoad; public void setStartEnd(int start, int end){
startLoad = start;
endLoad = end;
Log.i("test", "startLoad = " + startLoad);
Log.i("test", "endLoad = " + endLoad);
} public void lock() {
allow = false;
firstLoad = false;
} public void unlock() {
Log.i("test", "allow = true");
allow = true;
} /**
* @param imagePath 图像路径
* @param callback 回调接口
* @return 返回内存中缓存的图像,第一次加载返回null
*/
public Bitmap loadBitmap(final String imagePath, final int position, final ImageCallback callback) { // 如果缓存过就从缓存中取出数据
if (imageCache.containsKey(imagePath)) {
SoftReference<Bitmap> softReference = imageCache.get(imagePath);
if (softReference.get() != null) {
Log.i("test", "AsyncImageLoader: ----2----");
return softReference.get();
}
} // 缓存中没有图像,则从存储卡中取出数据,并将取出的数据缓存到内存中
executorService.submit(new Runnable() { @Override
public void run() {
while (!allow){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
} if (firstLoad || (position >= startLoad && position <= endLoad)) {
// 测试时,模拟网络延时,实际时这行代码不能有
SystemClock.sleep(2000); final Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
imageCache.put(imagePath, new SoftReference<>(bitmap)); handler.post(new Runnable() {
@Override
public void run() {
Log.i("test", "AsyncImageLoader: ----1----");
callback.imageLoaded(bitmap);
}
});
}
}
});
return null;
} //对外界开放的回调接口
public interface ImageCallback {
//注意 此方法是用来设置目标对象的图像资源
void imageLoaded(Bitmap imageBitmap); }
}

Android ListView 全面优化的更多相关文章

  1. Android listview 的优化

    接[Android listview的应用][1] 在我们上一篇[Android listview的应用][1]中,我们的adapter中的getView()方法中每次都将布局重新加载一遍,这样就会导 ...

  2. Android ListView性能优化实例讲解

    前言: 对于ListView,大家绝对都不会陌生,只要是做过Android开发的人,哪有不用ListView的呢? 只要是用过ListView的人,哪有不关心对它性能优化的呢? 关于如何对ListVi ...

  3. Android Listview 性能优化

    首先我一般使用的适配器是BaseAdapter,其中有两个方法最主要,分别是: getCount,getView, 在对Listview 进行优化的时候,首先使用 convertview 和viewH ...

  4. (翻译) Android ListView 性能优化指南

    本文翻译了Lucas Rocha的Performance Tips for Android’s ListView.这是一篇关于介绍如何提升ListView性能的文章,非常的优秀.使得我拜读之后,忍不住 ...

  5. Android ListView的优化

    最近的项目中有通讯录这个模块,里面的通讯录涉及的联系人数量很大,导致在加载页面的时候有点卡,所以就必须得进行优化,优化的最终实现理论是什么?就是让ListView一次性加载的数据较少,后续根据用户操作 ...

  6. android: ListView历次优化

    第一版: ListView一屏显示多少对象其内部就创建多少View对象.滑动时退出的缓存对象留给滑进去时调用getView传的convertView.因为如果每次都findViewById查找创建视图 ...

  7. android ListView优化

    android ListView通过优化重用历史缓存实现.listview相应的数据适配器一般使用自己定义BaseAdapter子类,重用历史缓冲区来提高性能. 例如,下面的示例代码演示: 1.lis ...

  8. Android之ListView性能优化——一行代码绑定数据——万能适配器

    如下图,加入现在有一个这样的需求图,你会怎么做?作为一个初学者,之前我都是直接用SimpleAdapter结合一个Item的布局来实现的,感觉这样实现起来很方便(基本上一行代码就可以实现),而且也没有 ...

  9. android ListView的介绍和优化

    xml设计 <?xml version="1.0"?> -<RelativeLayout tools:context=".MainActivity&qu ...

随机推荐

  1. python上下文管理器及with语句

    with语句支持在一个叫上下文管理器的对象的控制下执行一系列语句,语法大概如下: with context as var: statements 其中的context必须是个上下文管理器,它实现了两个 ...

  2. hdu 5646 DZY Loves Partition 二分+数学分析+递推

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=5646 题意:将n分成k个正整数之和,要求k个数全部相同:并且这k个数的乘积最大为多少?结果mod 1e^9 ...

  3. 由12306出错想到的div垂直居中的问题

    今天想看看元旦回家还有没有余票,偷偷的打开了12306,开始查询回家的车票,结果发现,竟然查询不出来,再查直接出错了 看到这个很郁闷,很纠结,但是突然想到了最近一直想实现div垂直居中,赶紧试了一下1 ...

  4. dos下的edit命令使用详解

    dos下的edit命令使用详解 来源:网络 作者:未知 edit命令是一个简单的编辑软件,我们经常用它来编辑一些程序和批处理文件. 比如,我想在c盘根目录下编辑一个简单的批处理文件,要求无论当前盘和当 ...

  5. java Scanner与BufferedReader读取键盘输入性能比较

    java  Scanner与BufferedReader读取键盘输入性能比较            1.Scanner和BufferedReader 性能比较 在java中常见的从键盘获取输入的方式有 ...

  6. WordPress 前端用户投稿插件 Frontend Publishing

    WordPress添加投稿功能(无需注册/可邮件通知站长和投稿人) WordPress匿名投稿插件:DX-Contribute (有朋友反馈不能用) WordPress投稿插件:User Submit ...

  7. 1182-IP地址转换

    描述 给定一个点分十进制的IP地址,把这个IP地址转换为二进制形式. 输入 输入只有一行,一个点分十进制的IP地址 包括四个正整数,用三个.分开,形式为a.b.c.d 其中0<=a,b,c,d& ...

  8. 设置Tomcat的UTF-8编码

    利用request.setCharacterEncoding("UTF-8");来设置Tomcat接收请求的编码格式,只对POST方式提交的数据有效,对GET方式提交的数据无效! ...

  9. 如何将Springside4项目转成Eclipse项目

    1)下载springside4 官网地址 http://www.springside.org.cn/download.html 2)运行CMD,进入 C:\Documents and Settings ...

  10. 滑动RecyclerView时出现异常: java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 6(offset:6).state:30

    RecyclerView 存在的一个明显的 bug 一直没有修复: java.lang.IndexOutOfBoundsException: Inconsistency detected. Inval ...