Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android使用自己封裝的Http和Thread、Handler實現異步任務

Android使用自己封裝的Http和Thread、Handler實現異步任務

編輯:關於Android編程

目錄結構如下:

這裡寫圖片描述

Http協議的封裝:

使用http協議有request和response這兩個主要的域,下邊是Http協議封裝的結構圖
這裡寫圖片描述

(1)HttpRequestInter.java:作為request域對象,應該可以獲得客戶端請求的地址和httpRequest對象,這樣的話才可以獲得客戶端請求的參數等信息;另外public HttpResponseInter request() throws Exception; 使用這個方法,是當執行完request請求之後,返回一個response對象(這裡用接口表示)

/**
 * 請求的接口
 * @author xuliugen
 */
public interface HttpRequestInter {

    //獲得httpRequest
    public HttpUriRequest getHttpRequest();

    //獲得http請求的url地址
    public String getRequestURL();

    //請求服務端:要返回一個response對象
    public HttpResponseInter request() throws Exception;
}

(2)HttpResponseInter.java作為和(1)中相對應的response對象,應該具有的方法:獲取返回的狀態碼、獲取返回的流、獲取返回返回的string數據等,下邊的方法就是獲取相應的數據

/**
 * 響應的接口
 * @author xuliugen
 */
public interface HttpResponseInter {

    //返回狀態碼
    public int statusCode();

    // 向客戶端返回流數
    public InputStream getResponseStream() throws IllegalStateException,IOException;

    //向客戶端返回字節數組
    public byte[] getResponseStreamAsByte() throws IOException;

    //向客戶端返回JSON數據
    public String getResponseStreamAsString() throws ParseException, IOException;
}

(3)這是HttpRequestImpl.java接口的實現類,我們可以看到我們不但實現了HttpRequestInter接口還實現了ResponseHandler 第二個就是用於當執行完request請求之後需要返回的數據,存放在一個response的Handler中。

public class HttpRequestImpl implements HttpRequestInter,ResponseHandler {

    protected HttpUriRequest httpUriRequest;// 用於獲取request的url地址
    private AbstractHttpClient abstractHttpClient; // client對象

    // 構造犯法
    public HttpRequestImpl(AbstractHttpClient httpClient) {
        this.abstractHttpClient = httpClient;
    }

    // get方法
    public HttpUriRequest getHttpRequest() {
        return httpUriRequest;
    }

    //獲得request的url
    public String getRequestURL() {
        return httpUriRequest.getURI().toString();
    }

    //執行request請求,並返回??個response對象接口
    public HttpResponseInter request() throws Exception {
        return abstractHttpClient.execute(httpUriRequest, this);//傳入的ResponseHandler對象
    }

    /**
     * 繼承ResponseHandler接口要實現的方法
     * 執行完畢之後對response對象的處理接口
     */
    public HttpResponseInter handleResponse(HttpResponse response)throws ClientProtocolException, IOException {
        //返回實現HttpResponseInter的類:返回給一個response接口
        HttpResponseInter httpResponseInter = new HttpResponseImpl(response); //返回的時候需要response
        return httpResponseInter;
    }
}

(4)然後下邊就是接口的實現類:HttpResponseImpl.java 可以在構造方法中看到一個HttpResponse response對象,這就是在執行完request之後的handler返回的response對象。

/**
 * 接口的實現類
 * @author xuliugen
 */
public class HttpResponseImpl implements HttpResponseInter {

    private HttpResponse response; // HttpResponse對象
    private HttpEntity entity; // HttpEntity試題對象

    public HttpResponseImpl(HttpResponse response) throws IOException {

        this.response = response;
        HttpEntity tempEntity = response.getEntity();// 獲得服務器端返回的entity
        if (null != tempEntity) {
            entity = new BufferedHttpEntity(tempEntity);
        }
    }

    // 返回response對象的狀態碼
    public int statusCode() {
        return response.getStatusLine().getStatusCode();
    }

    // 獲得結果的stream
    public InputStream getResponseStream() throws IllegalStateException,
            IOException {

        InputStream inputStream = entity.getContent();
        return inputStream;
    }

    // 獲得的結果轉化為string
    public String getResponseStreamAsString() throws ParseException,
            IOException {
        return EntityUtils.toString(entity);
    }

    // 獲得的結果轉化為字符數組
    public byte[] getResponseStreamAsByte() throws IOException {
        return EntityUtils.toByteArray(entity);
    }
}

