OkHttp3全面解析&注解工具butterknife

前言:Okhttp3是一个强大的网络请求下载开源框架,本文将会对OkHttp3进行全面解析以及在代码中穿插butterknife的使用。

我将对OkHttp3进行下面六种用途的讲解:

  • GET请求
  • POST请求(Form表单形式)
  • POST请求(JSON格式)
  • 文件下载(简单方式)
  • 文件下载(拦截器方式)
  • OkHttp3的简单封装

    1.GET请求

  • 对于网络加载库,那么最常见的肯定就是http get请求了,比如获取一个网页的内容。

        //我们想像为生成一个客户端
        OkHttpClient client = new OkHttpClient();

        String url = "http://192.168.1.189:5000/user/info?id=1";

        Request request = new Request.Builder()
                        .url(url)
                        .build();
        //请求加入调度
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

                Log.d("MainActivity","失败------"+e.getLocalizedMessage());

            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {


                String result = response.body().string();

                Log.d("MainActivity","成功:"+result);

                if(response.body() !=null){
                    response.body().close();
                }


            }
        });

我们得注意几点:

  • 上传下载功能必须得用异步的方式进行,所以调用call.enqueue,将call加入调度队列,然后等待任务执行完成,我们在Callback中即可得到结果。
  • onResponse回调的参数是response,我们希望获得返回的字符串,可以通过response.body().string()获取;这里我们要注意,把流形式转化为字符串用.string(),把Object形式的对象转化为字符串用.toString().
  • 以流形式操作我们就可以通过IO的方式写文件。不过也说明一个问题,这个onResponse执行的线程并不是UI线程。的确是的,如果你希望操作控件,还是需要使用handler等。
@Override
public void onResponse(final Response response) throws IOException
{
      final String res = response.body().string();
      runOnUiThread(new Runnable()
      {
          @Override
          public void run()
          {
            mTv.setText(res);
          }

      });
}

在平时的学习中,我以及碰到好几次开源框架,如Fresco,OkHttp的代码用如下形式:

  Request request = new Request.Builder()
                        .url(url)
                        .build();

我们对Request的源码进行分析,看看内部如何设计:

public final class Request {


//静态内部类,所以可以用类访问,以及类直接调用构造器:new Request.Builder()来得到一个builder对象。
 public static class Builder{


//方法返回一个Builder对象
  public Builder url(String url) {
      if (url == null) throw new IllegalArgumentException("url == null");

      // Silently replace websocket URLs with HTTP URLs.
      if (url.regionMatches(true, 0, "ws:", 0, 3)) {
        url = "http:" + url.substring(3);
      } else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
        url = "https:" + url.substring(4);
      }
      HttpUrl parsed = HttpUrl.parse(url);
      if (parsed == null) throw new IllegalArgumentException("unexpected url: " + url);
      return url(parsed);
    }


    //最后面调用build()方法,返回Request实例
     public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
      return new Request(this);
    }


}

}

通过对上面源码的分析,我们可以在以后对自己的工具类的封装中使用其思路,达到顺畅舒服的代码语法。

2.POST请求(Form形式)

  • 下面的代码中将会穿插butterknife知识的讲解,butterknife把我们从繁琐的findViewById()以及事件的监听中解放出来,这里是它的官网butterknife。

  • POST请求和GET请求不一样的是:POST请求将要上传几个key-value键值对。这几个key-value键值对处于请求报文最后面的body中。其实在GET请求中也有一些key-value键值对,但其处于URL后面,以?key1=value&key2&value2的结构出现。下面是POST方法的使用实例:


public class LoginActivity extends AppCompatActivity {
    //直接把组建绑定给id
    @BindView(R.id.etxt_username)
    EditText mEtxtUsername;
    @BindView(R.id.etxt_password)
    EditText mEtxtPassword;
    @BindView(R.id.btn_login)
    Button mBtnLogin;

    private OkHttpClient httpClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        //将activity与组建绑定,而上一句把布局activity与布局绑定
        ButterKnife.bind(this);

        httpClient= new OkHttpClient();

    }
    //直接在id上设置点击事件
    @OnClick(R.id.btn_login)
    public void onClick() {

        String username = mEtxtUsername.getText().toString().trim();
        String password = mEtxtPassword.getText().toString().trim();

        loginWithForm(username,password);


    }



