show code block

2017年2月16日 星期四

third-party元件 ─ 第三方AsyncHttpClient(使用方式和封裝)


請先參考:此篇https://disp.cc/b/11-9faq

此時你會發現我網誌就到這邊結束了,因為裡面都講得很詳細。

好啦當然開玩笑的。

也稍微介紹一下,基本上就是複製貼上。後面我會把這個方法做個封裝。

build.gradle (Module: app) 加上
   
compile 'com.loopj.android:android-async-http:1.4.9' 


此時最主要的方法是以下兩個
AsyncHttpClient client = new AsyncHttpClient(); 
RequestParams params = new RequestParams();





讓我們開始吧。

先加權限!

以下是重點程式碼的實作


String url = "http://disp.cc/api/board.php";
AsyncHttpClient client = new AsyncHttpClient();
RequestParams params = new RequestParams();
params.put("act", "blist");
params.put("limitNum", "5");
client.get(url, params, new JsonHttpResponseHandler() {
    @Override
    public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
        // Root JSON in response is an dictionary i.e { "data : [...] }
        // Handle resulting parsed JSON response here
        if (response.optInt("isSuccess") != 1) {
            Toast.makeText(mContext, "Error:" + response.optString("errorMessage"), Toast.LENGTH_LONG).show();
            return;
        }
        JSONObject data = response.optJSONObject("data");
        int totalNum = data.optInt("totalNum");
        Log.d("test","totalNum: " + totalNum);
    }

    @Override
    public void onFailure(int statusCode, Header[] headers, String res, Throwable t) {
        // called when response HTTP status is "4XX" (eg. 401, 403, 404)
        Toast.makeText(getApplicationContext(), "Error: " + statusCode + " " + e.getMessage(), Toast.LENGTH_LONG).show();
    }
});



要讀取網址:http://disp.cc/api/board.php?act=blist&limitNum=5

如何讀取:
String url = "http://disp.cc/api/board.php";
params.put("act", "blist");
params.put("limitNum", "5");
這是get的用法

如果要使用post 就可以不用加params 直接
String url = " http://disp.cc/api/board.php?act=blist&limitNum=5";
就可以用了。
至於postget的差別在哪? 大概可以理解成post的安全性比較高。

此時上面網址的json檔案長這樣:


isSuccess的部分為1,如果不等於1(response.optInt("isSuccess") != 1 ),就會跳Json內的errorMessage





接下來文章內的東西大致上介紹完畢了。


我想對AsynHttpClient做封包。


我不希望每次調用都是整個方法重新寫一次。
我希望以後我讀取資料可以統一變成以下這樣。

我希望把Url 和  params包成同一個東西。
紅框標起來的為我想呈現的程式碼。







接下來就來實作吧。

CommunicationManager.java
 public class CommunicationManager {
    public static final String handle = CommunicationManager.class.getSimpleName();
    private static CommunicationManager instance = new CommunicationManager();//變成靜態
    private static AsyncHttpClient client = new AsyncHttpClient();

    static {
        client.setTimeout(10000);
        client.setResponseTimeout(10000);
        client.setEnableRedirects(true, true, true);
    }

    private CommunicationManager() {//要件
    }

    public static CommunicationManager getInstance() {//變成靜態用
        return instance;
    }

    public void post(Context context, RequestData RequestData, AsyncHttpResponseHandler asyncHttpResponseHandler) {
        client.get(context, RequestData.getUrl(), RequestData.getHttpParams(), asyncHttpResponseHandler);
    }

    public static <T> T covertObj(String content, Class<T> classOfT) {
        Gson gson = new Gson();
        T obj = null;
        try {
            obj = gson.fromJson(content, classOfT);
        } catch (JsonSyntaxException e) {
            Log.d(handle, "Failed to convert gson:" + content);
            e.printStackTrace();
        }
        return obj;
    }

} 


這是拿來做這件事情的





RequestData.java
/**
 * 二次封包
 */

public class RequestData {
    public static final String handle = RequestData.class.getSimpleName();
    private Builder builder;

    private RequestData(Builder builder) {
        this.builder = builder;
    }

    public String getUrl() {
        return builder.url;
    }

    public List getParameters() {
        return builder.parameters;
    }

    public RequestParams getHttpParams() {
        RequestParams params = new RequestParams();
        for (int i = 0; i < getParameters().size(); i++) {
            NameValuePair pair = getParameters().get(i);
            params.add(pair.getName(), pair.getValue());
        }
        return params;
    }


    public static class Builder {

        String url;
        List parameters = new ArrayList<>();

