Android网络要心路历程

1、Exception Type

1)EXC_BAD_ACCESS

此类型的Excpetion是我们最好丰富碰到的Crash,通常用于访问了不改变访问的内存导致。一般EXC_BAD_ACCESS后面的”()”还会见含有补充信息。

SIGSEGV:
通常由还释放对象造成,这种类型在切换了ARC以后当早就大少看到了。
SIGABRT:
收到Abort信号退出,通常Foundation库中之容器为了保障状态正常会开有检测,例如插入nil到数组中等会碰到此类错误。
SEGV:(Segmentation
Violation),代表无效内存地址,比如空指针,未初始化指针,栈溢出等;
SIGBUS:总线错误,与 SIGSEGV 不同之凡,SIGSEGV 访问的凡低效地址,而
SIGBUS 访问的是行得通地址,但总线访问非常(如地址指向一头问题)
SIGILL:尝试实行非法的一声令下,可能无深受辨认或没权力

2)EXC_BAD_INSTRUCTION

此类异常通常由线程执行非法命令导致

3)EXC_ARITHMETIC

除开零错误会抛出此类异常

网要是android客户端好关键之片。下面从入门级开始介绍下好Android网络要的推行进程。希望能吃刚接触Android网络有的对象有拉。
本文包含:

2、获取测试机的crash log

森测试人员在测试途中,或者开发者在自测的路上,会遇上APP crash的图景。

诚如的bug,一个合格的测试好给闹显著的重现步骤为开发者清晰地领悟bug原因;

也出好多bug,很多下是偶现的,很可能无法再重现出来,无法重现出来的bug是开发者头疼的,测试一般会被出bug的截图及复发步骤;

若是相似crash是比较严重的题目了(所以绝对不可知当什么还尚未发了,不然会受从之233),这个上崩溃日志就一发关键了,把崩溃日志send给开发人员,如此才能够让开发者快速稳定及左的缘故以及职位。

那么测试如何用到crash日志呢?

术一致:连接电脑,通过iTools高级选项来获取崩溃日志(Mac版的搜不顶高档选项T.T,望赐教补充)

iOS崩溃日志分析_itools.png

艺术二:连接电脑,去当地目录找

Mac : ~/Library/Logs/CrashReporter/MobileDevice/<DEVICE_NAME>

Windows : C://Users/<USERNAME>/AppDataRoamingApple/ComputerLogsCrashReporterMobileDevice/<DEVICE_NAME>/
夫时段你见面发觉一大堆的.crash文件和.ips文件

iOS崩溃日志分析_finder.png

方三:通过Xcode获取到倒日志,方法是Xcode->Window->Devices

iOS崩溃日志分析_devices(1).png


HttpClient & HttpURLConnection

HttpClient早被废了,谁又好这种题材吧只有经历落后的面试官才会咨询。具体原因可以拘留这里。

