转 如何优雅的停止线程:http://www.cnblogs.com/l2rf/p/5566895.html
Android规定只有ui线程,也就是主线程才可以刷新UI,这样的规定的原因是UI操作是非线程安全的,如果允许多个线程同时执行ui操作,就必要加同步,而同步机制会影响执行性能,因为在同步中去wait或notify一个线程,通常都要借助操作系统来完成,所以存在用户线程跟内核线程之间的切换,这个切换是很好资源的。
所以,耗时的操作通常都是新启一个线程执行,这个新启的线程通常在主线程中创建,新启的线程会关联到主线程的消息队列,也即是Looper.getMainLooper()方法的结果。
Looper中是带有一个消息队列的即MessageQueue,MessageQueue是用来存放通过handler发送的消息的。
它的handler是在主线程中创建,它的handleMessage方法运行在主线程中,handler可以发送或处理一个消息或一个runnable实例,每个handler都与唯一的一个线程及该线程的消息队列关联。
程序组件通过handler把消息传给looper,looper把消息放入消息队列,同时looper也把消息队列中的消息分发给相应的handler来处理,通常每个消息都带有一个target对象,这是target是handler类型的,handler收到消息后会调用handleMessage处理,handler是在ui线程中创建的,所以它的handleMessage也是属于ui线程的,这样就可以在这个handlemessage中访问ui组件。
为什么要使用AsyncTask?使用handler,thread,messagequeue机制,完全可以实现Asynctask的功能,只是要自己管理线程类。使用Asynctask,在子线程跟UI线程的交互处理上更简洁。
1,
测试代码:
public class MainActivity extends AppCompatActivity {
String TAG= "First-Activity";
Button btn_cancel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button)findViewById(R.id.start_activity);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
lunchNewThread();
}
});
btn_cancel = (Button)findViewById(R.id.btn_cancel);
Log.d(TAG,"recycle,,onCreate");
}
private void lunchNewThread(){
new Thread(){
@Override
public void run() {
Message msg = Message.obtain(msgHandler);
msg.obj = "from sub thread";
msgHandler.sendMessage(msg);
}
}.start();
}
Handler msgHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
btn_cancel.setText(msg.obj.toString());
}
};
}
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.firstapp.linjw.myapplication_n.MainActivity">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:layout_editor_absoluteX="18dp"
tools:layout_editor_absoluteY="6dp"
android:layout_marginLeft="8dp"
tools:ignore="MissingConstraints">
<Button
android:id="@+id/start_activity"
android:layout_width="148dp"
android:layout_height="48dp"
android:text="start-activity"
tools:layout_editor_absoluteX="39dp"
tools:layout_editor_absoluteY="113dp" />
<Button
android:id="@+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="cancel"
tools:ignore="MissingConstraints"
tools:layout_editor_absoluteX="261dp"
tools:layout_editor_absoluteY="6dp" />
</LinearLayout>
</android.support.constraint.ConstraintLayout>
测试结果,点击 start_activity 按钮后, btn_cancel 按钮的文字由 "cancel"变为 from sub thread。
2,AsyncTask 通常需要实现的方法:
onPreExecute(),该方法在执行实际的后台操作前被UI线程调用,运行在UI线程,可以在这个方法中做些准备工作。
doInBackgroud(object[]params),在方法onPreExecute执行后马上执行,该方法运行在后台线程,这里负责执行耗时的操作。其中的参数是通过execute调用时传递的,这个方法中可以调用publishProgress方法发布在UI线程中的更新。
publishProgress(Progress…values),跟新实时的任务进度,每次调用都会触发onProgressUpdate方法的执行。如果task被取消了,onProgressUpdate就不会被调用了。其中参数就是更新ui用到的。
onProgressUpdate(Progress…values),在publishProgress方法被调用后,UI线程将调用这个方法在界面上展示任务的进展情况。运行在UI线程,其中的参数是通过publishProgress方法传递的。
onPostExecute(Resultresult),在doInBackground执行完成后,onPostExecute方法将被UI线程调用,后台的计算结果将通过这个方法传递到UI线程。
Asynctask实例必须要在UI线程创建,其execute方法也必须在UI线程中调用,只需要调用手动调用execute方法,其他方法不用手动调用,而且execute只能被执行一次,这个方法的返回值是Asynctask自身,以方便调用者保存对它的引用。
public finalAsyncTask<Params,Progress,Result> execute(Params... params) {}
execute这个方法会在一个单独的后台线程中或者在一个依赖与平台版本的线程池中,调度这个task,当第一次引用时,Asynctask在一个单独的后台线程中被串行地执行。
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
如果想并行地执行,可是使用executeOnExecutor方法,同时带有参数AsyncTask.THREAD_POOL_EXECUTOR,
也可以通过方法AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);设置task的执行方式。
测试代码:
沿用上面的测试代码,把onClick中的执行函数改为:
protected void startAsyncTask(){
if(mAsyncTaskDemo == null) {
mAsyncTaskDemo = new AsyncTaskDemo();
}
Debug.startMethodTracing("AsyncTaskDemo");
mAsyncTaskDemo.execute("test AsyncTask");
}
public class AsyncTaskDemo extends AsyncTask<String,Integer,String>{
private static final String TAG = "AsyncTaskDemo";
@Override
protected String doInBackground(String[] params) {
Log.d(TAG,"doInBackground(),params="+params[0]);
return params[0]+"after doInBackgroud";
}
@Override
protected void onPreExecute() {
Debug.stopMethodTracing();
Log.d(TAG,"onPreExecute()");
super.onPreExecute();
}
@Override
protected void onPostExecute(String str) {
Log.d(TAG,"onPostExecute(),str="+str);
super.onPostExecute(str);
}
@Override
protected void onProgressUpdate(Integer[] values) {
Log.d(TAG,"onProgressUpdate(),values="+values[0].toString());
super.onProgressUpdate(values);
}
}
Asynctask是一个泛型类,
AsyncTask<
Params,
Progress,
Result>,第一个参数是execute方法的执行参数类型,第二个参数是进度更新参数的类型,第三个参数是返回结果的参数类型。
运行结果:
01-26 22:24:45.287 12377-12377/com.firstapp.linjw.myapplication_n D/AsyncTaskDemo: onPreExecute()
01-26 22:24:45.288 12377-12432/com.firstapp.linjw.myapplication_n D/AsyncTaskDemo: doInBackground(),params=test AsyncTask
01-26 22:24:45.289 12377-12377/com.firstapp.linjw.myapplication_n D/AsyncTaskDemo: onPostExecute(),str=test AsyncTaskafter doInBackgroud