您的位置:首页 > 移动开发 > Android开发

Android中Gridview和ViewPager显示图片的优化处理(2)

2015-06-09 16:26 459 查看

2.ViewPager显示图片

解决在GridView中显示图片出现的OOM,加载速度缓慢问题等等,请查看Android中Gridview和ViewPager显示图片的优化处理(1)。

在GridView中,要查看图片的大图时,通常用ViewPager进行显示,而在ViewPager中由于图片过大,加载几张就会导致OOM,因此要及时的回收图片占用的内存。解决思路:只保证当前页、上一页、下一页加载图片或者只有当前页加载图片,滑到上一页和下一页时再加载图片。下面将从ViewPager和ImageSwitcher来解决显示大图出现的问题。

1.ViewPager

在ViewPager中有一个重要的方法viewPager.setOffscreenPageLimit(limit),该方法表示设置ViewPager加载页数。在默认情况下,通过Log分析,有的手机加载7页才开始销毁View,有的手机默认加载3页开始销毁View。




加载7页很容易就出现了OOM,加载3页也只是推迟了出现OOM,因此可以设置viewPager.setOffscreenPageLimit(0),加载的页数为3页(当前页,上一页,下一页),但是这样也并不能解决OOM。在PagerAdapter的destroyItem()方法中((ViewPager) container).removeView((View) object),只是移出了View,但是并没有清空Bitmap占用的内存。因此可以在这个方法中清空Bitmap占用的内存。另外在instantiateItem()方法中,不要加载图片,在接口OnPageChangeListener的onPageSelected()方法中再加载图片。

package com.example.album;

import java.util.ArrayList;
import java.util.List;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v4.util.LruCache;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

import com.example.album.adapter.BitmapAsyncTask;
import com.example.album.view.MyImageView;

public class VPActivity extends Activity implements OnPageChangeListener {

	public static final String URIS = "uris";
	public static final String POSITION = "position";
	private List<View> mViews;
	private ArrayList<String> mUris;
	private ViewPager mViewPager;
	private LruCache<String, Bitmap> mLruCache;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_vp);

		mViewPager = (ViewPager) findViewById(R.id.viewpager);
		mUris = getIntent().getStringArrayListExtra(URIS);
		mViews = new ArrayList<View>(mUris.size());
		mLruCache = new LruCache<String, Bitmap>((int) Runtime.getRuntime()
				.maxMemory() / 8) {
			@SuppressLint("NewApi")
			@Override
			protected int sizeOf(String key, Bitmap value) {
				return value.getByteCount();
			}
		};
		mViewPager.setOffscreenPageLimit(0);// 设置加载页数,为0的时候是3页,默认会加载7页
		// viewPager.setPageMargin(marginPixels);设置页边间距
		mViewPager.setOnPageChangeListener(this);
		mViewPager.setAdapter(new VPActivityAdpter());
		mViewPager.setCurrentItem(getIntent().getIntExtra(POSITION, 0));
	}

	@Override
	protected void onDestroy() {
		if (mLruCache != null) {
			mLruCache.evictAll();
			mLruCache = null;
		}
		super.onDestroy();
	}

	@Override
	public void onBackPressed() {
		super.onBackPressed();
	}

	private class VPActivityAdpter extends PagerAdapter {

		VPActivityAdpter() {
			int size = mUris.size();
			for (int i = 0; i < size; i++) {
				MyImageView picture = new MyImageView(VPActivity.this);
				picture.setLayoutParams(new ViewPager.LayoutParams());
				mViews.add(picture);
			}
		}

		@Override
		public int getCount() {
			return mUris.size();
		}

		@Override
		public void destroyItem(ViewGroup container, int position, Object object) {

			Bitmap bitmap = mLruCache.get(mUris.get(position));
			if (bitmap != null && !bitmap.isRecycled()) {
				bitmap.recycle();
				mLruCache.remove(mUris.get(position));
				bitmap = null;
				Log.d("TAG", "destroyItem=" + position);
			}
			((ViewPager) container).removeView((View) object);
		}

		@SuppressWarnings("unchecked")
		@Override
		public Object instantiateItem(ViewGroup container, int position) {
			Log.d("TAG", "instantiateItem=" + position);
			container.addView(mViews.get(position), 0);
			// 当postition=0的时候,不会调用接口OnPageChangeListener中的方法
			if (position == 0) {
				new BitmapAsyncTask(
						VPActivity.this,
						(MyImageView) mViews.get(position),
						mUris.get(position),
						new int[] {
								getResources().getDisplayMetrics().widthPixels,
								getResources().getDisplayMetrics().heightPixels })
						.execute(mLruCache);
			}
			return mViews.get(position);
		}

		@Override
		public boolean isViewFromObject(View arg0, Object arg1) {
			return arg0 == arg1;
		}

	}

	@Override
	public void onPageScrollStateChanged(int arg0) {
	}

	@Override
	public void onPageScrolled(int arg0, float arg1, int arg2) {
	}

	@SuppressWarnings("unchecked")
	@Override
	public void onPageSelected(int arg0) {

		MyImageView picture = (MyImageView) mViews.get(arg0);
		if (mLruCache.get(mUris.get(arg0)) == null) {
			new BitmapAsyncTask(VPActivity.this,
					(MyImageView) mViews.get(arg0), mUris.get(arg0), new int[] {
							getResources().getDisplayMetrics().widthPixels,
							getResources().getDisplayMetrics().heightPixels })
					.execute(mLruCache);
		} else {
			picture.setImageBitmap(mLruCache.get(mUris.get(arg0)));
		}

	}

}


