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线程同步问题。
这就是今天介绍的两种线程调用同步方法!
浙公网安备 33010602011771号