引言:
前些天,我在研究一个app项目结构的时候,被一个问题困扰,我发现它的网络请求部分没有单开线程,我找了半天它的异步网络请求操作没有找到,直到今天,谜团终于打开。
解释:
OKhttp用于网络请求,一般常见的就是GET与POST。
一个简单的get请求基本步骤如下:
1.创建一个okhttpclient对象:

OkHttpClient client = new OkHttpClient();      //创建一个窗口对象

2.创建一个请求对象:

Request request = new Request.Builder()       //创建一个请求
                .url("https://www.baidu.com")
                .get()  //表明为get请求
                .build();

其实request里面还可以添加许多参数,比如请求头,请求方法,请求行,还有很多参数。
3.创建一个call对象:

Call call=client.newCall(request);      //创建一个Call

4.发送请求,这里就有区分了,有同步的请求,异步的请求。call.execute()表示为同步请求,call.enqueue(new Callback(){…})为异步请求。他们的区别正是我的困扰所在,我开篇提到的问题在这里回答了,对于同步get请求,我们往往需要单开线程,因为网络请求比较耗时。对于异步get请求,我们则不需要单开线程,因为它本身运行在其他线程中。
下面我给出完整请求代码以及线程打印截图:
(1)同步:

private void sendSyncRequest(){
        //发送同步get请求,由于网络请求耗时,需单开线程
       new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Log.w(TAG,""+Thread.currentThread());
                    OkHttpClient client = new OkHttpClient();      //创建一个窗口对象
                    Request request = new Request.Builder()       //创建一个请求
                            .url("https://www.baidu.com")
                            .get()  //表明为get请求
                            .build();
                    Call call=client.newCall(request);      //创建一个Call
                    Response response=call.execute();    //execute为同步GET请求,可直接获取Response对象
                    if(response.isSuccessful()){
                        String responseData=response.body().string();
                        Log.w(TAG+" success",""+Thread.currentThread());
                        showRequestSuccess(textView,responseData);
                    }else{
                        Log.w(TAG+" fail",""+Thread.currentThread());
                        showRequestFail(textView);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        ).start();
    }

android OkGo同步 okhttp 同步请求_android OkGo同步


(2)异步:

private void sendAsyncRequest(){
        //发送异步get请求,本身就不在主线程运行
        Log.w(TAG,""+Thread.currentThread());
        OkHttpClient client = new OkHttpClient();      //创建一个窗口对象
        Request request = new Request.Builder()       //创建一个请求
                .url("https://www.baidu.com")
                .get()  //表明为get请求
                .build();
        Call call=client.newCall(request);      //创建一个Call
        call.enqueue(new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {
                showRequestFail(textView);
                Log.w(TAG+" fail",""+Thread.currentThread());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String responseData=response.body().string();
                showRequestSuccess(textView,responseData);
                Log.w(TAG+" success",""+Thread.currentThread());
            }
        });

    }

android OkGo同步 okhttp 同步请求_get请求_02


我这里的showRequestSuccess和showRequestFail方法使用了Handler与主线程通信,详情参照我的另一篇文章:

Handler实现线程间通信

5.post请求与get基本类似,只不过创建请求时可以post上去一些参数:

Request request1 = new Request.Builder()       //创建一个请求
                .url("https://www.baidu.com")
                .post(RequestBody.create(...))  //表明为post请求
                .build();

完整代码:

package com.example.test2.fragments;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;

import com.example.test2.R;
import com.example.test2.entities.MyHandler;