在测试过程中,除了小米手机之外,其它测试的手机三星、索尼、联想、酷派、中兴等等都没有出现OOM。因此还需要继续优化,那么可以只加载当前显示的图片在内存中,不要预先加载上一页和下一页的图片。刚好发现Android提供了一个ImageSwitcher类,可以用来显示图片。

2.ImageSwitcher

下面为使用ImageSwitcher显示图片,要监听手势滑动。用一个CacheBitmap来缓存当前显示的Bitmap,当显示下一个Bitmap时,就清空上一个Bitmap占用的内存,这样只保证内存只有一张图片。

package com.example.album;

import java.util.ArrayList;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageSwitcher;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.ViewSwitcher.ViewFactory;

import com.example.album.utils.BitmapUtil;
import com.example.album.view.MyImageView;

public class ISActivity extends Activity implements ViewFactory,
		OnTouchListener {

	private static final int ID = 0x123;
	private float startX = 0.0f;
	private float endX = 0.0f;
	private int index = 0;
	private boolean isMove = false;
	private Animation inAnimation;
	private Animation outAnimation;
	private Bitmap cacheBitmap;
	private ArrayList<String> uris;
	private ImageSwitcher switcher;
	private ImageSwitcher.LayoutParams params;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_imageswithcer);

		index = getIntent().getIntExtra(VPActivity.POSITION, 0);
		uris = getIntent().getStringArrayListExtra(VPActivity.URIS);
		switcher = (ImageSwitcher) findViewById(R.id.imageswither);
		params = new ImageSwitcher.LayoutParams(
				ViewGroup.LayoutParams.MATCH_PARENT,
				ViewGroup.LayoutParams.MATCH_PARENT);
		switcher.setFactory(this);
		switcher.setOnTouchListener(this);
	}

	@Override
	public void onBackPressed() {
		super.onBackPressed();
	}

	@Override
	public View makeView() {
		MyImageView picture = new MyImageView(this);
		picture.setId(ID);
		cacheBitmap = BitmapUtil.compress(this, uris.get(index), getResources()
				.getDisplayMetrics().widthPixels, getResources()
				.getDisplayMetrics().heightPixels);
		picture.setScaleType(ScaleType.CENTER);
		picture.setLayoutParams(params);
		picture.setImageBitmap(cacheBitmap);
		return picture;
	}

	@SuppressLint({ "NewApi", "ClickableViewAccessibility" })
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			startX = event.getX();
		} else if (event.getAction() == MotionEvent.ACTION_UP) {
			if (isMove) {
				endX = event.getX();
				// 判断向左滑动
				if (startX - endX > 50) {
					index = (index + 1 < uris.size()) ? ++index : 0;
					inAnimation = new TranslateAnimation(-100f, 0f, 0f, 0f);
					outAnimation = new TranslateAnimation(0f, -100f, 0f, 0f);
				// 判断向右滑动
				} else if (endX - startX > 50) {
					index = index - 1 > 0 ? --index : uris.size() - 1;
					inAnimation = new TranslateAnimation(100f, 0f, 0f, 0f);
					outAnimation = new TranslateAnimation(0f, 100f, 0f, 0f);
				}
				recycleCacheBitmap();
				Bitmap bitmap = BitmapUtil.compress(this, uris.get(index),
						getResources().getDisplayMetrics().widthPixels,
						getResources().getDisplayMetrics().heightPixels);
				ImageView picture = (ImageView) switcher.findViewById(ID);
				picture.setImageBitmap(bitmap);
				switcher.setInAnimation(inAnimation);
				switcher.setOutAnimation(outAnimation);
				inAnimation.startNow();
				outAnimation.startNow();
				cacheBitmap = bitmap;
			}
		} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
			isMove = true;
		}
		return true;
	}

	// 回收掉缓存的Bitmap
	private void recycleCacheBitmap() {
		if (cacheBitmap != null && !cacheBitmap.isRecycled()) {
			cacheBitmap.recycle();
			cacheBitmap = null;
		}

	}

}


通过ImageSwitcher,解决了在小米手机上显示图片时的OOM问题。虽然这样动画效果不是很好,但是不是主要的问题了,后面可以再仔细研究下切换图片时的过度动画效果。已经尝试用Animator去做过度动画,但还没有达到像Viewpager那样显示的效果,努力研究中。

到此,查看大图片的问题已经解决。源代码地址http://download.csdn.net/detail/wangjiang_qianmo/8789451

如果有疑问,请留言,希望和一起解决共同遇得到的那题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: