ListView载入照片的优化方法

【1】创建一个ListView布局

在activity的布局文件中添加ListView布局,其作用是告诉app此处有个ListView。

<ListView 
    				    android:id="@+id/main_list"
    				    android:layout_width="match_parent"
    				    android:layout_height="match_parent" > 		    
    				</ListView>


【2】定制ListView界面

步骤1完成后,界面上就有一个个List选项卡,但选项卡内部的布局需要再定制。(此处定义选项卡为一个List)

新建一个布局文件board_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    android:orientation="horizontal" >
    
    <ImageView
        android:id="@+id/board_image"
        android:layout_width="111dp"
        android:layout_height="150dp" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="10dip"
        android:orientation="vertical" >
        <TextView 
        	android:id="@+id/board_num"
        	android:layout_width="wrap_content"
        	android:layout_height="wrap_content" />
        <TextView
        	android:id="@+id/board_date"
        	android:layout_width="wrap_content"
        	android:layout_height="wrap_content" />
    </LinearLayout>

</LinearLayout>

上述布局文件说明每个选项卡有一个照片和两处文字。


【3】设计Adapter

Adapter与每个选项卡一一对应。选项卡作为界面显示,Adapter用于将数据提供给每个选项卡。Adapter是数据与选项卡的桥梁。

简单的ArrayAdapter在《第一行代码》中有介绍。另外,在书中的基础上,增加异步处理,将bitmap操作放到单独线程。代码如下:


public class BoardAdapter extends ArrayAdapter<Board>{
	
	private int resourceId;
	
	private static class ViewHolder{
		ImageView boardImage;
		TextView boardDate;
		TextView boardNum;
		int position;
	}
	
	public BoardAdapter(Context context, int textViewResourceId, List<Board> objects){
		super(context, textViewResourceId, objects);
		resourceId = textViewResourceId;
	}

	
	//getView在每个子项被滚到屏幕内的时候调用
	@Override
	public View getView(int position, View convertView, ViewGroup parent){
		
		Board board = getItem(position);
		
		View view; //代表每个子项
		ViewHolder viewHolder;
		
		//convertView,更新子项的布局
		if(convertView == null){
			//为子项加载传入的布局
			view = LayoutInflater.from(getContext()).inflate(resourceId,null);
			
			viewHolder = new ViewHolder();
			viewHolder.boardImage = (ImageView)view.findViewById(R.id.board_image);
			viewHolder.boardDate = (TextView)view.findViewById(R.id.board_date);
			viewHolder.boardNum = (TextView)view.findViewById(R.id.board_num);
			
			//给view添加一个额外的数据
			view.setTag(viewHolder);
			
		}else{
			view = convertView;
			viewHolder = (ViewHolder)view.getTag();
		}
		
		//保存数据的索引,传入AsyncTask
		viewHolder.position = position;
		
		//异步载入图片,参考谷歌的trainning 文档,异步工作方式参考《第一行代码》
		new AsyncTask<ViewHolder, Void, Bitmap>() {
		    private ViewHolder v;

		    @Override
		    protected Bitmap doInBackground(ViewHolder... params) {
		        v = params[0];
		        Board board = getItem(v.position);
				String PATH = Environment.getExternalStorageDirectory() + 
						"/boardpic/"+board.getPath()+".jpg";
				
				BitmapFactory.Options options = new BitmapFactory.Options();
				options.inSampleSize = 60;
				return BitmapFactory.decodeFile(PATH,options);
		    }

		    @Override
		    protected void onPostExecute(Bitmap result) {
		        super.onPostExecute(result);
		        
	            // If this item hasn't been recycled already, 
	            //show the image
	            v.boardImage.setVisibility(View.VISIBLE);
	            v.boardImage.setImageBitmap(result);
		        
		    }
		}.execute(viewHolder);
		
		viewHolder.boardNum.setText(String.valueOf(board.getNum()));
		viewHolder.boardDate.setText(board.getDate());
		return view;
	}
}



参考谷歌的培训文档:

http://developer.android.com/training/improving-layouts/smooth-scrolling.html#ViewHolder

Making ListView Scrolling Smooth

The key to a smoothly scrolling ListView is to keep the application’s main thread (the UI thread) free from heavy processing. Ensure you do any disk access, network access, or SQL access in a separate thread. To test the status of your app, you can enable StrictMode.

Use a Background Thread


Using a background thread ("worker thread") removes strain from the main thread so it can focus on drawing the UI. In many cases, using AsyncTask provides a simple way to perform your work outside the main thread. AsyncTask automatically queues up all the execute() requests and performs them serially. This behavior is global to a particular process and means you don’t need to worry about creating your own thread pool.

In the sample code below, an AsyncTask is used to load images in a background thread, then apply them to the UI once finished. It also shows a progress spinner in place of the images while they are loading.

// Using an AsyncTask to load the slow images in a background thread
new AsyncTask<ViewHolder, Void, Bitmap>() {
    private ViewHolder v;

    @Override
    protected Bitmap doInBackground(ViewHolder... params) {
        v = params[0];
        return mFakeImageLoader.getImage();
    }

    @Override
    protected void onPostExecute(Bitmap result) {
        super.onPostExecute(result);
        if (v.position == position) {
            // If this item hasn't been recycled already, hide the
            // progress and set and show the image
            v.progress.setVisibility(View.GONE);
            v.icon.setVisibility(View.VISIBLE);
            v.icon.setImageBitmap(result);
        }
    }
}.execute(holder);

Beginning with Android 3.0 (API level 11), an extra feature is available in AsyncTask so you can enable it to run across multiple processor cores. Instead of calling execute() you can specify executeOnExecutor() and multiple requests can be executed at the same time depending on the number of cores available.

Hold View Objects in a View Holder


Your code might call findViewById() frequently during the scrolling of ListView, which can slow down performance. Even when the Adapter returns an inflated view for recycling, you still need to look up the elements and update them. A way around repeated use of findViewById() is to use the "view holder" design pattern.

ViewHolder object stores each of the component views inside the tag field of the Layout, so you can immediately access them without the need to look them up repeatedly. First, you need to create a class to hold your exact set of views. For example:

static class ViewHolder {
  TextView text;
  TextView timestamp;
  ImageView icon;
  ProgressBar progress;
  int position;
}

Then populate the ViewHolder and store it inside the layout.

ViewHolder holder = new ViewHolder();
holder.icon = (ImageView) convertView.findViewById(R.id.listitem_image);
holder.text = (TextView) convertView.findViewById(R.id.listitem_text);
holder.timestamp = (TextView) convertView.findViewById(R.id.listitem_timestamp);
holder.progress = (ProgressBar) convertView.findViewById(R.id.progress_spinner);
convertView.setTag(holder);

Now you can easily access each view without the need for the look-up, saving valuable processor cycles.



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值