`
arest
  • 浏览: 21771 次
  • 性别: Icon_minigender_1
  • 来自: 南京
最近访客 更多访客>>
社区版块
存档分类
最新评论

正确的在ViewPager中使用Bitmap图像

 
阅读更多
欢迎访问:[http://www.3body.tk/iblog/](http://www.3body.tk/iblog/)

在实现image gallery的详情查看时使用swipe view模式是很好的选择,你可以使用ViewPager和对应的PagerAdapter来实现这个模式。不过对于adapter你还有更好的选择:FragmentStatePagerAdapter,当屏幕关闭的时候这个子类可以自动的销毁和保存ViewPager的Fragments状态,以节省内存。

注意:如果你只需要使用很少的图片,并确定其不会超出程序内存的限制的话,使用PagerAdapter或者FragmentPagerAdapter对于你来说是最适合的。

下面是一个ViewPager的实现,他里面包含了数个ImageView。在main activity中使用ViewPager和adapter:

public class ImageDetailActivity extends FragmentActivity {
    public static final String EXTRA_IMAGE = "extra_image";

    private ImagePagerAdapter mAdapter;
    private ViewPager mPager;

    // A static dataset to back the ViewPager adapter
    public final static Integer[] imageResIds = new Integer[] {
            R.drawable.sample_image_1, R.drawable.sample_image_2, R.drawable.sample_image_3,
            R.drawable.sample_image_4, R.drawable.sample_image_5, R.drawable.sample_image_6,
            R.drawable.sample_image_7, R.drawable.sample_image_8, R.drawable.sample_image_9};

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.image_detail_pager); // Contains just a ViewPager

        mAdapter = new ImagePagerAdapter(getSupportFragmentManager(), imageResIds.length);
        mPager = (ViewPager) findViewById(R.id.pager);
        mPager.setAdapter(mAdapter);
    }

    public static class ImagePagerAdapter extends FragmentStatePagerAdapter {
        private final int mSize;

        public ImagePagerAdapter(FragmentManager fm, int size) {
            super(fm);
            mSize = size;
        }

        @Override
        public int getCount() {
            return mSize;
        }

        @Override
        public Fragment getItem(int position) {
            return ImageDetailFragment.newInstance(position);
        }
    }
}

下面是使用Fragment和ImageView的一个实现,看上去是十分合理的,你能发现它的缺点吗?并且如何进行改进?

public class ImageDetailFragment extends Fragment {
    private static final String IMAGE_DATA_EXTRA = "resId";
    private int mImageNum;
    private ImageView mImageView;

    static ImageDetailFragment newInstance(int imageNum) {
        final ImageDetailFragment f = new ImageDetailFragment();
        final Bundle args = new Bundle();
        args.putInt(IMAGE_DATA_EXTRA, imageNum);
        f.setArguments(args);
        return f;
    }

    // Empty constructor, required as per Fragment docs
    public ImageDetailFragment() {}

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mImageNum = getArguments() != null ? getArguments().getInt(IMAGE_DATA_EXTRA) : -1;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // image_detail_fragment.xml contains just an ImageView
        final View v = inflater.inflate(R.layout.image_detail_fragment, container, false);
        mImageView = (ImageView) v.findViewById(R.id.imageView);
        return v;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        final int resId = ImageDetailActivity.imageResIds[mImageNum];
        mImageView.setImageResource(resId); // Load image into ImageView
    }
}

希望你已经注意到了这个问题:所有的图片都是在UI线程中处理的,这样将导致程序挂掉,强制退出。这时需要使用AsyncTask(在“Processing Bitmaps Off the UI Thread”这一篇文章中介绍过的)来处理,直接将图片的加载和处理放在后台线程中去做。

public class ImageDetailActivity extends FragmentActivity {
    ...

    public void loadBitmap(int resId, ImageView imageView) {
        mImageView.setImageResource(R.drawable.image_placeholder);
        BitmapWorkerTask task = new BitmapWorkerTask(mImageView);
        task.execute(resId);
    }

    ... // include BitmapWorkerTask class
}

public class ImageDetailFragment extends Fragment {
    ...

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (ImageDetailActivity.class.isInstance(getActivity())) {
            final int resId = ImageDetailActivity.imageResIds[mImageNum];
            // Call out to ImageDetailActivity to load the bitmap in a background thread
            ((ImageDetailActivity) getActivity()).loadBitmap(resId, mImageView);
        }
    }
}

任何多余的处理(比如调整图像大小,从网络获取图片)都移到BitmapWorkerTask中,这样就不会影响到UI主线程。如果后台线程除了在硬盘中直接读取图片之外还有其他处理,在内存或硬盘中加入一个缓存是十分有用的(在“Caching Bitmaps”这篇文章中有介绍)。下面是一个内存缓存的实现:

public class ImageDetailActivity extends FragmentActivity {
    ...
    private LruCache<String, Bitmap> mMemoryCache;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        // initialize LruCache as per Use a Memory Cache section
    }

    public void loadBitmap(int resId, ImageView imageView) {
        final String imageKey = String.valueOf(resId);

        final Bitmap bitmap = mMemoryCache.get(imageKey);
        if (bitmap != null) {
            mImageView.setImageBitmap(bitmap);
        } else {
            mImageView.setImageResource(R.drawable.image_placeholder);
            BitmapWorkerTask task = new BitmapWorkerTask(mImageView);
            task.execute(resId);
        }
    }

    ... // include updated BitmapWorkerTask from Use a Memory Cache section
}

现在将上面的代码片段整理一下,就是一个完美的ViewPager,它实现了最小化的图片资源加载延迟,可以在后台线程中实现尽量多或尽量少的处理(根据你的需求)。

下面一篇文章会介绍如何在GridView中做类似的处理。

翻译自:Displaying Bitmaps in Your UI

分享到:
评论

相关推荐

    高仿微信图片放大拖动浏览,自定义ImageView

    本文将深入探讨如何基于ImageView实现一个“高仿微信图片放大拖动浏览”的功能,包括支持双击缩放以及在ViewPager中嵌套使用。 首先,我们需要创建一个新的自定义控件,命名为XlhZoomImageView,它继承自Android...

    Android 图片浏览源码.zip

    在处理大量图片时,我们需要谨慎使用Bitmap,避免内存泄漏和oom问题,可能需要使用到Bitmap的配置和复用策略。 6. **动画效果**:为了提升用户体验,源码可能会包含一些过渡动画,如淡入淡出、平移等。这些可以通过...

    Andriod图片查看

    因此,我们需要确保图片在各种设备上都能正确显示,这可能涉及到布局适配和尺寸单位的使用。 总的来说,Andriod图片查看案例涵盖了Android开发中的图片加载、显示、手势识别、内存管理和用户体验优化等多个方面,...

    图片阅读器V1.2

    在图片阅读器V1.2中,考虑到图片可能会占用大量内存,开发者可能采用了内存优化策略,如使用Bitmap的高效加载和复用机制,以及及时回收不再使用的Bitmap对象,防止内存泄漏。此外,可能还利用了软引用和弱引用等内存...

    Gallery使用AsyncTask异步批量加载图片

    在Android开发中,`Gallery`组件是用于展示图像的一个旧版控件,它允许用户以横向滑动的方式浏览多张图片。然而,由于性能和功能的限制,`Gallery`已经在API 16(Android 4.1)之后被废弃,取而代之的是更现代的`...

    android特效GaussPager高斯模糊渐变的滑动效果.rar

    高斯模糊是图像处理中常见的滤波技术,它通过模拟高斯函数对图像进行平滑处理,可以降低图像中的噪声,同时保留边缘信息。在Android中,我们可以通过Java或Kotlin来实现这一效果。 高斯模糊主要涉及到以下几个关键...

    android 图片查看器 java 语言

    3. **GestureDetector与ScaleGestureDetector**:在Android中,为了处理用户的触摸事件,通常会使用GestureDetector来识别滑动、点击等基本手势,而ScaleGestureDetector则可以识别缩放手势。这些类可以帮助我们监听...

    图片阅读器代码(V1.0)

    在这个项目中,ViewPager用于展示图片,允许用户左右滑动切换不同的图片,提供了平滑的过渡效果和高效的内存管理。 2. **图片加载库**:在Android应用开发中,处理图片加载和缓存是非常常见且重要的任务。由于项目...

    android系统图库手势放大缩小滑动效果

    在这个项目中,ViewPager可能被用来展示一系列图片,并且在切换图片时保持手势操作的连贯性。 3. **自定义ImageView**: - **SimpleTouchImageView**:这个名称可能表示项目中自定义了一个ImageView子类,以支持更...

    逼真翻页效果.zip

    3. **PageTransformer**:在Android的ViewPager组件中,可以使用PageTransformer接口来自定义页面滑动时的变换效果。通过重写`transformPage()`方法,可以控制每个页面在滑动过程中的视觉变化,实现翻页效果。 4. *...

    android gif模式和图片展现模式 图片展现神器.zip

    在Android开发中,图片的展示是非常重要的一环,特别是在当今移动应用中,动态图像是吸引用户注意力和增强用户体验的有效手段。本资料包“android gif模式和图片展现模式 图片展现神器.zip”显然聚焦于如何在Android...

    Android实现图片叠加功能

    在使用微信 SDK 分享图片的过程中,发现图片过大会导致微信拉起失败。为了解决这个问题,我们可以将图片压缩至原来的一半,以减少图片占用内存。压缩图片可以使用 Matrix 对象的 setScale 方法将图片缩放到原来的...

    weixinps_android源码_

    此外,还要考虑性能优化,如使用异步处理避免UI卡顿,以及权限管理,确保应用在请求访问相册或相机等敏感资源时有正确的权限。 总结起来,微信风格的图片上传功能在Android中实现涉及到多个环节,包括图片选择、...

    android实现仿真翻页效果_动画效果.zip

    同时,`Canvas`用于绘制页面,通过`drawBitmap()`或`drawRect()`等方法在画布上绘制页面图像。 4. **透视效果**: 真实的翻页效果需要考虑到透视,即离观察者近的页面部分看起来更大。可以通过调整Matrix中的透视...

    Android Training Course in Chinese

    - 使用模拟位置进行测试:了解如何在开发过程中使用模拟位置进行测试。 #### 七、Android可穿戴应用 - **赋予Notification可穿戴特性** - 创建Notification:学习如何创建适应于可穿戴设备的Notification。 - ...

    Android代码-图片浏览功能源码.zip

    Android系统提供了丰富的API来处理图像,例如Bitmap类用于加载和显示图片,ImageView则是展示图片的主要组件。在实际开发中,我们通常会结合使用这两个核心元素。然而,直接加载大图可能会导致内存溢出(OOM),因此...

    android仿照电子相册源码

    因此,源码可能包含了Bitmap的优化策略,如使用inSampleSize减小图片大小,或者使用LruCache进行内存缓存。 7. **数据持久化**: 如果相册有收藏或者排序功能,那么数据持久化是必要的。除了SQLite,还可以使用...

    AndroidTrainingCHS.v0.9.1.pdf

    - **使用模拟位置进行测试:** 在开发过程中使用模拟位置进行测试。 #### 七、Android可穿戴应用 **1. 赋予Notification可穿戴特性** - **创建Notification:** 在可穿戴设备上创建通知。 - **在Notification中...

    GalleryDemo.zip项目安卓应用源码下载

    在早期版本的Android SDK中,有一个叫做Gallery的视图类,但在后来的版本中被废弃,取而代之的是更现代、功能更强大的RecyclerView或ViewPager等组件。因此,这个项目可能展示了如何利用这些新组件来实现类似的功能...

    安卓GalleryDemo图片浏览器

    使用`RelativeLayout`或`LinearLayout`来组合这些元素,并确保布局能在不同屏幕尺寸下正确显示。 5. **触摸事件处理**:为了实现滑动浏览图片,我们需要监听用户的触摸事件,处理滑动、缩放和旋转手势。可以重写`...

Global site tag (gtag.js) - Google Analytics