1. 程式人生 > >Android網路框架初步嘗試

Android網路框架初步嘗試

 最近面試了很多公司,感慨良多,面試官都強調要多寫技術文章,多閱讀原始碼。仔細想想確實如此,想成為一名好的Android工程師,如果沒有原始碼閱讀,怎麼能寫出好的程式碼那。

 因為是第一篇文章,肯定想拿出一點好東西帶大家分享。想想看自己也就寫過一個網路框架可以拿出來談談。
 首先介紹我這個網路框架的思路
 1.所有的網路請求都抽象成一個task.

 2.網路請求可以配置執行的方式,比如在當前執行緒執行,在單執行緒池排隊執行,多執行緒池併發執行
 3.網路請求的方法可以方便配置
 4.網路解析的方式可以方便配置,比如公司是採用XML JSON 還是其他格式都要可以支援變更

 以下是自己寫的https://github.com/OneOfBillions/NetExcutor 
 歡迎牛人來評鑑
 這裡給大家預覽一些程式碼

這是一個執行請求的方法,可以看出使用builder模式可以有很多可以自由設定的

    public static <T> Canceller executorCommonRequest(final Context context,
                                                      final NetUIListener<T> uiListener, final NetOptions
                                                              options) {
        Canceller canceller = new
Canceller(null); try { if (uiListener != null) { OkHttpNetEngine engine = new OkHttpNetEngine(context);//網路引擎 NetRequestConfig.Builder builder = new NetRequestConfig.Builder();//設定請求引數 builder.setContext(context); builder.setNetUIListener(uiListener); builder.setOptions(options); builder.setNetEngine(engine); builder.setMethod(uiListener.getMethod()); builder.setDataParser(new
JsonDataParser()); canceller = new Canceller(engine); new CommonNetTask(builder.build()).start(); } } catch (Exception e) { Log.d(NetUtils.TAG, "網路請求錯誤: " + e.toString()); } return canceller; }

網路請求就是一個TASK

public abstract class NetTask implements Runnable {


    /**
     * 任務處理中的資料中轉.
     */
    private HashMap<String, Object> data = new HashMap<>();
    /**
     * 單執行緒任務池.
     */
    private static ExecutorService executorService = Executors
            .newSingleThreadExecutor();
    /**
     * 多執行緒任務池.
     */
    private static ExecutorService executorMutipleService = Executors
            .newCachedThreadPool();

    /**
     * 單執行緒池,適用於時序要求的任務佇列.
     *
     * @param runnable the runnable
     */
    public static void executeRunnbale(Runnable runnable) {
        if (runnable != null) {
            executorService.execute(runnable);
        }

    }

    /**
     * 網路請求的配置類.
     */
    private NetRequestConfig netRequest;
    /**
     * Parameter.
     */
    private NetParameter parameter;

    /**
     * Instantiates a new Net task.
     *
     * @param netRequest the net request
     */
    public NetTask(NetRequestConfig netRequest) {
        this.netRequest = netRequest;
        if (netRequest != null) {
            if (netRequest.getNetEngine() != null) {

                if (netRequest.getOptions() != null) {
                    if (netRequest.getNetUIListener() != null) {
                        prepareCreateParameter();
                        this.parameter = netRequest.getNetUIListener().createNetParams();
                        if (this.parameter != null) {
                            //init success
                        } else {
                            throw new NetException("parameter 不能為空");
                        }
                    } else {
                        throw new NetException("uiListener 不能為空");
                    }
                } else {
                    throw new NetException("option 不能為空");
                }
            } else {
                throw new NetException("請設定一種執行網路任務的引擎");
            }


        } else {
            throw new NetException("NetRequest 不能為空");
        }
    }

    /**
     * Prepare create parameter.
     */
    public void prepareCreateParameter() {

    }