import java.io.BufferedWriter;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class Fragment3 extends Fragment implements View.OnClickListener {
    private Button send,clear;
    private TextView textView;
    private MyHandler myHandler;
    public static final int REQUEST_SUCCESS=1;
    public static final int REQUEST_FAIL=2;
    private String mFailString;
    private static final String TAG="Fragment3";
    /*线程池的使用*/
    private ThreadPoolExecutor threadPoolExecutor=
            new ThreadPoolExecutor(10,20,1, TimeUnit.SECONDS,new LinkedBlockingDeque<Runnable>());
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view=inflater.inflate(R.layout.lay3,container,false);
        send=(Button)view.findViewById(R.id.send_request);
        clear=(Button)view.findViewById(R.id.clear_data);
        textView=(TextView)view.findViewById(R.id.receive_data);
        mFailString=getString(R.string.request_fail_string);
        myHandler=new MyHandler();
        myHandler.onBindingMyData(textView,mFailString);
        send.setOnClickListener(this);
        clear.setOnClickListener(this);
        return view;
    }

    private void sendAsyncRequest(){
        //发送异步get请求,本身就不在主线程运行
        Log.w(TAG,""+Thread.currentThread());
        OkHttpClient client = new OkHttpClient();      //创建一个窗口对象
        Request request = new Request.Builder()       //创建一个请求
                .url("https://www.baidu" +
                        ".com")
                .get()  //表明为get请求
                .build();
        Call call=client.newCall(request);      //创建一个Call
        call.enqueue(new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {
                showRequestFail(textView);
                Log.w(TAG+" fail",""+Thread.currentThread());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String responseData=response.body().string();
                showRequestSuccess(textView,responseData);
                Log.w(TAG+" success",""+Thread.currentThread());
            }
        });

    }

    private void sendSyncRequest(){
        //发送同步请求,使用线程池来开启线程
        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Log.w(TAG,""+Thread.currentThread());
                    OkHttpClient client = new OkHttpClient();      //创建一个窗口对象
                    Request request = new Request.Builder()       //创建一个请求
                            .url("https://www.baidu.com")
                            .get()  //表明为get请求
                            .build();
                    Call call=client.newCall(request);      //创建一个Call
                    Response response=call.execute();    //execute为同步GET请求,可直接获取Response对象
                    if(response.isSuccessful()){
                        String responseData=response.body().string();
                        Log.w(TAG+" success",""+Thread.currentThread());
                        showRequestSuccess(textView,responseData);
                    }else{
                        Log.w(TAG+" fail",""+Thread.currentThread());
                        showRequestFail(textView);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        //发送同步get请求,由于网络请求耗时,需单开线程
       /*new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Log.w(TAG,""+Thread.currentThread());
                    OkHttpClient client = new OkHttpClient();      //创建一个窗口对象
                    Request request = new Request.Builder()       //创建一个请求
                            .url("https://www.baidu.com")
                            .get()  //表明为get请求
                            .build();
                    Call call=client.newCall(request);      //创建一个Call
                    Response response=call.execute();    //execute为同步GET请求,可直接获取Response对象
                    if(response.isSuccessful()){
                        String responseData=response.body().string();
                        Log.w(TAG+" success",""+Thread.currentThread());
                        showRequestSuccess(textView,responseData);
                    }else{
                        Log.w(TAG+" fail",""+Thread.currentThread());
                        showRequestFail(textView);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        ).start();*/
    }

    private void showRequestSuccess(TextView textView, final String response){
        Message message=Message.obtain();
        message.obj=response;
        message.what=REQUEST_SUCCESS;
        Log.w("fragment3",message.what+" ^_^");
        myHandler.sendMessage(message);
    }

    private void showRequestFail(TextView textView){
        Message message=Message.obtain();
        message.obj=null;
        message.what=REQUEST_FAIL;
        Log.w("fragment3",message.what+" ^_^");
        myHandler.sendMessage(message);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.send_request:
                sendSyncRequest();
                break;
            case R.id.clear_data:
                Toast.makeText(getActivity(),"Text was cleared",Toast.LENGTH_SHORT).show();
                textView.setText("");
                break;
                default:
                    break;
        }
    }
}

注意:
1.对Response的操作也要放在子线程中。
2.response.body()后的.string()方法不能连续调用两次,别问我怎么知道的,你可以去试试:
错误示范:

getExcution(response.body().string());  //获取登录时需要的表单项之一
                Log.w("main",response.body().string()); //.string方法不能连续调两次

然后运行结果如下:

android OkGo同步 okhttp 同步请求_OKhttp_03

更多:
更详细相关用法推荐(简书大佬写的):OkHttp3简单使用教程(一):请求和响应