Android学习之——并发编程:AsyncTask和UI线程
private final class AsyncInitGame extends AsyncTask<String, void, String> { private final View root; private final Game game; private final TextView message; private final Drawable bg; public AsyncInitGame(View root, Drawable bg, Game game, TextView msg) { this.root = root; this.bg = bg; this.game = game; this.message = msg; } //run on the UI thread //1. 当UI线程调用任务的execute方法时,会首先调用该方法,这里要做的操作时该任务能够对其本身和环境执行初始化,在这个例子中是安装等待启动的背景动画 @Override protected void onPreExecute() { if(0 >= mInFlight++){ root.setBackgroundResouce(R.anim.dots); ((AnimationDrawable)root.getBackground()).start(); } } //runs on the UI thread //3. 当doInBackground方法完成时,就删除背景线程,再在UI线程中调用onPostExecute方法。 @Override protected void onPostExecute(String msg){ if(0 >= --mInFlight){ ((AndimationDrawable)root.getBackground()).stop(); root.setBackgroundDrawable(bg); } message.setText(msg); } //runs on a background thread //2. 在onPreExecute方法完成后AsyncTask创建新的背景线程,并发执行doInBackground方法。 @Override protected String doInBackground(String... args){ return (1 != args.length) || (null == args[0])) ? null : game.initialize(args[0]); } }private final class AsyncInitGame extends AsyncTask<String, void, String> { private final View root; private final Game game; private final TextView message; private final Drawable bg; public AsyncInitGame(View root, Drawable bg, Game game, TextView msg) { this.root = root; this.bg = bg; this.game = game; this.message = msg; } //run on the UI thread //1. 当UI线程调用任务的execute方法时,会首先调用该方法,这里要做的操作时该任务能够对其本身和环境执行初始化,在这个例子中是安装等待启动的背景动画 @Override protected void onPreExecute() { if(0 >= mInFlight++){ root.setBackgroundResouce(R.anim.dots); ((AnimationDrawable)root.getBackground()).start(); } } //runs on the UI thread //3. 当doInBackground方法完成时,就删除背景线程,再在UI线程中调用onPostExecute方法。 @Override protected void onPostExecute(String msg){ if(0 >= --mInFlight){ ((AndimationDrawable)root.getBackground()).stop(); root.setBackgroundDrawable(bg); } message.setText(msg); } //runs on a background thread //2. 在onPreExecute方法完成后AsyncTask创建新的背景线程,并发执行doInBackground方法。 @Override protected String doInBackground(String... args){ return (1 != args.length) || (null == args[0])) ? null : game.initialize(args[0]); } }假设AsyncTask的实现是正确的,我们单击按钮“启动”按钮只需要创建一个实例并调用它,如下所示:
((Button)findViewById(R.id.start)).setOnClickListener( new View.OnClickListener(){ @Override public void onClick(View v){ new AsyncInitGame(root, bg, game, msg).execute("basic"); } } );//注:该文中的代码并不全面,只是为了阐述AsyncTask
public class AsyncDBReq extends AsyncTask<PreparedStatement, Void, ResultSet> { @Override protected ResultSet doInBackground(PreparedStatement...q){ //implementation..... } @Override protected onPostExecute(ResultSet result){ //implementation } } public class AsyncHttpReq extends AsyncTask<HttpRequest, Void, HttpResponse> { @Override protected HeepResponse doInBackground(HttpRequest.....req){ //implementaion..... } @Override protected void onPostExecute(HttpResponse result){ //implementaion } }第一个类,AsyncDBReq实例的execute方法参数是一个或者多个PreparedStatement变量。
//易犯错误一、 //....some clas int mCOunt; public void initButton1(Button button){ mCOunt = 0; button.setonClickListener( new View.OnClickListener(){ @SuppressWarnings("unchecked") @Override public void onCLick(View v){ new AsyncTask<Void, Void, Void>(){ @Override protected Void doInBackground(Void...args){ mCount++; //!!! not thread safe!! return null; } }.execute(); }}); }这里在编译时不会产生编译错误,也没有运行警告,可能甚至在bug被触发时也不会立即失败,但该代码绝对是错误的。有两个不同的线程访问变量mCount,而这两个线程之间却没有执行同步。
//易犯错误二、 public void initButton(Button button, final Map<String, String> vals){ button.setOnClickListener( new View.OnClickListener(){ @Override public void onClick(View v){ new AsyncTask<Map<String, String>, Void, Void>(){ @Override protected Void doInBackground(Map<String,String>...params){ //implementation, uses the params Map } }.execute(vals); vals.clear();//this is not thread safe!!!! }}); }错误原因:initButton的参数valse被并发引用,却没有执行同步!!!当调用AsyncTask时,它作为参数传递给execute方法。syncTask框架可以确保当调用doInBackground方法时,该引用会正确地传递给后台线程。但是对于在initButton方法中所保存并使用的vals引用,却没有办法处理。调用vals.caear修改了在另一个线程上正在使用的状态,但没有执行同步。因此,不是线程安全的。
public class AsyncTaskDemoWithProgress extends Activity{ private final class AsyncInit extends AsyncTask<String, Integer, String> implements Game.InitProgressLIstener { private final View root; private final Game game; private final TextView message; private final Drawable bg; public AsyncInit(View root, Drawable bg, Game game, TextView msg){ this.root = root; this.bg = bg; this.game = game; this.message = msg; } //run on the UI thread //1. 当UI线程调用任务的execute方法时,会首先调用该方法 @Override protected void onPreExecute() { if(0 >= mInFlight++){ root.setBackgroundResouce(R.anim.dots); ((AnimationDrawable)root.getBackground()).start(); } } //runs on the UI thread //3. 当doInBackground方法完成时,就删除背景线程,再在UI线程中调用onPostExecute方法。 @Override protected void onPostExecute(String msg){ if(0 >= --mInFlight){ ((AndimationDrawable)root.getBackground()).stop(); root.setBackgroundDrawable(bg); } message.setText(msg); } //runs on its own thread //2. 在onPreExecute方法完成后AsyncTask创建新的背景线程,并发执行doInBackground方法。 @Override protected String doInBackground(String... args){ return (1 != args.length) || (null == args[0])) ? null : game.initialize(args[0]); } //runs on its UI thread @Override protected void onProgressUpdate(Integer... vals){ updateProgressBar(vals[0].intValue()); } //runs on the UI thread @Override public void onInitProgress(int pctComlete){ //为了正确地给UI线程发布进程状态,onInitProgress调用的是AsyncTask的publicProgress。 //AsyncTask处理UI线程的publicProgress调度细节,从而onProgressUpdate可以安全地使用View方法。 publicProgress(Integer.valueOf(pctComplete)); } } int mInFlight,mComplete; /** @see android.app.Activity#onCreate(android.os.Bundle) */ @Override public void onCreate(Bundle state){ super.onCreate(state); setContentView(R.layout.asyncdemoprogress); final View root = findViewById(R.id.root); final Drawable bg = root.getBackground(); final TextView msg = ((TextView)findViewById(R.id.msg)); final Game game = Game.newGame(); ((Button)findViewById(R.id.start)).setOnClickListener( new View.OnClickListener(){ @Override public void onCLick(View v){ mComplete=0; new AsyncInit(root, bg, game, msg).execute("basic"); }}); } void updateProgressBar(int progress){ int p = progress; if(mComplete < p){ mComplete = p; (ProgressBar)findViewById(R.id.progress)).setprogress(p); } } }.......嗯,其实还没结束,来个总结:
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。