码不停蹄(二):Android前端如何与后台通信、获取后台数据——OkHttp框架的使用

版权声明:本文所有内容均为博主原创手打,转载请注明出处,如有雷同,不甚荣幸。 https://blog.csdn.net/Xu_JL1997/article/details/82469401

2018
写在前面:本文讲述如何使用现成框架(OkHttp)来解决前后端通信问题。如果你是刚接触Android,请一定要耐心听我讲走过的坑。


1、我有App,服务器也有,可是要怎么让它们通信呢?

首先假设你不懂后台的原理,你只要知道前后端通信的基本工作就是向指定服务器请求数据、提交数据就没问题。
不论学没学过计算机网络,不太严谨地说,接入网络的终端(手机、主机等)都是通过网络层(IP层)的报文进行沟通,当然,往上向程序递交报文是传输层的事。具体可以参考百度百科-五层因特网协议栈的一些介绍,我们只要知道一些基本原理就好了。
所以,狭义的理解,前后端通信的媒介就是Http报文,类似于信封这种东西,Android要做的就是将信的内容(各种参数)写好,装到信封里(Http报文),发给后台,让后台进行数据库处理等。同理,后台将数据放到信里面,我也能通过拆信(解析)来获取数据了。
而我接下来介绍的OkHttp框架就能够提供方法来打包我们要提交或者请求的数据。

2、使用OkHttp怎样将参数写到Http报文里?

  • 首先还是导入依赖implementation 'com.squareup.okhttp3:okhttp:3.11.0' 在写博文的时候OkHttp还是3.11.0版本,最新版还是请到GitHub中查看OkHttp-GitHub地址
    此外还要在 AndroidManifest 文件中添加网络权限App才能联网:
    <uses-permission android:name="android.permission.INTERNET"/>

  • Http请求有POST、GET、DELETE、PUT等方式,在Android里我们一般只会使用到两种,POST、GET。前者可以在报文内部添加参数,提交数据到服务器,后者也允许携带参数,不过参数要跟在指定的URL后面,如Http://域名?参数1=x&参数2=x, 这种形式安全性低,所以GET一般只用来请求一些数据,如请求百度的首页。
    那么怎么选择使用哪一种方法?我的建议是,提交数据使用POST,请求数据是由GET,根据风格来选择方式而不是根据有没有参数来选择。

  • 使用OKHttp的同步GET方法:这里还是沿用《第一行代码》请求百度首页的栗子。

OkHttpClient client = new OkHttpClient();   //新建客户端处理请求
Request request = new Request.Builder()
    .url("http://www.baidu.com")    //添加要请求的URL
    .build();
try{
    response = client.newCall(request).execute();    //执行这个Http请求
    String result = response.body().string();    //获取Http响应报文的结果,注意string()大小写
}catch(Execption e){
    e.printStackTrace();    //注意可能有异常抛出
}

上面的栗子运行之后就会获取百度首页的HTML数据。很简单的同步请求数据栗子,当然我们还可以在URL后面添加一些参数给服务器处理。

  • OKHtttp的异步GET请求百度首页:
OkHttpClient client = new OkHttpClient();   
Request request = new Request.Builder()
    .url("http://www.baidu.com")    
    .build();
//前面还是一样的,但是下面就是重点了
Call call = client.newCall(request);
//添加到消息队列里,传入Callback,当响应报文回来时执行相应的回调方法
call.enqueue(new Callback{    
    @Override
    public void onFailure(Call call, IOException e){
        /*
         * 请求失败的一些操作
         */
    }
    @Override
    public void onResponse(Call call, Response response){
        try{
            String result = response.body().string();    //同样获取结果
        }catch(Exception e){
            e.printStackTrace();
        }
    }
});
  • OkHttp的POST方法:相比GET,同步、异步的变化是一样的,只需要多构建一个RequestBody,用来保存参数。
OkHttpClient client = new OkHttpClient();   
ReuquestBody body = FormBody.Builder()    //同样使用Builder模式构建
    .add("key","value")    //添加参数的键值对,可多次add()
    .addHeader()    //选择性添加一些首部行。比如添加Cookie实现登陆区分用户操作
    .build();