脚说说HttpURLConnection的用法。
极端开始接触的尽管是以此。

    public class NetUtils {
        public static String post(String url, String content) {
            HttpURLConnection conn = null;
            try {
                // 创建一个URL对象
                URL mURL = new URL(url);
                // 调用URL的openConnection()方法,获取HttpURLConnection对象
                conn = (HttpURLConnection) mURL.openConnection();

                conn.setRequestMethod("POST");// 设置请求方法为post
                conn.setReadTimeout(5000);// 设置读取超时为5秒
                conn.setConnectTimeout(10000);// 设置连接网络超时为10秒
                conn.setDoOutput(true);// 设置此方法,允许向服务器输出内容

                // post请求的参数
                String data = content;
                // 获得一个输出流,向服务器写数据,默认情况下,系统不允许向服务器输出内容
                OutputStream out = conn.getOutputStream();// 获得一个输出流,向服务器写数据
                out.write(data.getBytes());
                out.flush();
                out.close();

                int responseCode = conn.getResponseCode();// 调用此方法就不必再使用conn.connect()方法
                if (responseCode == 200) {

                    InputStream is = conn.getInputStream();
                    String response = getStringFromInputStream(is);
                    return response;
                } else {
                    throw new NetworkErrorException("response status is "+responseCode);
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (conn != null) {
                    conn.disconnect();// 关闭连接
                }
            }

            return null;
        }

        public static String get(String url) {
            HttpURLConnection conn = null;
            try {
                // 利用string url构建URL对象
                URL mURL = new URL(url);
                conn = (HttpURLConnection) mURL.openConnection();

                conn.setRequestMethod("GET");
                conn.setReadTimeout(5000);
                conn.setConnectTimeout(10000);

                int responseCode = conn.getResponseCode();
                if (responseCode == 200) {

                    InputStream is = conn.getInputStream();
                    String response = getStringFromInputStream(is);
                    return response;
                } else {
                    throw new NetworkErrorException("response status is "+responseCode);
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {

                if (conn != null) {
                    conn.disconnect();
                }
            }

            return null;
        }

        private static String getStringFromInputStream(InputStream is)
                throws IOException {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            // 模板代码 必须熟练
            byte[] buffer = new byte[1024];
            int len = -1;
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
            is.close();
            String state = os.toString();// 把流中的数据转换成字符串,采用的编码是utf-8(模拟器默认编码)
            os.close();
            return state;
        }
    }

在意网络权限!被坑了小次。

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

亚、Crash Log的符号化

取得到了.crash或者.ips文件之时段(憋纠结就半独公文发出啊两样,改下后缀名就ok),用文本编辑器打开文件是平积聚十六进制的内存地址,你会心烦的觉察压根看不知情。

log(脱敏后产生点丑).png

Q:十六进制内存地址可以更改化看得知道的啊?

A:当然,将这些十六进制地址转化成为道名称以及行数的经过称之为Symbolication(符号化)。符号化很粗略,只要您将你的.crash文件拉至地方提到了的Xcode的device
log里面,然后几乎秒钟后就是会符号化。但是这里有只前提,就是者起crash的本子包得是若协调之Xcode里面Archive出来的(这个是苹果自带的法门,会自动检测是否包含相当的.dSYM文件与应用二进制文件)。

Q:那如只要在新电脑上吗想符号化怎么处置?

答案是,只出互相配合的.dSYM文件和以二进制文件就可符号化。必需完全匹配才实施。否则,日志将无法给全符号化。

.dSYM文件位置在编的.xcarchive的包内容里

直达图是.dSYM文件的位置,应用的二进制文件就是起之包得.ipa后缀改成.zip,然后解压后中有个.app文件就是运之二进制文件。
将.dSYM文件与.app文件
和crash文件放一个索引下,然后再用deviceLog方法就好记化了。
除此以外还有另外符号化iOS
Crash文件的3种方法发生大牛已经做得非常好了,给个链接,这里虽未赘述了。
符号化以后是这样的~

灰色的都是app的讳

然看上去就翻番爽了\_

HTTP缓存机制

缓存对于移动端是那个主要之存在。

  • 减少请求次数,减多少服务器压力.
  • 本土数据读取速度再快,让页面不会见空白几百毫秒。
  • 以无网的情形下提供数据。

缓存一般由服务器控制(通过一些方式可本地控制缓存,比如为过滤器添加缓存控制信息)。通过当请头上加下面几乎只字端:

Request

请求头字段 意义
If-Modified-Since: Sun, 03 Jan 2016 03:47:16 GMT 缓存文件的最后修改时间。
If-None-Match: "3415g77s19tc3:0" 缓存文件的Etag(Hash)值
Cache-Control: no-cache 不使用缓存
Pragma: no-cache 不使用缓存

Response

响应头字段 意义
Cache-Control: public 响应被共有缓存,移动端无用
Cache-Control: private 响应被私有缓存,移动端无用
Cache-Control:no-cache 不缓存
Cache-Control:no-store 不缓存
Cache-Control: max-age=60 60秒之后缓存过期(相对时间)
Date: Sun, 03 Jan 2016 04:07:01 GMT 当前response发送的时间
Expires: Sun, 03 Jan 2016 07:07:01 GMT 缓存过期的时间(绝对时间)
Last-Modified: Sun, 03 Jan 2016 04:07:01 GMT 服务器端文件的最后修改时间
ETag: "3415g77s19tc3:0" 服务器端文件的Etag[Hash]值

正规使用时以要求或不过含其中有些字段。
客户端要根据这些消息存储这次请信息。
接下来于客户端发起呼吁的时节要反省缓存。遵循下面步骤:

浏览器缓存机制

在意服务器返回304意思是数码没有更改滚去念缓存信息。
已年轻的自家吧自己写的纱要框架添加到了缓存机制,还沾沾自喜,直到来平等天我看到了下面2只东西。(/TДT)/

一、crash log的获取

当你的app
在手机上crash的时光,会于大哥大及自动生成一个倾家荡产日志,也即是我们说之Crash
Log

CrashLog的岗位在:
iPhone设备的var/mobile/Library/Logs/CrashReporter

咱俩只要赢得之虽是设备受到的这个CrashLog

网络图片加载优化

对图片的传,就如上面的记名接口的avatar字段,并无会见一直拿图纸写在返回内容里,而是于一个图形的地址。需要常再次夺加载。

假若你直接用HttpURLConnection去取一摆设图纸,你办得到,不过没有优化就不过是个BUG不断demo。绝对免克规范使用。
瞩目网络图片有些特点:

  1. 她世代不见面变
    一个链接对应的图片一般永远不会见变换,所以当第一糟加载了图时,就该给予永久缓存,以后就是不再网要。

  2. 它非常占内存
    同样摆放图小的几十k多的几M高清无码。尺寸也是64*64交2k图。你莫能够饶这样一直显示到UI,甚至不可知一直放大上内存。

  3. 它如果加载很悠久
    加载一摆图纸需要几百ms到几乎m。这中间的UI占各项图功能为是必考虑的。

说说自家当上面提到的RequestVolley里举行的图片请处理(没错我举行了,这片之代码可以去github里看源码)。

总结

末段总结一些或许会见针对各位有用之博文:
1、iOS应用崩溃日志分析(这最终有一个板栗很有趣)
2、获取 iOS crash
log(分析得很详细)
3、WWDC视频(2010年的WWDC视频)
4、官网文档——Analyzing iOS Application Crash
Reports

极端末尾得PS下:笔者为此之是Xcode7.1+iOS9.1

Get&Post

网络请求遭遇我们经常因此键值对来导参数(少部分api用json来传递,毕竟非是主流)。
通过地方的牵线,可以看到虽然Post与Get本意一个凡是表单提交一个凡是请页面,但实质并不曾啊分别。下面说说参数在当时2者的职位。

  • Get方式
    在url中填入参数:

      http://xxxx.xx.com/xx.php?params1=value1&params2=value2
    

居然使路由

    http://xxxx.xx.com/xxx/value1/value2/value3

这些虽是web服务器框架的行了。

  • Post方式
    参数是由此编码在请求体中之。编码包括x-www-form-urlencoded
    form-data
    x-www-form-urlencoded的编码方式是这样:
    tel=13637829200&password=123456
    form-data的编码方式是这么:
    —-WebKitFormBoundary7MA4YWxkTrZu0gW
    Content-Disposition: form-data; name=”tel”

      13637829200
      ----WebKitFormBoundary7MA4YWxkTrZu0gW
      Content-Disposition: form-data; name="password"
    
      123456
      ----WebKitFormBoundary7MA4YWxkTrZu0gW
    

x-www-form-urlencoded的优越性就特别明白了。不过x-www-form-urlencoded唯其如此传键值对,但是form-data足传二进制

坐url是存在吃要求行中之。
就此Get与Post区别本质就是是参数是坐落请求行受要么在请求体
本无论用啊种都能够在请求头中。一般在求求头中放大有发送端的常量。

有人说:

  • Get是明文,Post隐藏
    移动端不是浏览器,不用https全都是公然。
  • Get传递数据上限XXX
    胡说。有限制的凡浏览器被的url长度,不是Http协议,移动端请求无影响。Http服务器部分来限定的设置一下即可。
  • Get中文需要编码
    是真的…要注意。URLEncoder.encode(params, "gbk");

要建议就此post规范参数传递方式。并没什么更优秀,只是大家还如此社会更和谐。

面说之凡央。下面说响应。
央是键值对,但返回数据我们经常因此Json。
对于内存中的构造数据,肯定使为此多少描述语言将对象序列化成文本,再就此Http传递,接收端并于文本还原成结构数据。
对象(服务器)<–>文本(Http传输)<–>对象(移动端) 。

服务器返回的多少大部分且是繁体的组织数据,所以Json最可。
Json解析库有好多Google的Gson,阿里的FastJson。
Gson的用法看这里。

1、获取用户的 crash log

留意。这里的用户因的凡你的app已经上架到AppStore上后的用户。

用作开发者,你想只要获得到你的用户的垮台日志的言语就得经过 iTunes Connect
了。在 iTunes Connect 上的
Manage Your Applications -> View Details -> Crash Reports

这种措施发出个前提,就是用户设备同意上传相关信息,打开了诊断及用量是选项设置->隐私->诊断与用量
(由于作者还无有app上架,所以这个措施笔者非就此过,so 就此打住。
希望发因此了之大牛来拍砖或者上,Thx)

三级缓存

网上时不时说三级缓存--服务器,文件,内存。不过自己看服务器无算是一级缓存,那即便是多少源嘛。

  • 外存缓存
    先是内存缓存使用LruCache。LRU是Least Recently Used
    近期起码使用算法,这里确定一个高低,当Map里对象大小总和超此可怜时将祭效率低于的靶子释放。我以内存大小限制为经过可用内存的1/8.
    外存缓存里读博的数目就直回到,读不至之通向硬盘缓存要数。

  • 硬盘缓存
    硬盘缓存使用DiskLruCache。这个类似不以API中。得复制利用。
    瞧见LRU就知了吧。我用硬盘缓存大小设置为100M。

      @Override
      public void putBitmap(String url, Bitmap bitmap) {
          put(url, bitmap);
          //向内存Lru缓存存放数据时,主动放进硬盘缓存里
          try {
              Editor editor = mDiskLruCache.edit(hashKeyForDisk(url));
              bitmap.compress(Bitmap.CompressFormat.JPEG, 100, editor.newOutputStream(0));
              editor.commit();
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
    
      //当内存Lru缓存中没有所需数据时,调用创造。
      @Override
      protected Bitmap create(String url) {
          //获取key
          String key = hashKeyForDisk(url);
          //从硬盘读取数据
          Bitmap bitmap = null;
          try {
              DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);
              if(snapShot!=null){
                  bitmap = BitmapFactory.decodeStream(snapShot.getInputStream(0));
              }
          } catch (IOException e) {
              e.printStackTrace();
          }
          return bitmap;
      }
    

DiskLruCache的规律不再说了(我还缓解了她有的一个BUG,向Log中加上的数据增删记录时,最后一漫长没有出口,导致最终一漫漫缓存一直失效。)

  • 硬盘缓存也从未数据就回空,然后便往服务器请求数据。

随即就是漫天流程。
而自如此的处理方案要生好多受制。

  • 图形未经压缩处理直接存储使用
  • 文件操作以主线程
  • 没完善之图处理API

原先也当这么就够好直到自己遇上下面俩。

三、Crash Log的分析

属下就深受咱们本着已符号化以后的crash文件进行辨析。
网上一度有的分类比较多,我这里直接将自己当下相似找crash原因之模块展示下,其他的即留待各位好去研究了,分别是设备和crash信息、异常信息、线程信息
1、首先是设备及crash信息

Incident Identifier: F3573A...E2F244A              //crash的id
CrashReporter Key:   cc2298...es77eeb              //crash的设备id
Hardware Model:      iPhone7,2                     //手机型号
Process:             [AppName] [1816]              //APP的名字[进程的id]
Path:                /private/.../Application...   //APP的位置
Identifier:          com....                       //bundle ID
Version:             14 (2.3.5)                    //版本号
Code Type:           ARM-64 (Native)               //app的应用架构之类不大清楚,^_^
Parent Process:      launchd [1]

Date/Time:           2015-10-26 15:03:29.29 +0800    //crash发生时间
Launch Time:         2015-10-26 14:58:28.28 +0800    //进入应用时间
OS Version:          iOS 9.1 (13B143)                //iOS版本
Report Version:      105

当您有恢宏底crash文件的时,你便足以对crash文件里面的 Hardware
Model,Version , OS
Version等展开归类,就好取得知到无数音,比如说,你见面了解crash一般生原因是因手机型号,还是App版本,或者还是手机版的原故。(笔者暂时尚未接触了大量之crash文件,所以只是能够纸上谈兵了\_

2、其次是充分信息

Exception Type:  EXC_BAD_ACCESS (SIGABRT)                      //异常的类型
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000118  //异常子类型
Triggered by Thread:  0                    //异常发生的线程(0为主线程,其他为子线程)

3、线程信息

Last Exception Backtrace:
0   CoreFoundation                  0x182780f48 __exceptionPreprocess + 124
1   libobjc.A.dylib                 0x197333f80 objc_exception_throw + 56
2   CoreFoundation                  0x182780e90 +[NSException raise:format:] + 120
3   [AppName]                           0x100c42a40 UmengSignalHandler + 144
4   libsystem_platform.dylib        0x197d6193c _sigtramp + 52
5   [AppName]                           0x1005d9f38 CScopePtr<IAVGAudioLogic>::operator IAVGAudioLogic*<IAVGAudioLogic>() (xprefc.h:165)
6   [AppName]                           0x1005d3b8c tencent::av::AVRoomMultiImpl::GetAudioLogic() (av_room_multi_impl.h:119)
7   [AppName]                           0x10057076c tencent::av::AVAudioCtrlImpl::SetAudioOutputMode(int) (av_audio_ctrl_impl.cpp:443)
8   [AppName]                           0x10044dc3c -[AVBasicManager changeSpeakerMode:] (AVManager.mm:525)
9   [AppName]                           0x100296e1c -[KTQAVRoom enableSpeakerMode:] (KTQAVRoom.m:345)
10  [AppName]                           0x1002970d0 -[KTQAVRoom settingSpeaker:] (KTQAVRoom.m:362)
11  [AppName]                           0x1003d5464 -[KTChatView onAudioNotificationReceived:] (KTChatView.m:685)

好处。。。这符号化以后应该可以看懂了吧,这个crash的题目应有是腾讯第三在的一个冲吧233

诚如的话,通过非常信息和线程信息就好找到crash的因了。

图片管理方案

再说说图片存储。不要在好服务器上面,徒增流量压力,还并未图处理功能。
推荐七牛与阿里云存储(没因此了任何
π__π
)。它们都起良要紧的平起图片处理。在图Url上加上参数来对图纸进行部分甩卖又传。
于是乎(七牛之拍卖代码)

    public static String getSmallImage(String image){
        if (image==null)return null;
        if (isQiniuAddress(image)) image+="?imageView2/0/w/"+IMAGE_SIZE_SMALL;
        return image;
    }

    public static String getLargeImage(String image){
        if (image==null)return null;
        if (isQiniuAddress(image)) image+="?imageView2/0/w/"+IMAGE_SIZE_LARGE;
        return image;
    }

    public static String getSizeImage(String image,int width){
        if (image==null)return null;
        if (isQiniuAddress(image)) image+="?imageView2/0/w/"+width;
        return image;
    }

既然如此好加速请求速度,又会抽流量。再配合Fresco或Glide。完美的图纸加载方案。
只是这虽需而拿富有图片都存放于七牛要阿里云,这样呢是。

图表/文件上传也都是动它第三着存储,它们都发出SDK与法定文档教你。
但图片一定要减小了后上传。上传1-2M大的高清照片未曾意义。

2、Exception Code

0xbaaaaaad 此种档次的log意味着该Crash
log并非一个的确的Crash,它仅仅只是包含了整整体系有平等时时的运作状态。通常可以经并且以Home键和音量键,可能出于用户不小心点
0xbad22222 当VOIP程序在后台太过频繁之激活时,系统可能会见停此类程序
0x8badf00d 程序启动或恢复时间过长受watch dog终止
0xc00010ff
程序执行大量消耗CPU和GPU的演算,导致设备了热,触发系统了烫保护于系统已
0xdead10cc 先后退到后台时还占据系统资源,如通讯录被网已
0xdeadfa11 前面为波及了,程序无响应用户强制关闭

Volley&OkHttp

Volley&OkHttp应该是今天最常用之纱要求库。用法也殊相像。都是为此构造请求参加请求队列的点子管理网络请求。

先说Volley:
Volley可以由此这个库进行依赖.
Volley在Android 2.3跟以上版本,使用的凡HttpURLConnection,而在Android
2.2暨以下版本,使用的是HttpClient。
Volley的核心用法,网上资料无数,这里推荐郭霖大神的博客
Volley存在一个缓存线程,一个网络请求线程池(默认4独线程)。
Volley这样直接用支付效率会比较低,我用我动用Volley时的各种技术封装成了一个库房RequestVolly.
自家于这个库房中将构造请求的章程封装为了函数式调用。维持一个大局的呼吁队列,拓展一些便宜的API。

然而更怎么封装Volley在力量拓展性上始终无法与OkHttp相比。
Volley停止了翻新,而OkHttp得到了官的认同,并当时时刻刻优化。
故而自最终替换为OkHttp

OkHttp用法见这里
挺和气之API与详尽的文档。
即篇稿子也勾勒的那个详细了。
OkHttp使用Okio进展数量传。都是Square家的。
而并无是直用OkHttp。Square公司还起了一个Retrofit库配合OkHttp战斗力翻倍。

补偿部分百般类型信息

此间参考了重重信,有成百上千之生类型,有些尚未遇到了,这里就是厚颜摘抄过来了(这里是原文地址:iOS
Crash文件的分析,再次感谢大牛们的更)

HTTP请求&响应

既说于入门级开始就说说Http请求包的布局。
无异于不好呼吁虽是向阳目标服务器发送一错文本。什么样的文本?有下结构的公文。
HTTP请求保管结构

请求包

例子:

    POST /meme.php/home/user/login HTTP/1.1
    Host: 114.215.86.90
    Cache-Control: no-cache
    Postman-Token: bd243d6b-da03-902f-0a2c-8e9377f6f6ed
    Content-Type: application/x-www-form-urlencoded

    tel=13637829200&password=123456

恳请了不畏会收取响应包(如果对面存在HTTP服务器)
HTTP响应包结构

响应包

例子:

    HTTP/1.1 200 OK
    Date: Sat, 02 Jan 2016 13:20:55 GMT
    Server: Apache/2.4.6 (CentOS) PHP/5.6.14
    X-Powered-By: PHP/5.6.14
    Content-Length: 78
    Keep-Alive: timeout=5, max=100
    Connection: Keep-Alive
    Content-Type: application/json; charset=utf-8

    {"status":202,"info":"\u6b64\u7528\u6237\u4e0d\u5b58\u5728\uff01","data":null}

Http请求方式来

方法 描述
GET 请求指定url的数据,请求体为空(例如打开网页)。
POST 请求指定url的数据,同时传递参数(在请求体中)。
HEAD 类似于get请求,只不过返回的响应体为空,用于获取响应头。
PUT 从客户端向服务器传送的数据取代指定的文档的内容。
DELETE 请求服务器删除指定的页面。
CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
OPTIONS 允许客户端查看服务器的性能。
TRACE 回显服务器收到的请求,主要用于测试或诊断。

常用只有Post与Get。

  • HTTP请求&响应
  • Get&Post
  • [HttpClient & HttpURLConnection](#HttpClient & HttpURLConnection)
  • 同步&异步
  • HTTP缓存机制
  • Volley&OkHttp
  • Retrofit&RestAPI
  • 网图片加载优化
  • Fresco&Glide
  • 图片管理方案

Retrofit&RestAPI

Retrofit庞的简化了网络要的操作,它应该说只有是一个Rest
API管理库,它是直接用OKHttp进行网络要并无影响您对OkHttp进行安排。毕竟都是Square公司出品。
RestAPI是千篇一律种软件设计风格。
服务器作为资源存放地。客户端去告GET,PUT,
POST,DELETE资源。并且是不管状态的,没有session的插手。
运动端与服务器交互最要害的就是是API的宏图。比如就是一个专业的记名接口。

Paste_Image.png

你们应当看的生这接口对应的请保管以及应包约是呀样子吧。
吁方式,请求参数,响应数据,都好鲜明。
使用Retrofit这些API可以直观的反映于代码中。

Paste_Image.png

下一场下Retrofit提供于你的之接口的兑现类
就会直接进行网络要获得结构数据。

只顾Retrofit2.0互相较1.9进展了大量免配合更新。google上大部分课程都是因1.9底。这里有个2.0的教程。

学科里开展异步请求是使Call。Retrofit最劲的地方在于支持RxJava。就像自家及图被归的凡一个Observable。RxJava上亲手难度比较大,但据此过就算更为离不开了。Retrofit+OkHttp+RxJava配合框架打有成吨的出口,这里不再多说。

网络要学习及此地我当既到到了。。

Fresco&Glide

非用想呢晓得它都召开了酷健全的优化,重复过去轮子的表现十分笨。
Fresco凡是Facebook公司之不法科技。光看效果介绍就看到非常有力。使用方式官方博客说的足够详细了。
的确三级缓存,变换后的BItmap(内存),变换前之原有图片(内存),硬盘缓存。
以内存管理及到位了极致。对于重度图片以的APP应该是挺好的。
它一般是直接使用SimpleDraweeView来替换ImageView,呃~侵入性较强,依赖上它们apk包直接杀1M。代码量惊人。

从而自己再也爱好Glide,作者是bumptech。这个库房被普遍的以在google的开源项目面临,包括2014年google
I/O大会上宣告之官方app。
这里产生详尽介绍。直接利用ImageView即可,无需初始化,极简的API,丰富的展开,链式调用都是本身爱的。
累加的拓指的就算是这个。
另外自呢就此过Picasso。API与Glide简直一型一样,功能略少,且发生一半年无修复的BUG。

同步&异步

即2独概念就是被多线程编程中。
android中默认只发生一个主线程,也给UI线程。因为View绘制只能于此线程内开展。
故此如果你死了(某些操作而这线程在此地运行了N秒)这个线程,这中间View绘制将未能够拓展,UI就会见卡。所以一旦奋力避免以UI线程进行耗时操作。
网要是一个突出耗时操作。
经者的Utils类进行网络要单出一行代码。

NetUtils.get("http://www.baidu.com");//这行代码将执行几百毫秒。

如若您如此描写

        @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        String response = Utils.get("http://www.baidu.com");
    }

就会死。。
立刻就是是一同方式。直接耗时操作阻塞线程直到数据接收了毕然后回到。Android不同意的。
异步方式:

         //在主线程new的Handler,就会在主线程进行后续处理。
    private Handler handler = new Handler();
    private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.text);
        new Thread(new Runnable() {
            @Override
            public void run() {
                    //从网络获取数据
                final String response = NetUtils.get("http://www.baidu.com");
                    //向Handler发送处理操作
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                            //在UI线程更新UI
                        textView.setText(response);
                    }
                });
            }
        }).start();
    }

