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
如果有疑问,请留言,希望和一起解决共同遇得到的那题。
相关文章推荐
- Android 中compiledSDKVersion,minSdkVersion,targetSdkVersion的含义
- Android之ContentProvider使用
- Android中文API(129) —— AudioManager
- Android 应用添加快捷方式
- Android设计模式(八)--模板方法模式
- Android中ViewPager的使用
- Android用onCreateOptionsMenu()创建optinosMenu
- Android用onCreateOptionsMenu()创建optinosMenu
- android editText inputType 各个字段的含义
- Android的PopupWindow使用android学习之旅(四十三)
- android中image文件的压缩与解压缩
- Android的PopupWindow使用android学习之旅(四十三)
- Android的PopupWindow使用android学习之旅(四十三)
- 一---Android-SDK系列文章(6) ---JAVA 程序&& android应用程序(main函数)
- Android 通话:后台通话过程中锁屏解锁,发现听筒内存在锁屏提示音
- Android学习 - 如何结束进程
- 做Android设备的4条道路,为什么都不适合微软?!
- Android学习 1 -构建运行环境
- Android应用间跳转
- ListView setSelection 无效问题