Request request = new Request.Builder()
    .url("xxx")
    .post(body)    //将body加进来,报文里就有这个部分了    
    .build();
/*
 * 接下来的操作和之前的Get相同
 */

3、(大坑)同步和异步操作的区别与使用技巧?

  • 也许看了上面的代码还有的朋友会疑惑,同步和异步怎么使用呢?这就引出一个机制,在Android的主线程(也叫UI线程)里不允许有耗时操作,因为这会有阻塞线程的风险。那岂不是不能执行同步Http请求?

确实,这就是一个小知识点,我们绝大多数请求都是在Activity里写的,比如我要查看某个人的资料,那么开启查看资料这个Activity的时候我就应该向服务器发出一个Http请求,有可能还会在URL后面附上?useId=xxx 这个参数,表示我要请求谁的资料。如果我们直接在onCreate()onStart(),onResume() 这些方法里添加上面的 同步请求 的代码,妥妥的崩溃。因为UI线程不能有耗时操作,同步Http请求就是其中之一,UI线程不可能等到响应报文回来再继续下面的操作。

  • 怎么解决,很简单,让Http请求是异步的不就好了, 只要不和UI线程同步不就解决这个问题了吗?

两种实现的解决方法:
(1)异步Http请求,就是后一块代码。因为异步请求实际和主活动不在同一个线程。
(2)为同步Http请求开启一个新线程。不懂 java 多线程的朋友也不用担心,开启很简单。代码如下:在[1]区域中替换为相应的同步Http请求即可。

//执行网络请求的方法,博主喜欢将网络请求放在一个方法,便于重用
public void networkTask(){
    //创建新线程
    new Thread(){
        //重写线程的run()方法
        @Override
        public void run(){
            /* 
             * [1]执行耗时操作,同步Http请求
             */
        }
    }.start();
}
  • 一些个人的使用技巧

看了同步Http的开启线程的操作,其实我们也明白了,在Anrdoid中,同步请求并不能真的和Activity同步,只是一个另类的异步罢了,只有和子线程的方法它才是同步的。所以这里给大家一些提示:
(1)使用异步请求书写更加方便,只要重写失败/成功的回调方法
(2)OkHttpClient是可以重用的。很多App会要求用户登陆后,App向服务器请求的任何服务都不再需要使用用户的重要信息(账号密码等)来区分是哪一个用户在操作。如果每次操作都需要Http报文附带用户账号密码,那未免太不安全。这时会用到Cookie/Session,相关的后台操作我会在后台专题的博文中提到。使用同一个client可以统一管理Cookie,比如OkHttp的CookieJar。

  • 如果需要使用Http请求的数据来更新UI,怎么通知UI线程,因为时延的关系,会不会数据刚请求过来,Activity的View都加载完毕了?

这种情况是随处可见的,毕竟很多数据请求过来还是要展示给用户的。
(1)怎么沟通子线程和UI线程?在响应报文回来的部分,如 String result = response.body().string(); 后面使用runOnUIThread(Runable runable)方法,如下:

/*
 * 同步/异步请求
 */
 final String result = response.body().string();    //注意添加final修饰符
 //假设当前Activity是MainActivity
 MainActivity.this.runOnUIThread(new Runable(){    //传入一个自定义的Runable,和Thread很类似,它也是线程的一个接口
     @Override
     public void run(){
         /*
          * 这里写的东西都会在UI线程执行
          */
          parseResult(result);    //假设MainActivity里有这么一个处理结果的方法
     }
 });

(2)至于怎么更新UI,很简单,既然数据回来了,当然是在数据处理完之后更新。千万不要以为将Http请求写在UI更新之前就一定能正确更新。往往这种方式都会出现空指针异常 ,所以View的更新一定要写在数据处理之后,特别是ListView等。

以上就是关于开发中OkHttp通信的一些基本应用和使用技巧,如有不正,欢迎交流指教。点击 主页 可以了解我的其他博文。

猜你喜欢

转载自blog.csdn.net/Xu_JL1997/article/details/82469401