继承BaseAdapter的子类的基本实现和改进
基本过程:新建TopicAdapter,继承BaseAdapter,重写需要重写的方法。
第一步:增加一个带多个参数的构造函数和对应的属性,其目的是为了传递适配器使用过程所必需的参数
为了传递参数方便,增加TopicAdapter的带多个参数的构造函数,这样在Activity使用Adapter的时候方便使用,这里的多参数的构造函数仅仅是为了传递参数而已。
private List<Topic> dataList;
private int listviewItemRId;
private File cacheDir;
private LayoutInflater inflater;
/**
* 此构造函数是自己添加的,输入参数的值需要有对应的属性来接收
* (也可以使用setter方法来实现传值,但个人不赞成)
* @param context 应用上下文,此处是为了通过context得到LayoutInflater实例
* @param dataList 传递给Adapter的数据List
* @param listviewItemRId 显示ListView的条目Item的布局文件的RID
* @param cacheDir 用于缓存数据和图片文件的SD卡文件路径
*/
public TopicAdapter(Context context, List<Topic> dataList,
int listviewItemRId, File cacheDir){
String serverName = Context.LAYOUT_INFLATER_SERVICE;
this.inflater = (LayoutInflater)context.getSystemService(serverName);
this.dataList = dataList;
this.listviewItemRId = listviewItemRId;
this.cacheDir = cacheDir;
}
第二步、重写几个比较简单的方法
@Override
public int getCount() {
return dataList.size();
}
@Override
public Object getItem(int position) {
return dataList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
第三步、重写getView的方法,详见具体实现。
/**
* 返回待显示(第position条)Item所对应的View
* @param position: 是待显示item所对应的index
* @param convertView: 是待显示item所对应的View
* @param parent: 是待显示item所对应的View的parent
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = null;
TextView textView = null;
/**convertView先判断是否为空,如果为空则需要重新创建,然后获得imageView和textView组件;
* 如果不为空的,则从缓存中获得获得imageView和textView组件;
* 最后为imageView和textView准备对应的数据**/
if(convertView == null){
convertView = inflater.inflate(listviewItemRId, null);
imageView = (ImageView) convertView.findViewById(R.id.imageView);
textView = (TextView) convertView.findViewById(R.id.textView);
convertView.setTag(new DataWrapper(imageView, textView));
}else{
DataWrapper dataWrapper = (DataWrapper) convertView.getTag();
imageView = dataWrapper.imageView;
textView = dataWrapper.textView;
}
try {
Topic topic = dataList.get(position);
textView.setText(topic.title);
Uri imageURI = TopicService.getImage(topic.imageSrc, cacheDir);
imageView.setImageURI(imageURI);
} catch (Exception e) {
e.printStackTrace();
}
return convertView;
}
private final class DataWrapper{
public ImageView imageView;
public TextView textView;
public DataWrapper(ImageView imageView, TextView textView) {
this.imageView = imageView;
this.textView = textView;
}
}
以上的两行代码可能存在较为严重的性能问题,即可能出现ANR的错误。
所以第五步、使用多线程来修改。是修改为以下的代码
try {
Topic topic = dataList.get(position);
textView.setText(topic.title);
//Uri imageURI = TopicService.getImage(topic.imageSrc, cacheDir);
//imageView.setImageURI(imageURI);
asyncImageLoad(imageView, topic.imageSrc);
} catch (Exception e) {
e.printStackTrace();
}
新增新的asyncImageLoad()的方法
private void asyncImageLoad(final ImageView imageView, final String path) {
final Handler handler = new Handler(){
public void handleMessage(Message msg) {//运行在主线程中
/**主线程的handleMessage接到回传数据后,更新imageView的数据**/
Uri uri = (Uri)msg.obj;
if(uri!=null && imageView!= null)
imageView.setImageURI(uri);
}
};
Runnable runnable = new Runnable() {
public void run() {//在子线程中运行
try {
Uri uri = TopicService.getImage(path, cacheDir);
/*通过handler的sendMessage()来回传数据到主线程*/
handler.sendMessage(handler.obtainMessage(10, uri));
} catch (Exception e) {
e.printStackTrace();
}
}
};
new Thread(runnable).start();
}
第六步、使用AsyncTask优化第五步的多线程代码
private void asyncImageLoad(ImageView imageView, String path) {
AsyncImageTask asyncImageTask = new AsyncImageTask(imageView);
asyncImageTask.execute(path);
/**通过asyncImageTask.execute(path)调用AsyncImageTask的doInBackground()方法
* path是第一个参数,所以在doInBackground()的params[0]的值其实是path */
}
private final class AsyncImageTask extends AsyncTask<String, Integer, Uri>{
private ImageView imageView;
public AsyncImageTask(ImageView imageView) {
this.imageView = imageView;
}
protected Uri doInBackground(String... params) {//子线程中执行的
try {
/**这里接收到execute传入的path的值进行处理,处理结果Uri返回给onPostExecute**/
return TopicService.getImage(params[0], cacheDir);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Uri result) {//运行在主线程
if(result!=null && imageView!= null)
imageView.setImageURI(result);
}
}