(5)ExecuteHttpPost.java這個類繼承了HttpRequestImpl.java在裡邊主要寫了兩個構造方法,構造方法就是實際的進行post請求的方法,和參數的設置:

/**
 * 這裡才是真正執行post請求的地??
 * 
 * 繼承HttpRequestImpl 實現客戶端向服務器端的請??
 * 
 * @author xuliugen
 * 
 */
public class ExecuteHttpPost extends HttpRequestImpl {

    public ExecuteHttpPost(AbstractHttpClient httpClient, String url) {
        this(httpClient, url, null);
    }

    public ExecuteHttpPost(AbstractHttpClient httpClient, String url,HttpEntity entity) {
        super(httpClient);//父類中的httpClient

        this.httpUriRequest = new org.apache.http.client.methods.HttpPost(url);// 初始化httpUriRequest

        if (null != entity) {// 設置參數
            ((HttpEntityEnclosingRequestBase) httpUriRequest).setEntity(entity);
        }
    }
}

(6)另外一個重要的類就是客戶端的實現了:BaseHttpClient.java在這裡邊我們設置了一系列的方法,用於實現不同客戶端的請求方法,以及如何將客戶端請求的參數轉化為post請求的參數類型、將返回的數據轉化為相應的格式,方法的層疊調用,希望大家靜下心慢慢看。

/**
 * HttpClient客戶端的頂層類
 */
public class BaseHttpClient {

    private AbstractHttpClient httpClient;

    public static final int DEFAULT_RETIES_COUNT = 5;

    protected int retriesCount = DEFAULT_RETIES_COUNT;

    // 設置最大連接數
    public final static int MAX_TOTAL_CONNECTIONS = 100;

    // 設置獲取連接的最大等待時間
    public final static int WAIT_TIMEOUT = 30000;

    // 設置每個路由最大連接數
    public final static int MAX_ROUTE_CONNECTIONS = 100;

    // 設置連接超時時間
    public final static int CONNECT_TIMEOUT = 10000;

    // 設置讀取超時時間
    public final static int READ_TIMEOUT = 10000;

    /**
     * 構造方法,調用初始化方法
     */
    public BaseHttpClient() {
        initHttpClient();
    }

    /**
     * 初始化客戶端參數
     */
    private void initHttpClient() {

        //http的參數
        HttpParams httpParams = new BasicHttpParams();

        //設置最大連接數
        ConnManagerParams.setMaxTotalConnections(httpParams,MAX_TOTAL_CONNECTIONS);

        //設置獲取連接的最大等待時間
        ConnManagerParams.setTimeout(httpParams, WAIT_TIMEOUT);

        //設置每個路由最大連接數
        ConnPerRouteBean connPerRoute = new ConnPerRouteBean(MAX_ROUTE_CONNECTIONS);
        ConnManagerParams.setMaxConnectionsPerRoute(httpParams, connPerRoute);

        // 設置連接超時時間
        HttpConnectionParams.setConnectionTimeout(httpParams, CONNECT_TIMEOUT);

        // 設置讀取超時時間
        HttpConnectionParams.setSoTimeout(httpParams, READ_TIMEOUT);

        HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8);

        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme(http, PlainSocketFactory.getSocketFactory(), 80));//設置端口80
        schemeRegistry.register(new Scheme(https, SSLSocketFactory.getSocketFactory(), 443));//設置端口443

        //就是管理SchemeRegistry的
        ClientConnectionManager clientConnectionManager = new ThreadSafeClientConnManager(httpParams, schemeRegistry);

        httpClient = new DefaultHttpClient(clientConnectionManager, httpParams);

        //創建http重新連接的handler
        httpClient.setHttpRequestRetryHandler(new BaseHttpRequestRetryHandler(retriesCount));
    }

    /**
     * 將參數轉化為 List 的集合
     */
    private List parseParams(HashMap params) {

        if (params == null || 0 == params.size()){
            return null;
        }

        List paramsList = new ArrayList(params.size());

        for (Entry entry : params.entrySet()) {
            paramsList.add(new BasicNameValuePair(entry.getKey(), entry.getValue() + ));
        }
        return paramsList;
    }

    /**
     * 向服務器端請求:當請求只有url 沒有參數的時候
     */
    public String post(String url) throws Exception {
        return post(url, null); //調用有參數的時候執行的post並將參數設置為null
    }

    /**
     * post請求之後返回T類型的結果
     */
    public  T post(String url, HashMap params, Class clz) throws Exception {
        String json = post(url, params);
        return JSONUtil.fromJson(json, clz); //轉化為具體的類型返回
    }

    /**
     * 當請求有參數的時候,其他函數間接調用該方法
     */
    public String post(String url, HashMap params) throws Exception {

        //將傳入的參數轉化為參數實體:將params轉化為enrity的對象:表單entity
        UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parseParams(params));

        return request(url, entity).getResponseStreamAsString();

    }

    /**
     * 將post執行的結果直接返回
     */
    public Result postAsResult(String url, HashMap params)throws Exception {
        return post(url, params, Result.class);
    }

    /**
     * 將post執行的結果一Stream的形式返回
     */
    public InputStream postAsStream(String url, HashMap params) throws Exception {

        //將傳入的參數轉化為參數實體
        UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parseParams(params));

        return request(url, entity).getResponseStream();
    }

    public HttpResponseInter request(String url, HttpEntity entity) throws Exception {

        HttpRequestImpl httpRequestImpl = new ExecuteHttpPost(httpClient, url, entity);

        return httpRequestImpl.request();

    }
}