    /**
     * Use cache refresh ui.
     *
     * @param <T>        the type parameter
     * @param localValue the local value
     */
    public <T> void callback(String localValue) {

        if (!TextUtils.isEmpty(localValue)) {
            // 得到快取資料


            T localResponseBean = GsonUtil.fromJsonStringToCollection(
                    localValue, getNetUiListener().getType());

            if (localResponseBean != null) {

                // 用快取資料先重新整理介面
                callback(
                        NetUtils.NetRequestStatus.SUCCESS, localResponseBean);

            }


        }

    }

    /**
     * 網路請求回撥
     *
     * @param <T>              the type parameter
     * @param netRequestStatus the net request status
     * @param bean             the bean
     */
    public <T> void callback(
            final NetUtils.NetRequestStatus netRequestStatus, final T bean) {

        if (getNetUiListener() != null) {

            if (getOptions().isPostUIThread()) {
                //回撥到UI執行緒

                if (getContext() != null && getContext() instanceof Activity) {
                    Activity activity = (Activity) getContext();
                    if (!activity.isFinishing()) {
                        boolean isDes = false;
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                            isDes = activity.isDestroyed();
                        }
                        if (!isDes) {
                            activity.runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    getNetUiListener().onComplete(bean, netRequestStatus);
                                }
                            });


                        }
                    }


                }

            } else {
                //在任務執行執行緒執行回撥
                getNetUiListener().onComplete(bean, netRequestStatus);
            }


        }


    }


    /**
     * 多執行緒池,適用於並行任務的執行.
     *
     * @param runnable the runnable
     */
    public static void executeMutipleRunnbale(Runnable runnable) {
        if (runnable != null) {
            executorMutipleService.execute(runnable);
        }

    }

    /**
     * Put handler info.
     *
     * @param key   the key
     * @param value the value
     */
    public void putHandlerInfo(String key, Object value) {
        if (!TextUtils.isEmpty(key)) {
            data.put(key, value);
        }

    }


    /**
     * Gets handler info.
     *
     * @param <T>      the type parameter
     * @param key      the key
     * @param classOfT the class of t
     * @return the handler info
     */
    public <T> T getHandlerInfo(String key, Class<T> classOfT) {
        if (!TextUtils.isEmpty(key) && classOfT != null) {
            Object object = data.get(key);
            if (object != null && classOfT.isInstance(object)) {
                return (T) object;


            }


        }
        return null;

    }

    /**
     * Start.
     */
    public void start() {
        NetOptions netOptions = getOptions();
        if (netOptions != null) {
            switch (netOptions.getRunMode()) {
                case SINGLE_THREAD_POOL:
                    executeRunnbale(this);
                    break;
                case MUTIPLE_THREAD_POOL:
                    executeMutipleRunnbale(this);
                    break;
                case CURRENT_THREAD:
                    this.run();
                    break;


            }
        }
    }

    /**
     * Gets options.
     *
     * @return the options
     */
    public NetOptions getOptions() {
        return netRequest.getOptions();
    }


    /**
     * Gets net engine.
     *
     * @return the net engine
     */
    public NetEngine getNetEngine() {
        return netRequest.getNetEngine();
    }


    /**
     * Gets context.
     *
     * @return the context
     */
    public Context getContext() {
        return netRequest.getContext();
    }


    /**
     * Gets net request.
     *
     * @return the net request
     */
    public NetRequestConfig getNetRequest() {
        return netRequest;
    }


    /**
     * Gets net ui listener.
     *
     * @return the net ui listener
     */
    public NetUIListener getNetUiListener() {
        return netRequest.getNetUIListener();
    }


    /**
     * Gets parameter.
     *
     * @return the parameter
     */
    public NetParameter getParameter() {
        return parameter;
    }

    /**
     * Gets net data parser.
     *
     * @return the net data parser
     */
    public NetDataParser getNetDataParser() {
        return netRequest.getDataParser();
    }

}

去實現一個通用的網路任務

public class CommonNetTask extends NetTask {
    /**
     * Instantiates a new Common net task.
     *
     * @param netRequest the net request
     */
    public CommonNetTask(NetRequestConfig netRequest) {
        super(netRequest);
    }

