Android利用Thread或AsyncTask进行非UI操作

在Android中调用一些操作,如网络请求,必须强制使用非UI线程,如果在UI线程当中调用就会报错!

因此,线程操作是Android当中使用非常普遍,在线程中进行对应操作,最后把结果回传给UI线程,由UI线程进行结果的显示!

这里介绍两种线程操作!

 1、Thread+Handler

这种方法是最原始,也是最灵活的方式,完全没有被封装,但是使用起来相对也复杂一些!

主要的步骤为:

1)创建Handler,用于接收线程完成后回传的结果

private Handler resultHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            
            // 关闭加载控件
            if(progressDialog != null && progressDialog.isShowing()) {
                    progressDialog.dismiss();
            }
            
            // 处理返回结果
            if(msg.what == 0) {
              // 调用成功,显示结果
              ResultData resultData = (ResultData) msg.obj;
              
              tv_name.SetText(resultData.name);
            }
            else {
                // 调用失败
                String err = (String) msg.obj;
                
                Toast.makeText(context, err, Toast.LENGTH_SHORT).show();
            }
        }
}

 

 

2)创建Thread,在当中进行耗时操作

// 调用前显示加载控件
progressDialog = ProgressDialog.show(ReservationListActivity.this, "提示", "正在加载数据...");

// 开始线程并加载数据
new Thread(new Runnable() {
            
            @Override
            public void run() {
                // 线程处理过程
                ...
                
                // 返回成功结果
                ResultData resultData = new ResultData();
                resultData.name = "张三";
                
                Message msg = Message.obtain();
                msg.what = 0;
                msg.obj = resultData;
                resultHandler.sendMessage(msg);
                
                
                // 返回失败结果
                Message msg = Message.obtain();
                msg.what = -1;
                msg.obj = "结果不存在";
                resultHandler.sendMessage(msg);
            }
        }).start();

 

这种方法其实比较简单,通过Thread执行耗时操作,在操作完成后,向Handler发送消息,同时把结果传递进去;

之后Handler接收到传递过来的消息,根据消息的内容进行不同的处理,如成功、失败等!

多个Thread的返回可以共用一个Handler,只需要在结果那里处理好区分即可。

也有许多人将此操作封装成一个类,这样调用起来更简便,原理是一样的。

 

 

2、AsyncTask

 

这种方法是Google推荐的方法,原理与Thread+Handler类似,但是Google进行了封装,使用起来更方便一些。

使用时,需要对AsyncTask进行继承,其原型为:AsyncTask<Params,Progress,Result>,这里需要说明一下:

Params        启动任务时输入的参数类型

Progress      后台任务执行中返回进度值的类型

Result          后台任务执行完成后返回结果的类型

这样传参,进度,返回都已经包含在内了,如果传参,返回的数据较复杂,可定义为类进行传输

AsyncTask主要的重载函数包括:

doInBackground      必须重写,异步执行后台线程要完成的任务,耗时操作将在此方法中完成.

onPreExecute          执行后台耗时操作前被调用,通常用于进行初始化操作.

onPostExecute        当doInBackground方法完成后,系统将自动调用此方法,并将doInBackground方法返回的值传入此方法.通过此方法进行UI的更新.

onProgressUpdate  当在doInBackground方法中调用publishProgress方法更新任务执行进度后,将调用此方法.通过此方法我们可以知晓任务的完成进度.

一般我们只需要用到 doInBackground 和 onPostExecute。

// 调用前显示加载控件
progressDialog = ProgressDialog.show(ReservationListActivity.this, "提示", "正在加载数据...");

// 这里定义输入参数为String类型,输出参数为ReaultData类型
new AsyncTask<String, Void, ReaultData>(){
    
            // 在后台执行的过程函数,所有耗时操作放在此函数中执行
            @Override
            protected AsyncFilesData doInBackground(String... params) {
                // params 即传入的参数,此例中就是 "http://www.abc.com/api/getinfo?id=10"
                url = params[0];
                
                // 定义返回结果对象
                ResultData resultData = new ReaultData();
                
                try {
                    String str = geturl(url);
                    resultData = JSONObject.parseObject(str, ResultData.class);
                    return resultData;
                }
                catch(Exception ex) {
                    resultData.result = -1;
                    resultData.msg = ex.getMessage();
                    return resultData;
                }
            }
            
            
            // doInBackground返回结果后会自动调用此函数
            // 此函数是在 UI 线程当中被调用,因此可将对UI的操作放在当中执行
            @Override
            protected void onPostExecute(ResultData resultData) {
                // 关闭加载控件
                if(progressDialog != null && progressDialog.isShowing()) {
                        progressDialog.dismiss();
                }
                
                // 处理返回结果
                if(resultData.result == 0) {
                  // 调用成功,显示结果
                  tv_name.SetText(resultData.name);
                }
                else {
                    // 调用失败
                    String err = resultData.msg;
                    
                    Toast.makeText(context, err, Toast.LENGTH_SHORT).show();
                }
            }
            // 传入的参数是调用一个Webapi获取指定ID的info
        }.execute("http://www.abc.com/api/getinfo?id=10");    

AsyncTask的优势是书写简单,且 onPostExecute 已在UI线程当中,不必再处理线程向UI线程同步问题。

 

这就是今天介绍的两种线程调用同步方法!

 

 

 

posted on 2018-11-28 16:29  cexoboy  阅读(155)  评论(0)    收藏  举报