Android使用自己封装的Http和Thread、Handler实现异步任务

目录结构如下:

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<HttpResponseInter> {

    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<BasicNameValuePair> 的集合
     */
    private List<BasicNameValuePair> parseParams(HashMap<String, Object> params) {

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

        List<BasicNameValuePair> paramsList = new ArrayList<BasicNameValuePair>(params.size());

        for (Entry<String, Object> 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> T post(String url, HashMap<String, Object> params, Class<T> clz) throws Exception {
        String json = post(url, params);
        return JSONUtil.fromJson(json, clz); //转化为具体的类型返回
    }

    /**
     * 当请求有参数的时候,其他函数间接调用该方法
     */
    public String post(String url, HashMap<String, Object> params) throws Exception {

        //将传入的参数转化为参数实体:将params转化为enrity的对象:表单entity
        UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parseParams(params));

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

    }

    /**
     * 将post执行的结果直接返回
     */
    public Result postAsResult(String url, HashMap<String, Object> params)throws Exception {
        return post(url, params, Result.class);
    }

    /**
     * 将post执行的结果一Stream的形式返回
     */
    public InputStream postAsStream(String url, HashMap<String, Object> 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<Class<? extends IOException>> exceptionWhiteList = new HashSet<Class<? extends IOException>>();
    private static HashSet<Class<? extends IOException>> exceptionBlackList = new HashSet<Class<? extends IOException>>();

    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实体

public class Task {

    private int taskId;// 任务ID
    private Map<String, Object> 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<Task> tasks = new LinkedList<Task>();

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

    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<String, Object> paramsHashMap =  (HashMap<String, Object>) 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<String, Object> paramsHashMap = new HashMap<String, Object>(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());
    }

}

项目下载地址:https://github.com/xuliugen/HttpAndAsyncTaskFrame

时间: 2024-10-29 02:00:33

Android使用自己封装的Http和Thread、Handler实现异步任务的相关文章

(转载)Android支付宝支付封装代码

Android支付宝支付封装代码 投稿:lijiao 字体:[增加 减小] 类型:转载 时间:2015-12-22我要评论 这篇文章主要介绍了Android支付宝支付封装代码,Android支付的时候肯定会使用支付宝进行支付,封装可以简化操作步骤,感兴趣的小伙伴们可以参考一下 在做Android支付的时候肯定会用到支付宝支付, 根据官方给出的demo做起来非常费劲,所以我们需要一次简单的封装. 封装的代码也很简单,就是将官网给的demo提取出一个类来方便使用. ? 1 2 3 4 5 6 7 8

Android Thread Handler UIHandler demos

extends:http://blog.csdn.net/superjunjin/article/details/7540064 序效果:为了显示如何用message传值的简单例子 例1,点击按钮,持续显示当前系统时间(bundle传值,耗时,效率低) 例2,点击按钮,progressbar持续前进(message方法传值,效率高,但只能传整型int和对象object) 例1,主activity  package com.song; import java.text.SimpleDateForm

Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面

Android应用的开发过程中需要把繁重的任务(IO,网络连接等)放到其他线程中异步执行,达到不阻塞UI的效果. 下面将由浅入深介绍Android进行异步处理的实现方法和系统底层的实现原理. 本文介绍Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面: 即如何使用Thread+Handler的方式从非UI线程发送界面更新消息到UI线程. 概述:每个Android应用程序都运行在一个dalvik虚拟机进程中,进程开始的时候会启动一个主线程(MainThread),

Android主线程、子线程通信(Thread+handler)

Android是基于Java的,所以也分主线程,子线程! 主线程:实现业务逻辑.UI绘制更新.各子线程串连,类似于将军: 子线程:完成耗时(联网取数据.SD卡数据加载.后台长时间运行)操作,类似于小兵: 一.子线程向主线程发消息(Thread+handler): 1.主线程中定义Handler: Java代码   Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.h

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a vi

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views 这个错误相信大家一定不陌生,特别是刚学习android时,会引起的错误,意思是指在子线程中对UI做了操作,现在写个简单的demo: public class MainActivity extends Activity { privat

Android开发之异步具体解释(一)Thread+Handler

请尊重他人的劳动成果,转载请注明出处:  Android开发之异步具体解释(一)Thread+Handler http://blog.csdn.net/fengyuzhengfan/article/details/40211589 在Android实际开发project中常常会进行一些诸如:文件读写.訪问网络等耗时的操作,这些耗时的操作是不建议放到UI线程里的. 所以我们会新开一个线程.在子线程中进行这些耗时的操作.耗时操作过程中.UI常常须要更新,但Android是不同意在子线程中改动UI的.

Android开发之异步详解(一)Thread+Handler

请尊重他人的劳动成果,转载请注明出处:  Android开发之异步详解(一)Thread+Handler http://blog.csdn.net/fengyuzhengfan/article/details/40211589 在Android实际开发工程中经常会进行一些诸如:文件读写.访问网络等耗时的操作,这些耗时的操作是不建议放到UI线程里的.所以我们会新开一个线程,在子线程中进行这些耗时的操作,耗时操作过程中,UI经常需要更新,但Android是不允许在子线程中修改UI的.所以就出现了Th

Android异步处理系列文章四篇之一使用Thread+Handler实现非UI线程更新UI界面

目录: Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面Android异步处理二:使用AsyncTask异步更新UI界面Android异步处理三:Handler+Looper+MessageQueue深入详解Android异步处理四:AsyncTask的实现原理 Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面 概述:每个Android应用程序都运行在一个dalvik虚拟机进程中,进程开始的时候会启动一个主线程(MainTh

Android异步机制一:使用Thread+Handler实现非UI线程更新UI界面

概述:每个Android应用程序都运行在一个dalvik虚拟机进程中,进程开始的时候会启动一个主线程(MainThread),主线程负责处理和ui相关的事件,因此主线程通常又叫UI线程.而由于Android采用UI单线程模型,所以只能在主线程中对UI元素进行操作.如果在非UI线程直接对UI进行了操作,则会报错: CalledFromWrongThreadException only the original thread that created a view hierarchy can tou