在UI中显示Bitmap

uniapp-APP环境下截屏或整个页面生成图片 uniapp-app环境截屏或整个页面生成图片 阅读详情
这节课将我们前面几节课学习的东西都整合起来,向你展示如何使用后台线程和Bitmap缓存加载多个Bitmap(位图)到ViewPager和GridView组件中,并学习如何处理并发和配置变化问题。 实现加载Bitmap到ViewPager  

        滑动浏览模式(Swipe View Pattern)是一种很好的浏览详细图片的方式。你可以使用ViewPager组件配合PagerAdapter(适配器)来实现这种模式。然而,更加合适的适配器是FragmentStatePagerAdapter,它可以在ViewPager退出屏幕的时候自动销毁并存储Fragments的状态,使得内存依然保留下来。

        注意:如果你只有少量的图片,并且确信它们不会超出程序的内存限制,使用常规的PagerAdapter或者FragmentPagerAdapter或许更加合适。

        这里有一个包含ImageView的ViewPager的实现类,Main Activity(主活动)持有这个ViewPager和Adapter

public class ImageDetailActivity extends FragmentActivity {

02     public static final String EXTRA_IMAGE = "extra_image";
03  
04     private ImagePagerAdapter mAdapter;
05     private ViewPager mPager;
06  
07     // A static dataset to back the ViewPager adapter
08     public final static Integer[] imageResIds = new Integer[] {
09             R.drawable.sample_image_1, R.drawable.sample_image_2, R.drawable.sample_image_3,
10             R.drawable.sample_image_4, R.drawable.sample_image_5, R.drawable.sample_image_6,
11             R.drawable.sample_image_7, R.drawable.sample_image_8, R.drawable.sample_image_9};
12  
13     @Override
14     public void onCreate(Bundle savedInstanceState) {
15         super.onCreate(savedInstanceState);
16         setContentView(R.layout.image_detail_pager); // Contains just a ViewPager
17  
18         mAdapter = new ImagePagerAdapter(getSupportFragmentManager(), imageResIds.length);
19         mPager = (ViewPager) findViewById(R.id.pager);
20         mPager.setAdapter(mAdapter);
21     }
22  
23     public static class ImagePagerAdapter extends FragmentStatePagerAdapter {
24         private final int mSize;
25  
26         public ImagePagerAdapter(FragmentManager fm, int size) {
27             super(fm);
28             mSize = size;
29         }
30  
31         @Override
32         public int getCount() {
33             return mSize;
34         }
35  
36         @Override
37         public Fragment getItem(int position) {
38             return ImageDetailFragment.newInstance(position);
39         }
40     }
41 }

        这里有一个用来持有ImageView并显示详细信息的Fragment的实现类。看起来这似乎是非常合理的方法,但是你能否看到这个方案的缺点呢?应该如何改善它呢?

01 public class ImageDetailFragment extends Fragment {
02     private static final String IMAGE_DATA_EXTRA = "resId";
03     private int mImageNum;
04     private ImageView mImageView;
05  
06     static ImageDetailFragment newInstance(int imageNum) {
07         final ImageDetailFragment f = new ImageDetailFragment();
08         final Bundle args = new Bundle();
09         args.putInt(IMAGE_DATA_EXTRA, imageNum);
10         f.setArguments(args);
11         return f;
12     }
13  
14     // Empty constructor, required as per Fragment docs
15     public ImageDetailFragment() {}
16  
17     @Override
18     public void onCreate(Bundle savedInstanceState) {
19         super.onCreate(savedInstanceState);
20         mImageNum = getArguments() != null ? getArguments().getInt(IMAGE_DATA_EXTRA) : -1;
21     }
22  
23     @Override
24     public View onCreateView(LayoutInflater inflater, ViewGroup container,
25             Bundle savedInstanceState) {
26         // image_detail_fragment.xml contains just an ImageView
27         final View v = inflater.inflate(R.layout.image_detail_fragment, container, false);
28         mImageView = (ImageView) v.findViewById(R.id.imageView);
29         return v;
30     }
31  
32     @Override
33     public void onActivityCreated(Bundle savedInstanceState) {
34         super.onActivityCreated(savedInstanceState);
35         final int resId = ImageDetailActivity.imageResIds[mImageNum];
36         mImageView.setImageResource(resId); // Load image into ImageView
37     }
38 }

        希望你能注意到:这些图片是在UI线程从资源中读取过来的,而这极有可能导致应用挂起甚至被强制关闭。使用在“非UI线程处理Bitmap”一课中提到的AsyncTask,直接将图片加载和处理移到后台线程中。

        任何额外的处理(例如调整大小或者从网络获取图片)可以放在BitmapWorkerTask中而不会影响到主UI线程的响应性。如果后台线程做的不仅仅是直接从硬盘直接加载图片,那么如“缓存Bitmap”一课中说的,将图片缓存到内存或者硬盘是有利于程序优化的。这里是对内存缓存的一些额外修改:

