28 Okhttp原始碼分析&實踐(六)【實踐環節:Okhttp的基本框架搭建&請求實現】

語言: CN / TW / HK

開啟掘金成長之旅!這是我參與「掘金日新計劃 · 12 月更文挑戰」的第28天,點選檢視活動詳情

http的基礎知識、okhttp的框架基本原始碼,我們通過之前課程都已學習總結過,接下來,就是關鍵的實踐課程。 各位coder,需要緊跟小編腳步,要開始加速飆車了。 在這裡插入圖片描述

1.基本框架的搭建實現

既然不知道如何入手,我們不妨就以okhttp的基本使用程式碼為例,作為入手點,去開始程式設計實現。新建一個工程,小編這裡就以OkhttpStudy來命名。裡面基本啥也沒有引用。

```java plugins { id 'com.android.application' }

android { compileSdk 32

defaultConfig {
    applicationId "com.itbird.okhttpstudy"
    minSdk 22
    targetSdk 32
    versionCode 1
    versionName "1.0"

    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}
compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

}

dependencies {

implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

} ```

1.1 搭建框架

我們在MainActivity中,直接將使用程式碼copy過來。 ```java //第一步:new okhttpclient OkhttpClient okhttpClient = new OkhttpClient.Builder().build();

    //第二步:new Requset
    Request request = new Request.Builder().url("http://www.baidu.com").method(Method.GET).build();

    //第三步:new Call
    Call call = okhttpClient.newCall(request);

    //第四部:執行
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            Log.d(Constants.TAG, "MainActivity onFailure");
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            Log.d(Constants.TAG, "MainActivity onResponse" + response.toString());
        }
    });

```

有人會說,小編你這不是又在騙人嗎?你gradle中都沒有引入okhttp,這裡自己MainActivity中這樣寫,不就都報錯了嗎?小編只想說 在這裡插入圖片描述 我們通過AS的提示功能, 一一開始新建這些類、這些方法,OkhttpClient、OkhttpClient.Builder()、build()方法等,這樣更加快捷一些,也許新建過程中,您會說,這不就是一些空方法嗎?對的,就是空方法,我們接下來就是填充這些空方法,用自己已有的知識,去試著實現它。 大家在這個過程中,謹記一條,我們最初的本心目的,並不是想要去實現一個okhttp,我們僅僅是通過這樣的學習手段,想要將自己已有的知識和okhttp核心實現,去在腦中關聯起來。

1.2 OkhttpClient類和方法建立

OkhttpClient,okhttpClient,是幹什麼的,那麼裡面肯定有一個執行器,其實說白了,就是執行緒池

```java package com.itbird.okhttpstudy;

/* * Created by itbird on 2022/11/21 / public class OkhttpClient { private Builder builder; private Dispatcher dispatcher;

public OkhttpClient(Builder builder) {
    this.builder = builder;
    dispatcher = builder.dispatcher;
}




public Call newCall(Request request) {
    return new RealCall(request, this);
}


public static class Builder {
    private Dispatcher dispatcher;


    public Builder() {
        dispatcher = new Dispatcher();
    }


    public OkhttpClient build() {
        return new OkhttpClient(this);
    }
}

}

```

1.3 Request類和方法建立

開始逐層實現,requset是幹什麼的,當然是填充引數的、url、params、method,所以接下來,第二步,Request類和方法的建立

```java package com.itbird.okhttpstudy;

import java.util.HashMap; import java.util.Map;

/* * 請求 * Created by itbird on 2022/11/21 / public class Request { private Builder builder;

public Request(Builder builder) {
    this.builder = builder;
}


public static class Builder {
    private String url;
    private Map<String, String> params;
    private Method method;


    public Builder() {
        method = Method.GET;
        params = new HashMap<>(20);
    }


    public Builder url(String url) {
        this.url = url;
        return this;
    }


    public Builder addParam(String key, String value) {
        params.put(key, value);
        return this;
    }


    public Request build() {
        return new Request(this);
    }
}

} ```

1.4 RealCall類和方法建立

到了這裡,執行緒池執行器有了,Requset也有了,是不是缺少runnable了,也就是執行緒了,那麼我們現在只有requset一個請求實體而已,那接下來要做的,就顯而易見了,就是把requset封裝為runnable任務,然後提交執行緒池執行

```java package com.itbird.okhttpstudy;

import android.util.Log;

import java.io.IOException;

/* * Created by itbird on 2022/11/21 / public class RealCall implements Call { private Request request; private OkhttpClient okhttpClient;

public RealCall(Request request, OkhttpClient okhttpClient) {
    this.request = request;
    this.okhttpClient = okhttpClient;
}


@Override
public void enqueue(Callback callback) {
    okhttpClient.dispatcher.enqueue(new AsyncCall(callback));
}


@Override
public Response execute() {
    return getResponseWithInterceptorChain();
}


private Response getResponseWithInterceptorChain() {
    return null;
}


class AsyncCall extends NamedRunnable {
    private Callback callback;


    public AsyncCall(Callback callback) {
        this.callback = callback;
    }


    public AsyncCall() {
    }


    @Override
    public void execute() {
        Log.d(Constants.TAG, "AsyncCall execute");
        Response response = getResponseWithInterceptorChain();
        if (callback != null) {
            try {
                callback.onResponse(RealCall.this, response);
            } catch (IOException e) {
            }
        }
    }
}

} ```

1.5 Dispatcher 類和方法建立

好了,到了這裡,任務也有了,缺少啥了?當然是缺少執行了,大家忘記了嗎?執行那裡還是空的呢

```java package com.itbird.okhttpstudy;

import java.util.concurrent.ExecutorService; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit;

/* * 執行器 * Created by itbird on 2022/11/21 / public class Dispatcher { private ExecutorService executorService;

public void enqueue(RealCall.AsyncCall call) {
    executorService().execute(call);
}


public synchronized ExecutorService executorService() {
    if (executorService == null) {
        executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>(), new ThreadFactory() {
            @Override
            public Thread newThread(Runnable runnable) {
                Thread result = new Thread(runnable, "okhttp");
                result.setDaemon(false);


            return result;
            }
        });
    }
    return executorService;
}

} ``` 到現在為止,程式碼可以正常運行了,我們看一下執行結果 在這裡插入圖片描述 本章到現在,大家其實從okhttp的使用入手,已經搭建實現了一個自己的okhttp框架,而且整體流程時可以跑通的,是否現在有個感覺?一切都並不是剛開始想的那麼困難了,是不?

所以也許一些事情,只要你去做了,才能真正知道難或者不難,而不是先給自己心理暗示,很難,導致問題或者需求的實現解決上,舉步維艱。

好了,接下來,就是去實現,真正的請求了,因為現在僅僅是流程跑通了而已。