android 继承BaseAdapter的子类的基本实现和改进
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;}
?
第二步、重写几个比较简单的方法
@Overridepublic int getCount() {return dataList.size();}@Overridepublic Object getItem(int position) {return dataList.get(position);}@Overridepublic long getItemId(int position) {return position;}?
第三步、重写getView的方法,详见具体实现。
/** * 返回待显示(第position条)Item所对应的View * @param position: 是待显示item所对应的index * @param convertView: 是待显示item所对应的View * @param parent: 是待显示item所对应的View的parent */@Overridepublic 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);}}?
?
?
