Open fred-ye opened 10 years ago
在Android项目中难免会涉及到一些比较耗时的操作,如从网络上取数据,读本地的文件等等。Android 也推荐我们去新开一个线程完成这些操作,而不要在主线程中执行。当这些操作完成之后再调用主线程去更新UI。很明显当....之后.....这种类型的逻辑便是一个回调的模式。本文以一个从网络上取数据的例子来解释如何应用回调机制来实现一种比较好的设计。
Android
当....之后.....
Android中对比较耗时的操作通常采用两种方式来实现,一种是利用Thread + Handler,新开一个Thread去处理操作,操作完成后,采用handler发送message,然后更新UI。另一种方式是采用AsyncTask来实现,在AsyncTask中的doInBackground方法中去完成耗时的操作,当然这个方法中的代码会运行在另一个线程中。操作完成后在onPostExecute方法中进行UI的更新操作。两种方式无好坏之分,但个人倾向于采用AsyncTask的实现方式,觉得更简洁清晰一些。
Thread + Handler
Thread
handler
message
AsyncTask
doInBackground
onPostExecute
UI
直接上代码:
public interface IFeedback { boolean onFeedback(String key, boolean isSuccess, Object object); }
GetBookTask
public class GetBookTask extends AsyncTask<String, Void, Object> { public static final String TAG = GetBookTask.class.getSimpleName(); public static final String FEED_BACK_KEY = "GetBookTask"; private IFeedback feedback; private boolean isSuccess = false; public GetBookTask(IFeedback feedback) { this.feedback = feedback; } @Override protected Object doInBackground(String... params) { Log.i(TAG, "task executing...."); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } isSuccess = true; return null; } protected void onPostExecute(Object result) { super.onPostExecute(result); feedback.onFeedback(FEED_BACK_KEY, this.isSuccess, result); } } GetFookTask public class GetFoodTask extends AsyncTask<String, Void, Object> { public static final String TAG = GetFoodTask.class.getSimpleName(); public static final String FEED_BACK_KEY = "GetFoodTask"; private IFeedback feedback; private boolean isSuccess = false; public GetFoodTask(IFeedback feedback) { this.feedback = feedback; } @Override protected Object doInBackground(String... params) { Log.i(TAG, "task executing...."); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } isSuccess = true; return null; } protected void onPostExecute(Object result) { super.onPostExecute(result); feedback.onFeedback(FEED_BACK_KEY, this.isSuccess, result); } } Activity类
public class GetBookTask extends AsyncTask<String, Void, Object> { public static final String TAG = GetBookTask.class.getSimpleName(); public static final String FEED_BACK_KEY = "GetBookTask"; private IFeedback feedback; private boolean isSuccess = false; public GetBookTask(IFeedback feedback) { this.feedback = feedback; } @Override protected Object doInBackground(String... params) { Log.i(TAG, "task executing...."); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } isSuccess = true; return null; } protected void onPostExecute(Object result) { super.onPostExecute(result); feedback.onFeedback(FEED_BACK_KEY, this.isSuccess, result); } }
GetFookTask
public class GetFoodTask extends AsyncTask<String, Void, Object> { public static final String TAG = GetFoodTask.class.getSimpleName(); public static final String FEED_BACK_KEY = "GetFoodTask"; private IFeedback feedback; private boolean isSuccess = false; public GetFoodTask(IFeedback feedback) { this.feedback = feedback; } @Override protected Object doInBackground(String... params) { Log.i(TAG, "task executing...."); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } isSuccess = true; return null; } protected void onPostExecute(Object result) { super.onPostExecute(result); feedback.onFeedback(FEED_BACK_KEY, this.isSuccess, result); } }
Activity
public class MainActivity extends Activity { public static final String TAG = MainActivity.class.getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new GetBookTask(feedback).execute(new String[]{""}); new GetFoodTask(feedback).execute(new String[]{""}); } private final IFeedback feedback = new IFeedback(){ @Override public boolean onFeedback(String key, boolean isSuccess, Object object) { if (GetBookTask.FEED_BACK_KEY.equals(key)) { if (isSuccess) { Log.i(TAG, "GetBookTask execute success and update UI"); return true; } } if (GetFoodTask.FEED_BACK_KEY.equals(key)) { if(isSuccess) { Log.i(TAG, "GetFoodTask execute success and update UI"); return true; } } return false; } }; }
总结一下
IFeedback
onFeedback
String
Object
FEED_BACK_KEY
feedback
isSuccess
Task
new Thread() { @Override public void run() { try { HttpResponse response = new DefaultHttpClient().execute(new HttpGet("http://www.baidu.com")); //parse response feedback.onFeedback(key, isSuccess, object); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }.start();
在
Android
项目中难免会涉及到一些比较耗时的操作,如从网络上取数据,读本地的文件等等。Android
也推荐我们去新开一个线程完成这些操作,而不要在主线程中执行。当这些操作完成之后再调用主线程去更新UI。很明显当....之后.....
这种类型的逻辑便是一个回调的模式。本文以一个从网络上取数据的例子来解释如何应用回调机制来实现一种比较好的设计。Android
中对比较耗时的操作通常采用两种方式来实现,一种是利用Thread + Handler
,新开一个Thread
去处理操作,操作完成后,采用handler
发送message
,然后更新UI。另一种方式是采用AsyncTask
来实现,在AsyncTask
中的doInBackground
方法中去完成耗时的操作,当然这个方法中的代码会运行在另一个线程中。操作完成后在onPostExecute
方法中进行UI
的更新操作。两种方式无好坏之分,但个人倾向于采用AsyncTask
的实现方式,觉得更简洁清晰一些。直接上代码:
AsyncTask
的设计GetBookTask
总结一下
IFeedback
中只有一个回调方法onFeedback
,该方法有三个参数,第一个参数的类型是String
,用来区分是哪一个AsyncTask
的回调;第二个参数是用来表示对应的AsyncTask
的执行是否成功了;第三个参数是一个Object
,代表的是AsyncTask
执行后返回给主线程的数据。AsyncTask
的设计:每个AsyncTask
中多了三个属性,分别是FEED_BACK_KEY
,feedback
对象,状态标志位isSuccess
。将一个feedback
对象作为构造函数的参数传递给AsyncTask
,默认将FEED_BACK_KEY
的值设置为Task
的类名,在AsyncTask
的doInBackground
方法中根据执行情况设置isSuccess
的值,在onPostExecute
中调用回调接口的onFeedback
方法,将对应的三个属性值作为参数传递进去。Activity
中,由于一个Activity
可能会调用多个AsyncTask
,此时FEED_BACK_KEY
的作用就体现出来了。根据FEED_BACK_KEY
来判断是哪一个Task
的回调。onFeedback
方法执行的线程)。特别是,如果onFeedback
方法中有刷UI的操作,那就更要注意。在本文中onFeedback
方法的调用是在AsyncTask
类中的onPostExecute
方法中,而这个方法是在主线程中运行,所以刷UI不会有任何问题。但有可能存在着这么一种情况,onFeedback
方法的调用不是在主线程中运行,而是在某个子线程中运行,而此时onFeedback
方法中又包含了刷UI的操作,那么问题就大的。这一点是值得注意的。如下方代码新开一个线程从Server拿数据,拿 到数据后,直接调onFeedback
方法,此时的onFeedback
方法是在这个新线程中运行的,如果这个方法中有刷UI的操作,那就不好玩了。