(7)最後一個就是我們在httpClient中使用的一個BaseHttpRequestRetryHandler.java用於實現網絡重復請求的次數

/**
 * http重新嘗試連接:主要用於完成嘗試重新連接
 * @author xuliugen
 */
public class BaseHttpRequestRetryHandler implements HttpRequestRetryHandler {

    private int max_retry_count;// 最大嘗試連接的次數

    public BaseHttpRequestRetryHandler(int maxretryCount) {
        this.max_retry_count = maxretryCount;
    }

    private static HashSet> exceptionWhiteList = new HashSet>();
    private static HashSet> exceptionBlackList = new HashSet>();

    static {
        exceptionWhiteList.add(NoHttpResponseException.class);

        exceptionWhiteList.add(UnknownHostException.class);
        exceptionWhiteList.add(SocketException.class);

        exceptionBlackList.add(SSLException.class);
        exceptionBlackList.add(InterruptedIOException.class);
        exceptionBlackList.add(SocketTimeoutException.class);

    }

    public boolean retryRequest(IOException exception, int executionCount,HttpContext context) {

        if (executionCount > max_retry_count){
            return false;
        }
        if (exceptionBlackList.contains(exception.getClass())){
            return false;
        }
        if (exceptionWhiteList.contains(exception.getClass())){
            return true;
        }

        HttpRequest request = (HttpRequest) context.getAttribute(ExecutionContext.HTTP_REQUEST);
        boolean idempotent = (request instanceof HttpEntityEnclosingRequest);
        if (!idempotent) {
            // 濡傛灉璇鋒眰琚??涓烘槸骞傜瓑鐨勶紝閭d箞灏遍噸璇?
            return true;
        }

        Boolean b = (Boolean) context.getAttribute(ExecutionContext.HTTP_REQ_SENT);
        boolean sent = (b != null && b.booleanValue());

        if (!sent) {
            return true;
        }

        return false;
    }
}

Service和AsyncTask的結合使用

大致流程如下:
這裡寫圖片描述
(1)我們將任務統一的交給Service進行處理,這樣的話我們就需要一個Task實體<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;"> public class Task { private int taskId;// 任務ID private Map taskParams;// 參數 public static final int USER_LOGIN = 1; //自定義的一個任務ID //構造方法和get、set方法省略 }

(2)下邊就是統一管理Task的Service,在Service中我們不僅需要統一的管理Task即是異步任務,我們還需要負責管理更新界面的操作,因為更新界面的操作不能再住UI中進行,所以我們需要統一的管理activity,在Service中,我們執行異步任務的操作使用過Thread和Handler實現的。


public class MainService extends Service implements Runnable {

    // 任務隊列:用於存放任務的隊列
    private static Queue tasks = new LinkedList();

    // 將需要更新的UI添加到集合中
    private static ArrayList appActivities = new ArrayList();

    private boolean isRun;// 是否運行線程

