Gallery滑動的時候之所以會卡,是因為當它滑動到中間的時候,默認會為選中狀態,那麼這個時候就要去加載圖片,如果當圖片比較大的時候,就會導致卡一下。
一、通過異步加載圖片的方式
其餘的地方不變,隻是在Adapter中使用異步加載的方式。
[java]
public class GalleryAdapter extends BaseAdapter {
private ImageView[] imageView;// 加載圖片的imageView數組
private Context context;
private Integer[] imagesId;// 要顯示的圖片
public GalleryAdapter(Context context) {
this.context = context;
imagesId = new Integer[] { R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d,
R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d, R.drawable.a, R.drawable.b,
R.drawable.c, R.drawable.d, R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d,
R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d, R.drawable.a, R.drawable.b,
R.drawable.c, R.drawable.d, R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d };
imageView = new ImageView[imagesId.length];
}
public int getCount() {
return imagesId.length;
}
public Object getItem(int position) {
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), imagesId[position]);
return bitmap;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (imageView[position] == null)
imageView[position] = new ImageView(context);
new MyTask().execute(position);//開啟異步任務加載圖片
imageView[position].setLayoutParams(new MyGallery.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
return imageView[position];
}
private class MyTask extends AsyncTask<Integer, Void, Void> {
private Bitmap bitmap;
private int position;
@Override
protected Void doInBackground(Integer… params) {
//在這裡加載圖片
position = params[0];
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
bitmap = BitmapFactory.decodeResource(context.getResources(), imagesId[params[0]],
options);
return null;
}
@Override
protected void onPostExecute(Void result) {
//因為該方法是由UI線程調用,所以在這裡設置ImageView的圖片
super.onPostExecute(result);
imageView[position].setImageBitmap(bitmap);
}
}
}
[html]
<p>
</p><p>二、上面的方法,雖然是異步加載,可是,是先開啟加載,在顯示圖片,所以,被選中的ImageView會黑一下。而且不知道為什麼,理論上異步加載是不會卡的,可是,用這種方法加載更大一點的圖片,還是會卡一下,而且卡的很奇怪,總是在移到某一張圖片的時候,在往後面移動, 會先彈出下下一張圖片的一小部分,然後,才顯示下一張圖片。這中間會小卡一下,不明白原因啊!!所以想瞭下,采用瞭下面的方法改進。</p><p>每次緩沖3張,讓ImageView先顯示,再去異步加載圖片
</p><p>先看Adapter的代碼:</p><p>
</p>
[html]
<pre>
[java]
public class GalleryAdapter extends BaseAdapter {
private Context context;
private Integer[] imagesId;// 要顯示的圖片 www.aiwalls.com
private Bitmap[] nearBitmaps;// 自己所緩存的當前圖片附近的圖片,當前圖片是1,上一張是0,下一張是2
private int showingIndex;// 正在顯示的圖片是第幾張圖片
public GalleryAdapter(Context context, Integer[] imagesId) {
this.context = context;
this.imagesId = imagesId;
nearBitmaps = new Bitmap[3];
// 最開始的時候,先初始化最開始的3張圖片
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
nearBitmaps[1] = BitmapFactory.decodeResource(context.getResources(), imagesId[0], options);
nearBitmaps[2] = BitmapFactory.decodeResource(context.getResources(), imagesId[1], options);
}
public int getCount() {
return imagesId.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = new ImageView(context);
convertView.setLayoutParams(new MyGallery.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
}
if (position == showingIndex)
((ImageView)convertView).setImageBitmap(nearBitmaps[1]);
if (position == showingIndex – 1) {//說明是向前滑動
((ImageView)convertView).setImageBitmap(nearBitmaps[0]);
}
if (position == showingIndex + 1) {//說明是向後滑動
((ImageView)convertView).setImageBitmap(nearBitmaps[2]);
}
return convertView;
}
public Bitmap[] getNearBitmaps() {
return nearBitmaps;
}
public int getShowingIndex() {
return showingIndex;
}
public void setShowingIndex(int showingIndex) {
this.showingIndex = showingIndex;
}
Activity中的代碼:
[html]
<pre name="code" class="java">public class ImageScanActivity extends Activity {
private MyGallery gallery;
private GalleryAdapter adapter;
//圖片數組
private Integer[] imagesId = new Integer[] { R.drawable.a, R.drawable.b, R.drawable.c,
R.drawable.d, R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d, R.drawable.a,
R.drawable.b, R.drawable.c, R.drawable.d };
private int motionStatus=0;//記錄到底是向前滑動,還是向後,-1向前,1向後
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
gallery = (MyGallery) findViewById(R.id.gallery);
adapter = new GalleryAdapter(this,imagesId);
gallery.setAdapter(adapter);
gallery.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if(position==adapter.getShowingIndex()-1){//向前
new MyTask().execute();
motionStatus=-1;
}
if(position==adapter.getShowingIndex()+1){//向後
motionStatus=1;
new MyTask().execute();
}
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
private class MyTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void… params) {
int showing = adapter.getShowingIndex();// 記錄當前正在顯示圖片的id
Bitmap[] bitmaps = adapter.getNearBitmaps();//獲得Adapter中的緩存圖片數組
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
if(motionStatus==-1){//向前滑動,bitmaps[0]加載新的圖片
bitmaps[2]=bitmaps[1];
bitmaps[1]=bitmaps[0];
if(showing>=2)
bitmaps[0]=BitmapFactory.decodeResource(getResources(), imagesId[showing – 2],
options);
}
if(motionStatus==1){//向後滑動,bitmaps[2]加載新的圖片
bitmaps[0]=bitmaps[1];
bitmaps[1]=bitmaps[2];
if(showing<=imagesId.length-3)
bitmaps[2]=BitmapFactory.decodeResource(getResources(), imagesId[showing + 2],
options);
}
adapter.setShowingIndex(showing+motionStatus);
return null;
}
}
}
反正,就是先緩存幾張圖片,然後,根據移動,在加載圖片,因為如果一次加載太多瞭,容易內存泄漏。
感覺這樣做,真是吃力不討好,可是又實在想不出什麼好的辦法。而且當快速滑動的時候,grallery還會黑,刷新不出圖片瞭,雖然可以解決,可是太麻煩瞭,而且又會搞的有點卡。
到底怎麼一勞永逸的解決這個卡的問題,求指教啊!!!
摘自 LonelyRoamer的專欄