Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 基於OkHttp的UI層回調封裝

Android 基於OkHttp的UI層回調封裝

編輯:關於Android編程

用多了OkHttp你會發現,它的返回結果都是在子線程中的,我們對返回結果進行解析後,必須通過handler去更新UI,這麼一來,便會多出很多重復的機械代碼。我們需要進行一層封裝,在onResponse回調方法中對返回結果進行解析,然後將解析結果發出去到UI線程進行更新UI。

因此,我們需要一個解析的方法,我們定義一個接口。

 {
    T parse(Response response);
}
 data-snippet-id=ext.cec61e79aa461b746feef11602eb4015 data-snippet-saved=false data-csrftoken=FFB8F3V0-cMZ5HYXGR2ciooUmZ0MydkD49ok data-codota-status=done>public interface Parser {
    T parse(Response response);
}

該接口傳入okhttp給我們返回的Response ,我們將其進行解析,具體怎麼解析由我們自己實現,比如直接返回字符串形式,或者將json轉化為實體類返回等等。

然後我們默認提供幾種實現,首先是直接返回字符串。

 {
    @Override
    public String parse(Response response) {
        String result=null;
        try {
            result=response.body().string();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
} data-snippet-id=ext.516a89f6a521c25637bfc09af9f05630 data-snippet-saved=false data-csrftoken=y3cxcXmx-n-JLN_KclziMMzSOdhEgpZDwWcc data-codota-status=done>public class StringParser implements Parser {
    @Override
    public String parse(Response response) {
        String result=null;
        try {
            result=response.body().string();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
}

再實現一個將json轉化為實體類的。這個相對復雜一點,需要將實體類的Class對象傳入,因為我們使用的是gson,進行轉換的時候需要該參數。當然這個應該是對所有實體類通用的,很顯然的用到了泛型。

 implements Parser {
    private Class mClass=null;
    public GsonParser(Class clazz){
        if (clazz==null){
            throw new IllegalArgumentException(Class can't be null);
        }
        this.mClass=clazz;
    }
    @Override
    public T parse(Response response) {
        try {
            Gson gson=new Gson();
            String str=response.body().string();
            T t=gson.fromJson(str,mClass);
            return t;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}
 data-snippet-id=ext.eb19a9e01dbbd2b4c51c65e05d4020f0 data-snippet-saved=false data-csrftoken=IZar1yFn-UJkcVXawAxgbtZEYAKOCG964lOA data-codota-status=done>public class GsonParser implements Parser {
    private Class mClass=null;
    public GsonParser(Class clazz){
        if (clazz==null){
            throw new IllegalArgumentException(Class can't be null);
        }
        this.mClass=clazz;
    }
    @Override
    public T parse(Response response) {
        try {
            Gson gson=new Gson();
            String str=response.body().string();
            T t=gson.fromJson(str,mClass);
            return t;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

要在UI層進行更新UI,其實很簡單,解析完成後發生一個消息就好了,那麼要怎麼做呢。

首先實現Callback接口

 implements com.squareup.okhttp.Callback {
    private Parser mParser;

    public Callback(Parser mParser) {
        if (mParser == null) {
            throw new IllegalArgumentException(Parser can't be null);
        }
        this.mParser = mParser;
    }

    @Override
    public void onFailure(Request request, IOException e) {

    }

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

    }


}
 data-snippet-id=ext.7e4050d9ffcd016000b2d5fce948b0e4 data-snippet-saved=false data-csrftoken=3LIOZuhp-3Fb7sxOuPVtPQBo_1fubSAlgGkE data-codota-status=done>public class Callback implements com.squareup.okhttp.Callback {
    private Parser mParser;

    public Callback(Parser mParser) {
        if (mParser == null) {
            throw new IllegalArgumentException(Parser can't be null);
        }
        this.mParser = mParser;
    }

    @Override
    public void onFailure(Request request, IOException e) {

    }

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

    }


}

通過構造函數將我們的Parser傳遞了進去。

現在假設,我們已經定義好了Handler對象,則在請求失敗的時候我們需要發送一個失敗的消息

應該有兩個區別消息的常量

private static final int CALLBACK_SUCCESSFUL=0x01;
private static final int CALLBACK_FAILED=0x02;

請求失敗後發送失敗的消息

public void onFailure(Request request, IOException e) {
    Message message=Message.obtain();
    message.what=CALLBACK_FAILED;
    message.obj=e;
    mHandler.sendMessage(message);
}

請求成功的回調的處理看個人情況了,這裡認為響應碼是2開頭的就是請求成功,否則也認為是失敗,比如400,500。如果請求成功了就調用Parser的parse方法解析

public void onResponse(Response response) throws IOException {
    if (response.isSuccessful()) {
        T parseResult = mParser.parse(response);
        Message message=Message.obtain();
        message.what=CALLBACK_SUCCESSFUL;
        message.obj=parseResult;
        mHandler.sendMessage(message);
    } else {
        Message message=Message.obtain();
        message.what=CALLBACK_FAILED;
        mHandler.sendMessage(message);
    }
}

剩下的就是我們的Handler了,我們把它定義成靜態的,防止內存洩露,由於需要調用外部類的方法,所有還需要持有外部類的引用,同樣的防止內存洩露,使用弱引用。同時記得使用主線程的Looper。

 extends Handler{
    private WeakReference mWeakReference;
    public UIHandler(cn.edu.zafu.coreokhttp.callback.Callback callback){
        super(Looper.getMainLooper());
        mWeakReference=new WeakReference(callback);
    }

    @Override
    public void handleMessage(Message msg) {

    }
}
private Handler mHandler=new UIHandler(this); data-snippet-id=ext.f51a388bd196ac6782b89d87fe2e01fd data-snippet-saved=false data-csrftoken=WyHTOoMS-rPdG952wjFxjTAikJsxdDhHQ54A data-codota-status=done>static class UIHandler extends Handler{
    private WeakReference mWeakReference;
    public UIHandler(cn.edu.zafu.coreokhttp.callback.Callback callback){
        super(Looper.getMainLooper());
        mWeakReference=new WeakReference(callback);
    }

    @Override
    public void handleMessage(Message msg) {

    }
}
private Handler mHandler=new UIHandler(this);

接下來就是handleMessage方法的處理了。

public void handleMessage(Message msg) {
    switch (msg.what){
        case CALLBACK_SUCCESSFUL: {
            T t = (T) msg.obj;
            cn.edu.zafu.coreokhttp.callback.Callback callback = (cn.edu.zafu.coreokhttp.callback.Callback) mWeakReference.get();
            if (callback != null) {
                callback.onResponse(t);
            }
            break;
        }
        case CALLBACK_FAILED: {
            IOException e = (IOException) msg.obj;
            cn.edu.zafu.coreokhttp.callback.Callback callback = (cn.edu.zafu.coreokhttp.callback.Callback) mWeakReference.get();
            if (callback != null) {
                callback.onFailure(e);
            }
            break;
        }
        default:
            super.handleMessage(msg);
            break;
    }
}

從代碼中看到,我們回調了兩個函數,沒錯,這兩個是空函數,由用戶去覆蓋重寫實現

public void onResponse(T t){

}
public  void onFailure(IOException e){

}

這樣有什麼好處呢?

Parser可以重復使用,避免多次解析使用同樣的代碼 避免編寫多次Handler去處理UI層更新

現在我們看看如何使用。

我們簡單的使用StringParser進行解析返回結果

OkHttpClient okHttpClient=new OkHttpClient();
StringParser parser=new StringParser();
Request request = new Request.Builder().url(https://www.baidu.com).build();
okHttpClient.newCall(request).enqueue(new cn.edu.zafu.coreokhttp.callback.Callback(parser) {
    @Override
    public void onResponse(String s) {
        Toast.makeText(getApplicationContext(),s,Toast.LENGTH_SHORT).show();
    }

});

從代碼中看到,我們重寫了我們定義的空函數,直接用Toast顯示出了解析結果。

在一定程度上簡化了原來的代碼。但是還不夠精簡,請期待後續的封裝。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved