灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:1970回复:0

控件一:Gallery之滑动不流畅的解决办法,异步加载

楼主#
更多 发布于:2012-09-06 14:02

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.atcpu.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还会黑,刷新不出图片了,虽然可以解决,可是太麻烦了,而且又会搞的有点卡。
到底怎么一劳永逸的解决这个卡的问题,求指教啊!!!





喜欢0 评分0
游客

返回顶部