01 public class ImageDetailActivity extends FragmentActivity {
02     ...
03     private LruCache<String, Bitmap> mMemoryCache;
04  
05     @Override
06     public void onCreate(Bundle savedInstanceState) {
07         ...
08         // initialize LruCache as per Use a Memory Cache section
09     }
10  
11     public void loadBitmap(int resId, ImageView imageView) {
12         final String imageKey = String.valueOf(resId);
13  
14         final Bitmap bitmap = mMemoryCache.get(imageKey);
15         if (bitmap != null) {
16             mImageView.setImageBitmap(bitmap);
17         } else {
18             mImageView.setImageResource(R.drawable.image_placeholder);
19             BitmapWorkerTask task = new BitmapWorkerTask(mImageView);
20             task.execute(resId);
21         }
22     }
23  
24     ... // include updated BitmapWorkerTask from Use a Memory Cache section
25 }

        将上面的代码片段整合在一起会让你的ViewPager具备优良的响应性能,可以实现最小的加载延迟,根据你的图片加载需要或多或少的进行后台处理。

实现加载Bitmap到GridView

        网格列表控件(Grid List Building Block)对于显示图片数据集非常有用,也可以使用GridView组件来实现,如果用户上下滚动的话,有很多图片处于就绪状态,随时可以显示在屏幕上。如果要实现这种类型的控制,你必须确保UI保持流畅性,内存使用处于控制之中而且并发也要被正确地处理(取决于GridView回收子视图的方式)。

        首先,这里有一个标准的GridView实现,将ImageView子控件存放在Fragment中。我们再一次思考这个问题,这个方法看起来似乎非常完美且合乎情理,但是有没有办法让它便得更好呢?

01 public class ImageGridFragment extends Fragment implements AdapterView.OnItemClickListener {
02     private ImageAdapter mAdapter;
03  
04     // A static dataset to back the GridView adapter
05     public final static Integer[] imageResIds = new Integer[] {
06             R.drawable.sample_image_1, R.drawable.sample_image_2, R.drawable.sample_image_3,
07             R.drawable.sample_image_4, R.drawable.sample_image_5, R.drawable.sample_image_6,
08             R.drawable.sample_image_7, R.drawable.sample_image_8, R.drawable.sample_image_9};
09  
10     // Empty constructor as per Fragment docs
11     public ImageGridFragment() {}
12  
13     @Override
14     public void onCreate(Bundle savedInstanceState) {
15         super.onCreate(savedInstanceState);
16         mAdapter = new ImageAdapter(getActivity());
17     }
18  
19     @Override
20     public View onCreateView(
21             LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
22         final View v = inflater.inflate(R.layout.image_grid_fragment, container, false);
23         final GridView mGridView = (GridView) v.findViewById(R.id.gridView);
24         mGridView.setAdapter(mAdapter);
25         mGridView.setOnItemClickListener(this);
26         return v;
27     }
28  
29     @Override
30     public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
31         final Intent i = new Intent(getActivity(), ImageDetailActivity.class);
32         i.putExtra(ImageDetailActivity.EXTRA_IMAGE, position);
33         startActivity(i);
34     }
35  
36     private class ImageAdapter extends BaseAdapter {
37         private final Context mContext;
38  
39         public ImageAdapter(Context context) {
40             super();
41             mContext = context;
42         }
43  
44         @Override
45         public int getCount() {
46             return imageResIds.length;
47         }
48  
49         @Override
50         public Object getItem(int position) {
51             return imageResIds[position];
52         }
53  
54         @Override
55         public long getItemId(int position) {
56             return position;
57         }
58  
59         @Override
60         public View getView(int position, View convertView, ViewGroup container) {
61             ImageView imageView;
62             if (convertView == null) { // if it's not recycled, initialize some attributes
63                 imageView = new ImageView(mContext);
64                 imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
65                 imageView.setLayoutParams(new GridView.LayoutParams(
66                         LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
67             } else {
68                 imageView = (ImageView) convertView;
69             }
70             imageView.setImageResource(imageResIds[position]); // Load image into ImageView
71             return imageView;
72         }
73     }
74 }

        当然,问题还是这个方法在UI线程中处理图片。这种方式或许是和处理小而简单的图片(系统资源的加载和缓存),如果需要做任何的处理,UI就会被阻塞(甚至引起ANR(Application Not Responding))。

        和前一节相同的处理方式,我们在异步线程中进行处理和缓存。然而,考虑到GridView回收子视图的方式,你需要谨慎处理并发问题。可以使用“在非UI线程中处理Bitmap”一课中提到的技巧。这里是更新的解决方案:

01 public class ImageGridFragment extends Fragment implements AdapterView.OnItemClickListener {
02     ...
03  
04     private class ImageAdapter extends BaseAdapter {
05         ...
06  
07         @Override
08         public View getView(int position, View convertView, ViewGroup container) {
09             ...
10             loadBitmap(imageResIds[position], imageView)
11             return imageView;
12         }
13     }
14  
15     public void loadBitmap(int resId, ImageView imageView) {
16         if (cancelPotentialWork(resId, imageView)) {
17             final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
18             final AsyncDrawable asyncDrawable =
19                     new AsyncDrawable(getResources(), mPlaceHolderBitmap, task);
20             imageView.setImageDrawable(asyncDrawable);
21             task.execute(resId);
22         }
23     }
24  
25     static class AsyncDrawable extends BitmapDrawable {
26         private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
27  
28         public AsyncDrawable(Resources res, Bitmap bitmap,
29                 BitmapWorkerTask bitmapWorkerTask) {
30             super(res, bitmap);
31             bitmapWorkerTaskReference =
32                 new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
33         }
34  
35         public BitmapWorkerTask getBitmapWorkerTask() {
36             return bitmapWorkerTaskReference.get();
37         }
38     }
39  
40     public static boolean cancelPotentialWork(int data, ImageView imageView) {
41         final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
42  
43         if (bitmapWorkerTask != null) {
44             final int bitmapData = bitmapWorkerTask.data;
45             if (bitmapData != data) {
46                 // Cancel previous task
47                 bitmapWorkerTask.cancel(true);
48             } else {
49                 // The same work is already in progress
50                 return false;
51             }
52         }
53         // No task associated with the ImageView, or an existing task was cancelled
54         return true;
55     }
56  
57     private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
58        if (imageView != null) {
59            final Drawable drawable = imageView.getDrawable();
60            if (drawable instanceof AsyncDrawable) {
61                final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
62                return asyncDrawable.getBitmapWorkerTask();
63            }
64         }
65         return null;
66     }
67  
68     ... // include updated BitmapWorkerTask class

        注意:相同的代码也可以很好的适配ListView。

        这里的实现方法允许灵活地处理和加载图片,并且不会影响UI的流畅性。在后台线程中,你可以从网络加载图片,调整大幅的数码相机照片的大小,并在处理任务结束的时候将图片显示在UI界面中。

转至:http://my.oschina.net/ryanhoo/blog/88484




相关推荐

【Ultrascale+ MPSOC学习记录】10、PS端以太网使用lwip

还是参考ALINX教程,学习PS端以太网如何使用,从教程中可以看到,开发板使用了一个xilinx默认不支持的phy JL2121,所以需要修改lwip的库源码。

ryo891012的博客 880

UNIAPP保存base64图片

制作APP分享二维码,后端生成base64图片,需要前端保存到相册,上代码 saveImgFile(base64) { //base64为base64图片值 const bitmap = new plus.nativeObj.Bitmap("test"); bitmap.loadBase64Data(base64, function() { const url = "_doc/" + new Date().getTime() + ".png"; // url为时间戳命名方式 console.

mr_lihuijie的博客 2078

Swift Package Manager (SPM) 创建并集成本地库

Swift Package Manager (SPM) 在macOS 项目中创建并集成的完整步骤

征战无悔人生 1423

uniapp获取图片后,base64位之间的转换

uniapp获取图片后,base64位之间的转换 uni.chooseImage之后会返回本地的base64位路径,提交上传服务端时,因为是本地路径的原因会读取不到。使用要进行特殊的转换,js代码如下。新建image-tools.js,放libs目录下。 // 将图片转成base64格式 function getLocalFilePath(path) { if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.inde

weixin_43374521的博客 5685

【麒麟系统】Rsync文件复制与同步工具

本文摘要: Rsync是一款Linux/Unix系统标配的高效文件同步工具,支持增量传输、SSH加密、断点续传等核心功能,相比SCP具有显著优势。文章详细解析了Rsync的五种标准语法格式和常用参数组合,重点介绍了本地同步、远程SSH同步(推送/拉取)的实操方法,并提供了密钥免密登录配置方案。针对企业运维场景,还讲解了文件过滤、镜像同步(--delete)、迁移同步(--remove-source-files)、空运行预校验(--dry-run)等高级功能,以及带宽限速等优化技巧,帮助用户安全高效地完成各类

信创运维工程师 · 银河麒麟 & 容器实战 | 金融生产环境迁移·等保加固 | 142篇原创·17万+阅读 998

2024年12月中国电子学会青少年软件编程(Python)等级考试试卷(五级)答案 + 解析

2024年12月中国电子学会青少年软件编程(Python)等级考试试卷(五级)答案 + 解析

伶俐角少儿编程 484

【Android Advanced Training - 09】高效地显示Bitmap图片 [ Lesson 3 - 两种缓存Bitmap的方式 ]...

Caching Bitmaps [缓存位图] 加载单个Bitmap到UI是简单直接的,但是如果你需要一次加载大量的图片,事情则会变得复杂起来。在大多数情况下(例如在ListView,GridVieworViewPager), 显示图片的数量通常是没有限制的。 通过循环利用子视图可以抑制内存的使用,GC(garbage collector)也会释放那些不再需要使用的bitmap。这...

mmdev 243

机器学习之多种算法优缺点总结及优化方法

一、无监督算法: 1、聚类算法:Kmeans 2、关联规则算法:Apriori 二、有监督算法 1、分类算法 决策树(Decision Tree) 支持向量机(SVM) K近邻(kNN,k-NearestNeighbor) 朴素贝叶斯 逻辑回归 2、回归算法 线性回归 多项式回归 3、集成算法 a、bagging(Bootstrapped Aggregation) 随机森林 ...

平原的博客 7081

uni-app bitmap.load() 返回code=-100

部分目录结构 project ├─static │ │ logo.png │ └─test │ test.vue 我的目的是在test.vue文件中使用plus.nativeObj.Bitmap的load函数加载logo.png 错误代码 let bitmap = new plus.nativeObj.Bitmap('test'); bitmap.load('../logo.png', ()=>{ console.log('图片加载成功') bi.

Novice-XiaoSong的博客 1213

人工智能面试总结-分类与聚类

目录说说常用的分类算法,以及各自的优缺点?说说为什么正确率有时不能有效评估分类算法?说说什么样的分类器最好?说说聚类算法有哪些衡量标准?(选看)各聚类算法性能比较汇总说说什么是聚类,你知道哪些聚类算法?具体展开介绍你知道的聚类算法?说说K-Means聚类算法流程?说说K-Means聚类算法如何调优?说说K-Means聚类算法如何选择初始点?说说K-Means聚类聚的是特征还是样本?说说K-Means聚类的特征距离是如何计算的?说说聚类与分类的区别?手撕K-Means聚类 说说常用的分类算法,以及各自的优缺点

啥都生的博客 3863

基于YOLOv11的手术器械计数系统:从数据集构建到Web应用部署

m2cai16-tool数据集:包含15种腹腔镜手术器械的标注图像Cholec80数据集:包含80个胆囊切除手术视频,标注了7种器械SurgicalTools数据集:包含超过10,000张手术器械图像,涵盖21类常见器械手术剪(Scissors)止血钳(Hemostat)持针器(Needle Holder)手术刀(Scalpel)镊子(Forceps)拉钩(Retractor)吸引器(Suction)

YOLO 396

在UI上显示Bitmap

实现加载图片到ViewPager Swipe View Pattern是一个使用滑动来切换显示不同详情页面的设计模型。(关于这种效果请先参看Android Design: Swipe Views)。我们可以通过PagerAdapter与ViewPager控件来实现这个效果。 不过,一个更加合适的Adapter是PagerAdapter的一个子类,叫做FragmentStatePagerAdapte...

qq_42795723的博客 289

飞牛NAS系统盘占用过高排查与解决全记录(已有效解决)

📢NAS弹出系统盘占用过高预警?别慌!亲测解决全流程来啦~ 精准定位根源+安全迁移数据,附详细实操步骤,帮同款困扰的你高效释空间、少走弯路!

XiaoqiangClub的博客 3121

android bitmap管理,Android在UI上显示Bitmap

这一课会演示如何运用前面几节课的内容,使用后台线程与缓存机制将图片加载到ViewPager与GridView控件,并且学习处理并发与配置改变问题。实现加载图片到ViewPagerSwipe View Pattern是一个使用滑动来切换显示不同详情页面的设计模型。(关于这种效果请先参看Android Design: Swipe Views)。我们可以通过PagerAdapter与ViewPager控...

weixin_28707365的博客 370

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

高效地显示Bitmap图片 2 - 在UI线程之外处理Bitmaps

Processing Bitmaps Off the UI Thread [在UI Thread之外处理Bitmap] 在上一课中有介绍一系列的BitmapFactory.decode* 方法,当数据源是网络或者是磁盘时(或者是任何实际源不在内存的),这些方法都不应该在main UI 线程中执行。那些情况下加载数据是不可以预知的,它依赖于许多因素(从网络或者硬盘读取数据的速度, 图片的大

Dream It Possible 1633

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

android 在你的UI中显示Bitmap - 开发文档翻译

由于本人英文能力实在有限,不足之初敬请谅解本博客只要没有注明“转”,那么均为原创,转贴请注明本博客链接链接Displaying Bitmaps in Your UI在你的UI中显示Bitmap This lesson brings together everything from previous lessons, showing you how to load multiple bitmaps

su1216的专栏 2071

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

高效显示Bitmap之UI线程外处理Bitmap

如果数据源从硬盘读取或者网络, BitmapFactory.decode*方法不应该在main线程中执行。加载这些数据的时间是不可预知的,受限于多种因素(硬盘读取速度,图片大小,CPU等等)。如果任一因素锁住了UI线程,系统会标记你的APP无响应,用户会有选择关闭其操作(see Designing for Responsiveness for more information)。 这节课教你

mzyl 633

android 在UI上显示Bitmap

编写:kesenhoo - 原文:http://developer.android.com/training/displaying-bitmaps/display-bitmap.html 这一课会演示如何运用前面几节课的内容,使用后台线程与缓存机制将图片加载到ViewPager与GridView控件,并且学习处理并发与配置改变问题。 实现加载图片到ViewPager Swipe View

chuyouyinghe的专栏 1015

Displaying Bitmaps in Your UI 在UI中显示Bitmap

这节课将我们前面几节课学习的东西都整合起来,向你展示如何使用后台线程和Bitmap缓存加载多个Bitmap(位图)到ViewPager和GridView组件中,并学习如何处理并发和配置变化问题。 实现加载Bitmap到ViewPager          滑动浏览模式(Swipe View Pattern)是一种很好的浏览详细图片的方式。你可以使用ViewPager组件配合PagerA

504

UI显示Bitmap整合前两章内容

转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-)  http://my.oschina.net/ryanhoo/blog/88484 译者:Ryan Hoo 来源:https://developer.android.com/develop/index.html 译者按: 在Google最新的文档中,提供了一系

dp543831577的专栏 600

【Google官方教程】第四课:在UI中显示Bitmap

在Google最新的文档中,提供了一系列含金量相当高的教程。因为种种原因而鲜为人知,真是可惜!Ryan将会细心整理,将之翻译成中文,希望对开发者有所帮助。         本系列是Google关于展示大Bitmap(位图)的官方演示,可以有效的解决内存限制,更加有效的加载并显示图片,同时避免让人头疼的OOM(Out Of Memory)。 -----------------

专注Android开发 801
上一篇: Android自适应不同分辨率或不同屏幕大小
下一篇: 缓存Bitmap
SpeedyCoder
博客等级 码龄14年 415粉丝 7原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值