AsyncTask探究2

叁叁肆2018-09-21 11:28


本文来自网易云社区

作者:孙有军


前一篇文章中我们探究了AsyncTask的执行流程,那这一篇里面就写一个小的demo,来尝试一下AsyncTask的调用。
1:布局文件:


  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.toolbox.suspend.SuspendActivity" >

<TextView
android:id="@+id/async_task"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20dip"
android:background="@drawable/g_green_btn_selector"
android:gravity="center"
android:padding="10dip"
android:text="@string/async_task"
android:textColor="@color/white_color"
android:textSize="16sp" />

<TextView
android:id="@+id/async_task_thread"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20dip"
android:background="@drawable/g_green_btn_selector"
android:gravity="center"
android:padding="10dip"
android:text="@string/async_task_thread"
android:textColor="@color/white_color"
android:textSize="16sp" />

<TextView
android:id="@+id/async_task_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20dip"
android:background="@drawable/g_green_btn_selector"
android:gravity="center"
android:padding="10dip"
android:text="@string/async_task_result"
android:textColor="@color/white_color"
android:textSize="16sp" />

</LinearLayout>


2:页面代码
public class AsyncTaskActivity extends ActionBarActivity implements OnClickListener {

TextView result;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.async_task_activity);
findViews();
setViewListener();
}

private void findViews() {
result = (TextView) findViewById(R.id.async_task_result);
}

private void setViewListener() {
findViewById(R.id.async_task).setOnClickListener(this);
findViewById(R.id.async_task_thread).setOnClickListener(this);
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.async_task:
startAsyncTask(3);
break;
case R.id.async_task_thread:
startAsyncTask2();
default:
break;
}

}

private void startAsyncTask2() {
Thread thread = new Thread(new Runnable() {

@Override
public void run() {
startAsyncTask(5);
}
});
thread.start();
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB) private void startAsyncTask(int value) {
AsyncTask<Integer, Void, Integer> task = new AsyncTask<Integer, Void, Integer>() {

@Override
protected Integer doInBackground(Integer... params) {
return params[0] * params[0];
}
@Override
protected void onPostExecute(Integer result) {
Toast.makeText(AsyncTaskActivity.this, "Current Value = " + result, Toast.LENGTH_LONG).show();
setTextValue("Current Value =" + result);
}
};
if (Build.VERSION.SDK_INT >= 11) {
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,value);
} else {
task.execute(value);
}
}

private void setTextValue(String text) {
result.setText(text);
}

@Override
protected void onDestroy() {
super.onDestroy();
}
}


代码中有两处调用AsyncTask的地方:
一处是在UI线程中进行调用的,另一处是新开了一个线程,在新的线程中进行调用的,第一种显而易见执行完毕可以更新UI界面,但是第二种呐?这就引出了今天的话题,在另外一个线程中调用AsyncTask会出现什么情况?
这儿主要是有两个问题:1,能否在其他线程中调用AsyncTask,2:如果可以调用,它能更新界面吗?如果能,为什么在新开的线程中可以更新界面,下面逐步解答者两个问题:
A1:可以在其他线程中调用AsyncTask
A2:它能更新UI界面,下面我们详细说说为什么能更新UI界面,正常情况下,一个线程都对应了一个Hander,每个Hander对应一个Looper,我们上面新开了一个线程,如要使用Handler,就要调用Looper.prepare()函数,因为UI线程在ActivityThread起来的时候已经调用了prepare函数,所以在程序中我们不需要再次调用,但是AsyncTask函数中并没有任何地方调用Looper.prepare(),同时它还能更新界面就说明了这个Looper就是使用的MainLooper。我们看到AsyncTask中有一个init函数

public static void init() {
sHandler.getLooper();
}

这个Looper就是MainLooper,但是init这个函数是在什么地方调用的呐?如果是MainLooper那应该就是在UI线程中调用的,那又在UI线程的什么地方进行调用的呐?
public static void main(String[] args) {
5107 SamplingProfilerIntegration.start();
5108
5109 // CloseGuard defaults to true and can be quite spammy. We
5110 // disable it here, but selectively enable it later (via
5111 // StrictMode) on debug builds, but using DropBox, not logs.
5112 CloseGuard.setEnabled(false);
5113
5114 Environment.initForCurrentUser();
5115
5116 // Set the reporter for event logging in libcore
5117 EventLogger.setReporter(new EventLoggingReporter());
5118
5119 Security.addProvider(new AndroidKeyStoreProvider());
5120
5121 Process.setArgV0("<pre-initialized>");
5122
5123 Looper.prepareMainLooper();
5124
5125 ActivityThread thread = new ActivityThread();
5126 thread.attach(false);
5127
5128 if (sMainThreadHandler == null) {
5129 sMainThreadHandler = thread.getHandler();
5130 }
5131
5132 AsyncTask.init();
5133
5134 if (false) {
5135 Looper.myLooper().setMessageLogging(new
5136 LogPrinter(Log.DEBUG, "ActivityThread"));
5137 }
5138
5139 Looper.loop();
5140
5141 throw new RuntimeException("Main thread loop unexpectedly exited");
5142 }
5143}
我们查看ActivityThread的main函数中调用了AsyncTask.init(),由此可以知道确实是在UI线程中进行调用的,因此在其他线程中调用AsyncTask,最终是与UI线程进行通信的。因此也能对界面进行更改。

网易云免费体验馆,0成本体验20+款云产品!

更多网易研发、产品、运营经验分享请访问网易云社区