于子线程进行耗时操作,完成后透过Handler将更新UI的操作发送到主线程执行。这就是受异步。Handler是一个Android线程模型中着重之事物,与网络无关便不说了。关于Handler不了解就先行去Google一下。
至于Handler原理同首对的篇章

可诸如此类描写好难看。异步通常伴随者他的好基友回调
立即是经回调封装的Utils类。

    public class AsynNetUtils {
        public interface Callback{
            void onResponse(String response);
        }

        public static void get(final String url, final Callback callback){
            final Handler handler = new Handler();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    final String response = NetUtils.get(url);
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            callback.onResponse(response);
                        }
                    });
                }
            }).start();
        }

        public static void post(final String url, final String content, final Callback callback){
            final Handler handler = new Handler();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    final String response = NetUtils.post(url,content);
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            callback.onResponse(response);
                        }
                    });
                }
            }).start();
        }
    }

接下来使办法。

    private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.webview);
        AsynNetUtils.get("http://www.baidu.com", new AsynNetUtils.Callback() {
            @Override
            public void onResponse(String response) {
                textView.setText(response);
            }
        });

举凡无是雅很多。
嗯,一个傻到哭的纱要方案成型了。
不灵的地方时有发生为数不少:

  • 历次都new Thread,new Handler消耗了好
  • 莫那个处理体制
  • 不曾缓存机制
  • 从不两全之API(请求头,参数,编码,拦截器等)与调试模式
  • 没有Https