继承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); } }