    Handler handler = new Handler() {

        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case Task.USER_LOGIN: {// 用戶登錄 :更新UI
                //根據name找到activity:因為MAinActivity實現了MainActivityInter接口,所以可以強轉為MainActivityInter類型
                MainActivityInter activity = (MainActivityInter) getActivityByName(MainActivity); 
                activity.refresh(msg.obj.toString());
                break;
            }
            default:
                break;
            }
        };
    };

    /**
     * 添加任務到任務隊列中
     */
    public static void newTask(Task t) {
        tasks.add(t);
    }

    @Override
    public void onCreate() {

        isRun = true;
        Thread thread = new Thread(this);
        thread.start();

        super.onCreate();
    }

    /**
     * 讓服務一直遍歷執行
     */
    public void run() {

        while (isRun) { // 去監聽任務
            Task task = null;
            if (!tasks.isEmpty()) { // 判斷隊列中是否有值
                task = tasks.poll();// 執行完任務後把改任務從任務隊列中移除
                if (null != task) {
                    doTask(task); // TO DO :執行任務
                }
            }
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
            }
        }
    }

    // 處理任務
    private void doTask(Task task) {
        Message msg = handler.obtainMessage();
        msg.what = task.getTaskId();

        switch (task.getTaskId()) {
        case Task.USER_LOGIN: { // 用戶登錄
            HashMap paramsHashMap =  (HashMap) task.getTaskParams();

            //訪問網絡,進行判斷用戶是否存在
            String url = http://172.23.252.89:8080/igouServ/userlogin.action;
            BaseHttpClient httpClient = new  BaseHttpClient();
            try {
                String result = httpClient.post(url, paramsHashMap);
                msg.obj= result; //返回到handler進行處理
            } catch (Exception e) {
                e.printStackTrace();
            }

            break;
        }

        default:
            break;
        }

        handler.sendMessage(msg);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * 添加一個Activity對象到集合中
     */
    public static void addActivity(Activity activity) {

        if (!appActivities.isEmpty()) {

            for (Activity ac : appActivities) {
                if (ac.getClass().getName().equals(ac.getClass().getName())) {
                    appActivities.remove(ac);
                    break;
                }
            }
        }
        appActivities.add(activity);
    }

    /**
     * 根據Activity的Name獲取Activity對象
     */
    private Activity getActivityByName(String name) {

        if (!appActivities.isEmpty()) {
            for (Activity activity : appActivities) {
                if (null != activity) {
                    if (activity.getClass().getName().indexOf(name) > 0) {
                        return activity;
                    }
                }
            }
        }
        return null;
    }

    /**
     * 退出系統
     */
    public static void appExit(Context context) {
        // Finish 所有的Activity
        for (Activity activity : appActivities) {
            if (!activity.isFinishing())
                activity.finish();
        }

        // 結束 Service
        Intent service = new Intent(com.xuliugen.frame.task.MainService);
        context.stopService(service);
    }
}

(3)為了可以讓Service統一的管理activity的話,我們可以書寫一個Interface接口MainActivityInter.java有兩個方法,其中一個就是為了刷新界面,以便於我們在service中進行界面的操作

public interface MainActivityInter {

    /**
     * 初始化操作
     */
    public void init();

    /**
     * 刷新UI
     */
    public void refresh(Object... params);
}

測試步驟

(1)創建MainActivity.java 主要是為了模擬一次登錄操作,在這裡邊我們需要開啟服務,差UN該就愛弄一個任務,將任務加到Service管理的任務隊列中去,然後其他的操作就交給MainService.java(Service)進行操作了。

public class MainActivity extends Activity implements MainActivityInter {

    private Button btn_login;
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn_login = (Button) this.findViewById(R.id.btn_login);
        textView=  (TextView) this.findViewById(R.id.textView1);

        // 啟動服務
        Intent serviceIntent = new Intent(this, MainService.class);
        startService(serviceIntent);

        btn_login.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {

                //構造參數傳給Task進行處理
                Map paramsHashMap = new HashMap(2);
                paramsHashMap.put(userName, xuliugen);
                paramsHashMap.put(password, 123456);

                Task task = new Task(Task.USER_LOGIN, paramsHashMap);
                MainService.newTask(task);
            }
        });

        // 將activity放入到activity隊列集合中
        MainService.addActivity(this);
    }

    /******************** 以下兩個方法是MainActivityInter接口中的 ********************/
    public void init() {

    }

    public void refresh(Object... params) {
        //根據返回的參數進行更新UI 
        textView.setText(params[0].toString());
    }

}

這裡寫圖片描述
這裡寫圖片描述

 

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