    /**
     * Run.
     */
    @Override
    public void run() {
        Object responseBean = null;
        NetUtils.NetRequestStatus netRequestStatus = NetUtils.NetRequestStatus.SERVER_ERROR;
        NetEngine engine = getNetEngine();


        NetRequestConfig netRequest = getNetRequest();
        NetResponseInfo netResponseInfo;
        NetRequestConfig.Method method = netRequest.getMethod();
        netResponseInfo = engine.request
                (getParameter(),netRequest.getMethod());
        String resultStr = null;
        NetUIListener netUIListener = getNetUiListener();
        Type type = netUIListener.getType();
        if (netResponseInfo != null && netResponseInfo.isSuccess()) {
            resultStr = netResponseInfo.getResult();
            netUIListener.setOriginalData(resultStr);//儲存原始字元
            responseBean = netRequest.getDataParser().parse(resultStr, type);
            if (responseBean != null) {
                netRequestStatus = NetUtils.NetRequestStatus.SUCCESS;
            } else {
                netRequestStatus = NetUtils.NetRequestStatus.SERVER_ERROR;
            }
        } else {
            netRequestStatus = NetUtils.NetRequestStatus.NET_ERROR;
        }
        callback(netRequestStatus, responseBean);
    }
}

網路請求引擎,實現類一般是各種網路框架okhttp,httpclient.

public interface NetEngine {
    /**
     * Init context.
     *
     * @param context the context
     */
    void initContext(Context context);

     NetResponseInfo request(NetParameter params, NetRequestConfig.Method method);


    /**
     * Add task tag.
     *
     * @param taskTag the task tag
     */
    void addTaskTag(Object taskTag);

    /**
     * Cancel task.
     *
     * @param canceller the canceller
     */
    void cancelTask(Canceller canceller);


}





/**
 * 用okhttp網路框架實現{@link NetEngine}
 *
 * @version V1.0
 */
public class OkHttpNetEngine implements NetEngine {


    /**
     * The DEBUG TAG.
     */
    public static final String TAG = OkHttpNetEngine.class.getSimpleName();

    /**
     * Instantiates a new Ok http net engine.
     *
     * @param context the context
     */
    public OkHttpNetEngine(Context context) {
        initContext(context);
    }

    /**
     * Add task tag.
     *
     * @param taskTag the task tag
     */
    @Override
    public void addTaskTag(Object taskTag) {
        this.taskTag = taskTag;
    }

    /**
     * 任務TAG
     */
    private Object taskTag;

    /**
     * @version V1.0
     * @Title: Ok http excutor
     *  2016.12.02
     * @Title: Ok http excutor
     */
    private static class OkHttpExcutor {
        /**
         * M ok http client.
         */
        private static final OkHttpClient okHttpClient = new OkHttpClient();
        /**
         * 連線超時.
         */
        private static final int CONNECT_TIME_OUT_MS = 60 * 1000;
        /**
         * 讀取超時.
         */
        private static final int READ_TIME_OUT_MS = 60 * 1000;


        static {
            okHttpClient.setConnectTimeout(CONNECT_TIME_OUT_MS,
                    TimeUnit.MILLISECONDS);
            okHttpClient.setWriteTimeout(READ_TIME_OUT_MS, TimeUnit.MILLISECONDS);
            okHttpClient.setReadTimeout(READ_TIME_OUT_MS, TimeUnit.MILLISECONDS);

            okHttpClient.setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });


            try {
                SSLContext sslContext = SSLContext.getInstance("SSL");

                sslContext.init(null, new TrustManager[]{new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] chain, String authType) {
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] chain, String authType) {
                    }

                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        X509Certificate[] x509Certificates = new X509Certificate[0];
                        return x509Certificates;
                    }
                }}, new SecureRandom());
                okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (KeyManagementException e) {
                e.printStackTrace();
            }

        }


        /**
         * Init persistent cookie store.
         *
         * @param context the context
         */
        public static void initPersistentCookieStore(Context context) {
            if (okHttpClient.getCookieHandler() == null) {
                if (context != null) {
                    Context application = context.getApplicationContext();
                    if (application != null) {
                        okHttpClient.setCookieHandler(new CookieManager(
                                new PersistentCookieStore(application), CookiePolicy.ACCEPT_ALL));


                    }
                }
            }

        }

        /**
         * Cancel task.
         *
         * @param taskTag the task tag
         */
        public static void cancelTask(Object taskTag) {
            if (taskTag != null) {
                okHttpClient.cancel(taskTag);
            }
        }

        /**
         * Request by post net response info.
         *
         * @param params  the params
         * @param taskTag the task tag
         * @param method  the method
         * @return the net response info
         */
        public static NetResponseInfo requestByMethod(NetParameter params, Object taskTag, NetRequestConfig.Method method) {
            NetResponseInfo netEventInfo = new NetResponseInfo();//返回資訊
            Request.Builder builder = new Request.Builder();
            if (taskTag != null) {
                builder.tag(taskTag);
            }


            ResponseBody responseBody = null;
            try {
                FormEncodingBuilder formEncodingBuilder = new FormEncodingBuilder();
                //請求引數拼裝
                List<KeyValuePair> list = params.createParameters();
              Request request =null;
                switch (method){
                    case GET:
                        String url = params.getRequestURL();
                        if (list != null && !list.isEmpty()) {
                            url += "?"
                                    + URLEncodedUtils.format(list, "UTF-8");
                        }
                        request = builder.url(url).build();
                        break;
                    case DELETE:
                        if (list != null && !list.isEmpty()) {
                            for (KeyValuePair keyValuePair : list) {
                                formEncodingBuilder.add(keyValuePair.getKey(),
                                        keyValuePair.getValue());

                            }
                        }
                        request = builder.url(params.getRequestURL())
                                .delete(formEncodingBuilder.build()).build();
                        break;
                    case POST:
                        if (list != null && !list.isEmpty()) {
                            for (KeyValuePair keyValuePair : list) {
                                formEncodingBuilder.add(keyValuePair.getKey(),
                                        keyValuePair.getValue());

                            }
                        }
                        request = builder.url(params.getRequestURL())
                                .post(formEncodingBuilder.build()).build();
                        break;
                    case PUT:
                        if (list != null && !list.isEmpty()) {
                            for (KeyValuePair keyValuePair : list) {
                                formEncodingBuilder.add(keyValuePair.getKey(),
                                        keyValuePair.getValue());

                            }
                        }
                        request = builder.url(params.getRequestURL())
                                .put(formEncodingBuilder.build()).build();
                        break;
                    default:
                        if (list != null && !list.isEmpty()) {
                            for (KeyValuePair keyValuePair : list) {
                                formEncodingBuilder.add(keyValuePair.getKey(),
                                        keyValuePair.getValue());

                            }
                        }
                        request = builder.url(params.getRequestURL())
                                .post(formEncodingBuilder.build()).build();
                        break;



                }
                Call call = okHttpClient.newCall(request);
                netEventInfo.setStartTime(String.valueOf(System.currentTimeMillis()));//網路耗時統計
                Response response = call.execute();
                netEventInfo.setEndTime(String.valueOf(System.currentTimeMillis()));//網路耗時統計
                netEventInfo.setHttpCode(String.valueOf(response.code()));///網路返回狀態碼
                if (response.isSuccessful()) {
                    netEventInfo.setSuccess(true);
                    responseBody = response.body();
                    if (responseBody != null) {
                        String reponseStr = responseBody.string();

                        if (!TextUtils.isEmpty(reponseStr)) {
                            //網路返回結果解碼
                            netEventInfo.setResult(params.decodeResponse(reponseStr));
                        }
                    }


                }
            } catch (Exception e) {
                netEventInfo.setException(e.toString());//記錄網路請求錯誤
            } finally {
                try {
                    responseBody.close();
                } catch (Exception e) {

                }


            }
            return netEventInfo;


        }


    }


    /**
     * Init context.
     *
     * @param context the context
     */
    @Override
    public void initContext(Context context) {
        if (context != null) {
            OkHttpExcutor.initPersistentCookieStore(context);
        }
    }

    @Override
    public NetResponseInfo request(NetParameter params, NetRequestConfig.Method method) {
       return OkHttpExcutor.requestByMethod(params, taskTag, method);
    }

    /**
     * Cancel task.
     *
     * @param canceller the canceller
     */
    @Override
    public void cancelTask(Canceller canceller) {
        if (canceller != null) {
            OkHttpExcutor.cancelTask(canceller.getTaskTag());
        }

    }

    private static final String POST = "POST";
    private static final String GET = "GET";
    private static final String PUT = "PUT";
    private static final String DELETE = "DELETE";


}