private void loginWithForm(String username, String password) {


        String url = Config.API.BASE_URL+"login";
        //比GET方法多了一个RequestBody类,该类将提交参数加入
        RequestBody body = new FormBody.Builder()
              .add("username",username)
              .add("password",password)
              .build();

       Request request = new Request.Builder()
              .url(url)
              .post(body)
              .build();

      httpClient.newCall(request).enqueue(new Callback() {
           @Override
           public void onFailure(Call call, IOException e) {

               Log.d("LoginActivity","请求服务器出差");

           }

            @Override
           public void onResponse(Call call, Response response) throws IOException {

                if(response.isSuccessful()){

                   String json = response.body().string();
                  try {
                  //将json字符串转换为JSONObject对象,从中取出value
                       JSONObject jsonObj = new JSONObject(json);

                        final String message = jsonObj.optString("message");
                        final int success = jsonObj.optInt("success");

                    //如果需要实现对UI的操作,则需要使用runOnUiThread方法
                       runOnUiThread(new Runnable() {
                           @Override
                            public void run() {

                                if(success==1)

                                    Toast.makeText(LoginActivity.this,"登录成功",Toast.LENGTH_LONG).show();

                               else
                                    Toast.makeText(LoginActivity.this,message,Toast.LENGTH_LONG).show();
                            }
                        });


                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }

           }
        });
    }
}

3.POST请求(JSON形式)


       JSONObject jsonObj = new JSONObject();

       try {
          jsonObj.put("username",username);
           jsonObj.put("password",password);
       } catch (JSONException e) {
           e.printStackTrace();
      }

       String jsonParams =jsonObj.toString();

      Log.d("LoginActivity","json params = "+jsonParams);

     RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),jsonParams);

     Request request = new Request.Builder()
               .url(url)
              .post(body)
               .build();
  • JSON形式提交是指先把提交的key-value对转换为JSONObject对象,将转换为字符串的JSONObject对象传入RequestBody中,请求调用request。

4.文件下载(简单方式)

  • 我们将下载一个apk为例对文件下载进行讲解。

public class FileDownloadActivity extends AppCompatActivity {


    public String url ="http://112.124.22.238:8081/course_api/css/net_music.apk";
    //定义下载后的文件名
    public String fileName = "net_music.apk";



    @BindView(R.id.btn_download)
    Button mBtnDownload;
    @BindView(R.id.progressBar)
    ProgressBar mProgressBar;

    private OkHttpClient httpClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_file_download);
        ButterKnife.bind(this);


        requestPermission();
        initOKhttp();
    }

    private void initOKhttp() {

       httpClient = new OkHttpClient();

}


    //当点击download时调用downloadAPK()方法
    @OnClick(R.id.btn_download)
    public void onClick() {

        downloadAPK();

    }

    private void downloadAPK() {

        Request request = new Request.Builder()
                .url(url)
                .build();

        httpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

                Log.d("LoginActivity","请求文件出差");

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                //与前面俩种案例比较,区别在于对输入流的处理
                writeFile(response);

            }
        });




    }


    //在Handler类中调用handleMessage方法来对UI进行处理
    Handler mHandler = new Handler(){

        @Override
        public void handleMessage(Message msg) {

            if(msg.what==1){

               int  progress = msg.arg1;
                mProgressBar.setProgress(progress);

            }

        }
    };


    private void writeFile(Response response) {
    //输入流和输出流之间共接一个内存
        InputStream is =null;
        FileOutputStream fos = null;
        //从response中得到输入流,inputStream
        is = response.body().byteStream();

        //对文件的处理,得到文件路径,创建文件
        String path = Environment.getExternalStorageDirectory().getAbsolutePath();

        Log.d("FileDownloadActivity","path:"+path);
        //创建文件
        File file = new File(path,fileName);
        try {
            fos = new FileOutputStream(file);

            byte[] bytes = new byte[1024];

            int len =0;
       //提前的到文件的大小
      long  totalSize = response.body().contentLength();

           long sum =0;

            while ((len =is.read(bytes)) !=-1){

                   fos.write(bytes);


                   sum +=len;

                 int progress = (int) ((sum * 1.0f / totalSize) * 100);
                //把message标示为1,上文中msg.what ==1来区分信息
                Message msg = mHandler.obtainMessage(1);
                msg.arg1 = progress;
                //对UI的处理只能在UI线程中执行,所以把msg传给Handler处理
                mHandler.sendMessage(msg);



            }


        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally {
                //文件流打开时,必须关闭! inputstream,outputStream
                try {
                    if(is !=null){
                        is.close();
                    }

                    if(fos !=null){
                        fos.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
            }

        }

    }

}
  • 这段代码中将response.body().byteStream 转换为输入流,接下来就是我们常写的读取输入流,写入文件的操作。这里注意Handler的使用,在Handler类中调用handleMessage方法,在方法内部对UI进行操作。在文件操作处,mHandler.sendMessage(msg); 将msg传到UI线程处。
  • 还得注意在配置文件中配置权限

5.文件下载(拦截方式)

6.OkHttp3的封装(采用链式封装)

5,6俩点我尚未全部理解和实现,先放着,等我全部实现了再回来编辑,不好意思了,读者们。

你可能感兴趣的:(网络,开源框架,okhttp3,ButterKnif)