OkHttp3全面解析&注解工具butterknife

来源:互联网 发布:桌面控制软件 编辑:程序博客网 时间:2024/06/14 11:18

前言: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等。
@Overridepublic 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俩点我尚未全部理解和实现,先放着,等我全部实现了再回来编辑,不好意思了,读者们。

4 0
原创粉丝点击