有 請求了肯定有回撥啊,這個是必須的

public abstract  class NetUIListener<T> {

    /**
     * M type.
     */
    private Type mType;
    /**
     * Original data.
     */
    private String originalData;

    /**
     * Gets original data.
     *
     * @return the original data
     */
    public String getOriginalData() {
        return originalData;
    }

    /**
     * Sets original data.
     *
     * @param originalData the original data
     */
    public void setOriginalData(String originalData) {
        this.originalData = originalData;
    }

    /**
     * Instantiates a new Ui listener.
     */
    public NetUIListener() {
        mType = getSuperclassTypeParameter(getClass());

    }

    /**
     * Gets type.
     *
     * @return the type
     */
    public Type getType() {
        return mType;
    }


    /**
     * Gets superclass type parameter.
     *
     * @param subclass the subclass
     * @return the superclass type parameter
     */
    private Type getSuperclassTypeParameter(Class<?> subclass) {
        Type superclass = subclass.getGenericSuperclass();
        if (superclass instanceof Class) {
            throw new RuntimeException("Missing type parameter.");
        }
        ParameterizedType parameterized = (ParameterizedType) superclass;
        return parameterized.getActualTypeArguments()[0];
    }

    public NetRequestConfig.Method getMethod(){
        return NetRequestConfig.Method.POST;
    }



    public abstract NetParameter createNetParams();
    /**
     * 在非主執行緒中組裝引數適用於耗時的任務
     */
    public void assembleCommonParamsBeanBackground(){

    }

    /**
     * SUCCESS:伺服器成功返回資料並GSON解析完成,業務處理
     * SERVER_ERROR:系統錯誤(例如gson解析錯誤)
     * NET_ERROR:網路錯誤
     * UI執行緒執行
     *
     * @param bean             the bean
     * @param netRequestStatus the net request status
     */
    public abstract void onComplete(T bean, NetUtils.NetRequestStatus netRequestStatus);

}




public abstract  class CommonNetUIListener<T>  extends NetUIListener<T> implements  ConfigUrl{
    @Override
    public NetParameter createNetParams() {
        return new CommonNetParameter(createUrl(),submitNetParams());
    }





    /**
     * 提交網路請求引數
     * return NULL,不傳送網路請求,也不會有結果回撥
     * UI執行緒執行
     *
     * @return the common params bean
     */
    public abstract List<KeyValuePair> submitNetParams();

}

網路返回資料解析類,具體可以實現 XML, JSON等格式的轉換

public interface NetDataParser {

    /**
     * Parse t.
     *
     * @param data     the data
     * @param classOfT the class of t
     * @return the t
     */
    Object parse(Object data, Type classOfT);
}



public class JsonDataParser implements NetDataParser {

    /**
     * Parse t.
     *
     * @param data     the data
     * @param classOfT the class of t
     * @return the t
     */
    @Override
    public Object parse(Object data, Type classOfT) {
        if (data != null && classOfT != null) {

            if (data.getClass() != classOfT) {
                return GsonUtil.fromJsonStringToCollection(
                        String.valueOf(data), classOfT);
            } else {
                return data;
            }

        }

        return null;

    }

可以說費勁九牛二虎之力實現一個很原始的網路框架。。。。哈哈