        public Builder(String url) {
            this.url = url;
            parameters = new ArrayList<>();
        }

        public Builder addParameter(String name, String value) {
            BasicNameValuePair nameValuePair = new BasicNameValuePair(name, value);
            parameters.add(nameValuePair);
            return this;
        }

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


大致完成了。






此時我們可以在MainActivity直接呼叫我們封包過的AsynHttpClient
就可以直接這樣呼叫使用
 private void initAsynHttp() {
        // http://disp.cc/api/board.php?act=blist&limitNum=5
        String url = "http://disp.cc/api/board.php";
        final RequestData requestData = new RequestData.Builder(url)
                .addParameter("act", "blist")
                .addParameter("limitNum", "5")
                .build();
        CommunicationManager.getInstance().post(context, requestData, new TextHttpResponseHandler() {
            @Override
            public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
            //失敗的事情,responseString內你會看到他跳出的錯誤訊息
              Log.d("OnFailer","OnFailer"+responseString);
   }

            @Override
            public void onSuccess(int statusCode, Header[] headers, String responseString) {
             //成功後做的事情,responseString內你會看到整個json檔案
                Log.d("onSuccess","onSuccess"+responseString);
            }
        });
    } 


此時會想問,要如何讀取json內的資料呢?

其實你已經寫好轉換方式了。

就是在CommunicationManager內的這一段:
    
public static <T> T covertObj(String content, Class<T> classOfT) {
        Gson gson = new Gson();
        T obj = null;
        try {
            obj = gson.fromJson(content, classOfT);
        } catch (JsonSyntaxException e) {
            Log.d(handle, "Failed to convert gson:" + content);
            e.printStackTrace();
        }
        return obj;
    }



此時你回到json檔案,會發現你的json有三層。
開始創建三層java呼應的json檔案

第一層:
public class JsonFirst implements Serializable {
    @SerializedName("isSuccess")
    public int isSuccess;

    @SerializedName("errorMessage")
    public String errorMessage;

    @SerializedName("data")
    public data dataLists;
}

第二層:
public class data {
    @SerializedName("isLogin")
    public boolean isLogin;

    @SerializedName("totalNum")
    public int totalNum;

    @SerializedName("remainNum")
    public int remainNum;

    @SerializedName("blist")
    public List blistLists;
}//最後一個blist json檔內是一個陣列,所以必須給一個List

第三層:
public class blist implements Serializable {
    public int bi;
    public String name;
    public String type;
    public String title;
    public String icon;
    public String hot;
}

創建好之後,就可以直接呼叫您的json檔案出來了
JsonFirst getJsonFirst = CommunicationManager.covertObj(responseString, JsonFirst.class);


你可以設Log看看是否呼喚成功。
private void initAsynHttp() {

    // http://disp.cc/api/board.php?act=blist&limitNum=5

    String url = "http://disp.cc/api/board.php";

    final RequestData requestData = new RequestData.Builder(url)
            .addParameter("act", "blist")
            .addParameter("limitNum", "5")
            .build();

    Log.d(handle, "RequestData =" + requestData.getUrl() + "\n Params :" + requestData.getParameters());
    CommunicationManager.getInstance().post(context, requestData, new TextHttpResponseHandler() {

        @Override

        public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
            Log.d(handle, " onFailure " + responseString + "\nthrowable =" + throwable);
            Toast.makeText(MainActivity.this, "responseString =" + responseString + "\n throwable =" + throwable, Toast.LENGTH_SHORT).show();
        }



        @Override
        public void onSuccess(int statusCode, Header[] headers, String responseString) {
            Log.d(handle, " onSuccess " + requestData.getUrl());
            JsonFirst getJsonFirst = CommunicationManager.covertobj(responseString, JsonFirst.class);
            Log.d(handle, "CheckPoint.dataLists =" + getJsonFirst.dataLists.blistLists.size());
            Log.d(handle, "CheckPoint getJsonFirst.isSuccess =" + getJsonFirst.isSuccess);
        }
    });
}
 


之後再做ListView 或是 RecyclerView把陣列的資料列出來就大功告成囉。



內容有點多,寫的比較粗略,有不懂在提問吧。

檔案Demo打包:
https://drive.google.com/open?id=0Byk75IYx-dKXMGQ5VlZyM3hVbjA

沒有留言:

張貼留言

協程(coroutine) - 協程為什麼要學它?

 Coroutine 協程 再強調一次 協程就是由kotlin官方所提供的線程api //Thread Thread { }.start() //Executor val execu...