Android控件之ImageView(二)

前言

在上一篇文章中,我们讲解了如何加载本地图片,那么在实际项目中 ImageView 大多数使用场景是加载网络图片,网络图片其实就是存储在服务器上的文件,我们需要从服务器获取到文件的二进制输入流 Inpustream ,然后将其转化为 ImageView 可以加载的 Bitmap 对象。实现网络图片的加载。

这篇文章我们通过使用原始的网络连接和使用第三库来简单讲解 ImageView 网络图片的加载。

  • 怎么使用原始方式加载网络图片?
  • 第三方网络图片加载库与原始加载库的对比?
  • 怎样使用第三方网络加载库加载图片?

使用原始方式加载网络图片

先上代码(主要分为三大步骤):

  • 1~6 : 从网络获取图片。由于Android 系统规定网络请求操作需要在子线程完成。主要是因为网络请求属于耗时操作,如果在主线程发起网络请求会导致主线程在网络请求期间,无法及时响应用户的操作,
  • 7:利用在 Activity声明的 Handler对象把在子线从网络获取到的 Bitmap 对象,转移到 UI 线程。
  • 8 : 更新UI
public class ImageNetActivity extends AppCompatActivity {

    /**
     * 7.要知道 这里现在是子线程 更新UI的操作需要在主线程(UI线程)完成。
     * 在 Activity 中声明 Handler 对象,并复写它的 handleMessage 方法
     */
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == 1010) {
                Bitmap bitmap = (Bitmap) msg.obj;
                setImageView(bitmap);
            }
        }
    };

    private ImageView mImageView;

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

        mImageView = findViewById(R.id.image);


        loadImageUrl("https://cdn.pixabay.com/photo/2017/05/09/23/02/dog-2299482_960_720.jpg");
    }

   

    private void loadImageUrl(final String imageUrl) {
        // Android 系统强制网络请求需要在子线程操作
        new Thread(new Runnable() {

            @Override
            public void run() {
                InputStream inputStream = null;
                try {
                    // 1. 把传过来的路径转成URL
                    URL url = new URL(imageUrl);
                    // 2.通过URL 建立网络连接
                    // --> url.openConnection() 返回 URLConnection
                    // ,它是一个抽象类,这里需要通过Http协议建立连接,需要它的实现类 HttpURLConnection
                    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                    // 3. 使用GET方法访问网络
                    urlConnection.setRequestMethod("GET");
                    // 配置网络超时时间为 10秒
                    urlConnection.setConnectTimeout(10000);

                    //4. 获取Http协议 响应码
                    int responseCode = urlConnection.getResponseCode();
                    // Http 协议 规定 响应码为200时 请求成功
                    if (responseCode == 200) {
                        // 5. 得知 请求资源成功后,获取图片文件输入流
                        inputStream = urlConnection.getInputStream();

                        // 6. 把获取到的 文件输入流 通过 系统Api 转换为 ImageView 可以识别的 Bitmap 对象

                        Bitmap bitmap = BitmapFactory.decodeStream(inputStream);

                        // 7.要知道 这里现在是子线程 更新UI的操作需要再主线程(UI线程)完成。
                        Message message = mHandler.obtainMessage();
                        message.obj = bitmap;
                        message.what = 1010;//
                        mHandler.sendMessage(message);
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (inputStream != null) {
                        try {
                            //关闭流
                            inputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();


    }
}
/**
* 8.利用从 Mesage 从子线程中携带回来的 Bitmap 对象,在UI线程设置图片
*/
 private void setImageView(Bitmap bitmap) {
        mImageView.setImageBitmap(bitmap);
 }
}

上面是创建一个空的 Activity ,布局文件中只有一个 ImageView 控件。
注意:在 Android中 主线程 也叫 UI线程。UI 线程是响应用户操作的线程,一旦在 UI线程中存在好在操作,就会阻塞 UI 线程,导致无法及时响应用户操作事件。所以在Android 系统 4.0 后,强制网络请求操作必须在子线程。但问题是:所有更新 UI 的操作又必须在UI线程,这就是我们必须把网络请求的结果,转移到主线程才能更新 UI。怎么转移呢? 那就是 Handler。这个现在知道怎么用就行,后面我们会仔细讲解。

上面的代码中,利用系统自带 ULRConnection请求网络请求的步骤注释已经很详细了。可仔细了解其网络请求步骤,大致的套路是一样的。

<font face="黑体" size="4" color="#ff0000">特别特别特别注意:网络请求是需要权限的,你需要在 AndroidManifet.xml 文件中声明一句用户权限。至于权限的概念后面我们会细聊。现在只需要在AndroidManifet.xml文件申明即可。</font>

<uses-permission android:name="android.permission.INTERNET"/>

第三方网络图片加载库与原始加载库的对比

我们来思考几个问题,如果在真实项目中,我们这样加载图片你觉得可以吗?

........

答案是:不可以。

  • 问题1:上面就只单一使用了内存缓存来解决图片加载问题,Android 系统为每个应用分配的内存是有限的,假如说我们的图片成千上万,即使现在的 Android 手机硬件都配置很高,也顶不住这样的操作,当内存不足时应用马上会崩溃(Crash)。
  • 问题2:内存缓存,易失去性。即当你重新启动应用程序后,原来已经加载过的图片就会丢失,重启后又会重新下载!这就会导致页面加载缓慢,再次耗费用户流量。

所以我们需要一个比较完善的图片加载系统,这个系统最基础的要包括图片的缓存策略:先从网络请求图片,在手机内存中和SD卡中各自保存一份图片资源。当重启应用时,如果图片存在SD卡中,就可以从SD卡中直接获取图片加载。并且SD卡所能存储的图片总数是一定的,会不断的根据策略去舍去图片的存留。

还有非常重要的一点:从图片加载库的使用者角度讲,使用者无需关心内部到底是使用内存缓存,还是SD卡缓存,或是直接从网络获取的。这对于使用者来讲,内部的一切用户并不需要知道。使用者只需要知道加载图片的接口

对于图片加载框架,内部实现是极其复杂的,目前我们并不需要了解其内部实现方式。

下面我们就使用最常用的图片加载框架 Glide来完成我们图片加载框架使用的演示。

怎样使用第三方网络加载库加载图片(Glide)

我们要知道,因为Android是开源的,所以会产生各种各样的第三方框架,而我们不能盲目的去使用,要根据实际情况,从这之中挑选出最优的、最适合自己项目的框架,合理有效的去使用各种资源。而我们推荐的Glide是经过不断的和其他框架对比所挑选出来性价比最高的!

目前国内主流的第三方网络图片加载库有Glide(主推)、ImageLoaderPicassoVolleyFresco等,感兴趣的小伙伴可以去搜索一下这些加载库的全方面对比,百度一哈比比皆是,我们就不再这里将网上的一些大神所对比的实际内容再复述一遍啦。下面请跟我走4步,完成你人生中第一次加载网络图片吧!!!

  1. 首先我们要通过依赖 Glide 图片加载库。

    Glide github 官方地址

  2. 在官方文档中我们找到需要依赖的 Glide库地址。

 implementation 'com.github.bumptech.glide:glide:4.9.0'
  1. 将依赖地址放置到 app 模块下的 build.gradle 中如图:
image

添加完成后,我们点击 右上角的 Sync Now ,从网络下载依赖库到本地,并依赖到 app 模块。

  1. 我们在创建的空 Activity 当中,为 ImageView控件利用 Glide加载图片。
image

okay,搞定!!使用第三图片加载库是不是很简单。

其实里面的大致操作就是我们在第一个问题中书写的代码,里面多的就是各种缓存策略和逻辑处理。

结语

关于网络图片的加载我们今天就讲到这里,请原谅小编没有对Glide的源码做详解,因为内容过于复杂,涉及到很多初学者无法理解的知识,咱们目前只需要会使用,慢慢的跟着我们一起学习,后续这些都会融会贯通的~ 如果有小伙伴对Glide的源码感兴趣可以加入我们的微信群一起探讨~ 在公众号中回复微信群,就可以加入其中,也可以在公众号中回复视频,里面有一些初学者视频哦~

PS:如果还有未看懂的小伙伴,欢迎加入我们的QQ技术交流群:892271582,里面有各种大神回答小伙伴们遇到的问题,我们的微信群马上也将要和大家见面啦,届时希望大家踊跃加入其中~~

image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 224,535评论 6 522
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,106评论 3 402
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 171,668评论 0 366
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 60,863评论 1 300
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 69,874评论 6 399
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,362评论 1 314
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,748评论 3 428
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,717评论 0 279
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,249评论 1 324
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,280评论 3 345
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,408评论 1 354
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,020评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,727评论 3 337
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,191评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,320评论 1 275
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,946评论 3 381
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,473评论 2 365

推荐阅读更多精彩内容

  • 7.1 压缩图片 一、基础知识 1、图片的格式 jpg:最常见的图片格式。色彩还原度比较好,可以支持适当压缩后保持...
    AndroidMaster阅读 2,524评论 0 13
  • 一、简介 在泰国举行的谷歌开发者论坛上,谷歌为我们介绍了一个名叫Glide的图片加载库,作者是bumptech。这...
    天天大保建阅读 7,500评论 2 28
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,119评论 1 32
  • 近来,简书最热门的事情就是简书钻。 我是一书呆子,只知道写文更文,对于政策的领会总是迷迷糊糊。 打开自己的简书,发...
    南歌吟阅读 1,207评论 20 24
  • 我是一个大大咧咧的女孩,从小就不喜欢做家务,家里面也不整理,但内心却想成为一个很精致的女孩。 我一直想过这样一种生...
    不是文艺的小女孩阅读 212评论 0 0