Getting started with Android (XVII) Android multithreading

Original link: http://www.orlion.ga/670/

1、 Update UI in child thread

Android does not allow the UI to be updated in the sub thread, but only in the main thread. However, sometimes we must perform some time-consuming tasks in the sub thread, and then update the UI according to the running results. In this case, Android provides a set of asynchronous message processing mechanism.

Create the project androidthreaddemo and modify the activity_ main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <Button 
        android:id="@+id/change_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Change Text" />

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="@string/hello_world" 
        android:textSize="20sp"/>

</RelativeLayout>

MainActivity.java:

package ga.orlion.androidthreaddemo;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener{
	
	public static final int UPDATE_TEXT = 1;
	
	private TextView text;
	
	private Button changeText;
	
	private Handler handler = new Handler() {
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case UPDATE_TEXT:
				// 在这里可以进行UI操作
				text.setText("Nice to meet you");
				break;
			default:
				break;
			}
		}
	};
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		text = (TextView) findViewById(R.id.text);
		changeText = (Button) findViewById(R.id.change_text);
		changeText.setOnClickListener(this);
	}
	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.change_text:
			new Thread(new Runnable() {

				@Override
				public void run() {
					Message message = new Message();
					message.what = UPDATE_TEXT;
					handler.sendMessage(message); // 将message对象发送过去
				}
				
			}).start();;
			break;
		default:
			break;
		}
	}

	
}

Here, we first define an integer constant update_ Text, used to indicate the action of updating textview. Then add a handler object and override the handlemessage method of the parent class to process the specific message here. If the value of the what field of the message is found to be equal to update_ Text, change the content displayed in textview to nice to meet you.

Let's take a look at the code in the click event of the change text button. As you can see, instead of directly performing UI operations in the child thread, we created a message (Android. OS. Message) object and specified the value of its what field as update_ TEXT, then call the sendMessage () method of Handler to send the Message. Soon, the handler will receive this message and process it in the handlemessage () method. Note that the code in the handlemessage () method is running in the main thread, so we can safely operate the UI here. Next, judge the value of the what field carried by the message. If it is equal to update_ Text, change the content displayed in textview to nice to meet you.

2、 Parsing asynchronous processing mechanism

Asynchronous processing in Android is mainly composed of four parts: message, handler, messagequeue and looper

1.Message

Message is a message passed between threads. It can carry a small amount of information internally for data exchange between different threads. In the above code, we use the what field of message. In addition, we can also use the arg1 and arg2 fields to carry integer data and the obj field to carry an object object

2.Handler

Handler, as its name implies, means handler. It is mainly used to send and process messages. Sending a message usually uses the handler's SendMessage () method. After a series of tossing and turning, the sent message will eventually be delivered to the handler's handlemessage () method.

3.MessageQueue

Messagequeue means message queue. It is mainly used to store all messages sent through the handler. This part of the message will always exist in the message queue and wait to be processed. There will only be one messagequeue object per thread

4.Looper

Loop is the steward of messagequeue in each thread. After calling loop () method of loop, it will enter an infinite loop. Then, whenever a message is found in messagequeue, it will be taken out and passed to handlemessage () method of handler. There will also be only one looper object per thread.

The whole process of asynchronous message processing: first, you need to create a handler object in the main thread and override the handlemessage () method. Then, when UI operations are required in the child thread, you need to create a message object and send the message through the handler. After that, the message will be added to the queue of messagequeue for processing, while looper will always try to get the message to be processed from messagequeue, and finally distribute it to the handler's handlemessage () method. Since the handler is created in the main thread, the code in the handlemessage () method will also be executed in the main thread.

After a message is called by such a process, it enters the main thread from the sub thread, and it can never be called

Updating the UI becomes the UI that can be updated, which is the core idea of the whole asynchronous message processing.

3、 Using asynctask

Asynctask is an abstract class. During inheritance, we can specify three generic parameters for asynctask class. The purposes of these parameters are as follows:

1.Params

The parameters that need to be passed in when executing asynctask can be used in background tasks

2.Progress

During background task execution, if the current progress needs to be displayed on the interface, the generic specified here is used as the progress unit

3.Result

After the task is executed, if the result needs to be returned, the generic type specified here is used as the return value type

Therefore, the simplest custom asynctask can be written as follows:

class DownloadTask extends AsyncTask<Void , Integer , Boolean>{
}

Here, we specify the first generic parameter of asynctask as void, which means that there is no need to pass in parameters to the background task when executing asynctask. The second release parameter is specified as integer, indicating that integer data is used as the progress display unit. If the third generic parameter is specified as boolean, it means that Boolean data is used to feed back the execution result.

At present, our custom downloadtask is still an empty task and cannot perform any actual operations. We still need to rewrite several methods in asynctask to complete the task customization. There are four methods that often need to be rewritten:

1.onPreExecute()

This method is called before the background task is executed, and it is used for initialization operations on some interfaces, such as displaying a progress bar dialog box.

2.doInBackground(Params…)

All the code in this method will run in the sub thread, and we should deal with all the time-consuming tasks here. Once the task is completed, you can return the task execution result through the return statement. If the third generic parameter of asynctask specifies void, you can not return the task execution result. Note that UI operations are not allowed in this method. If you need to update UI elements, such as feedback on the execution progress of the current task, you can call the publishprogress (Progress...) method to complete it

3.onProgressUpdate(Progress…)

When the publishProgress (Progress...) method is invoked in the background task, this method will be invoked very quickly. The parameters in the method are passed in the background task. In this method, the UI can be operated, and the interface elements can be updated accordingly by using the values in the parameters.

4.onPostExecute(Result)

When the background task is completed and returned through the return statement, this method will be called soon. The returned data will be passed to this method as parameters. You can use the returned data to carry out some UI operations, such as reminding the result of task execution and closing the progress bar dialog box.

Therefore, a complete custom asynctask can be written as follows:

class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
    @Override
    protected void onPreExecute() {
        progressDialog.show(); // 显示进度对话框
    }
    @Override
    protected Boolean doInBackground(Void... params) {
        try {
            while (true) {
                int downloadPercent = doDownload(); // 这是一个虚构的方法
                publishProgress(downloadPercent);
                if (downloadPercent >= 100) {
                    break;
                }
            }
        } catch (Exception e) {
            return false;
        }
        return true;
    }
    @Override
    protected void onProgressUpdate(Integer... values) {
        // 在这里更新下载进度
        progressDialog.setMessage("Downloaded " + values[0] + "%");
    }
    @Override
    protected void onPostExecute(Boolean result) {
        progressDialog.dismiss(); // 关闭进度对话框
        // 在这里提示下载结果
        if (result) {
            Toast.makeText(context, "Download succeeded",            Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(context, " Download Failed",            Toast.LENGTH_SHORT).show();
        }
    }
}

In this downloadtask, we execute the specific download task in the doinbackground () method. The code in this method runs in the child thread, so it will not affect the operation of the main thread. Note that there is a fictional method called download (), which is used to calculate the current download progress and return it. We assume that this method already exists. After getting the current download progress, we should consider how to display it on the interface. Because the doinbackground() method runs in the sub thread, UI operations cannot be performed here, so we can call the publishprogress() method and pass in the current download progress, so the onprogressupdate() method will be called soon, Here you can perform UI operations.

When the download is completed, the doinbackground () method will return a boolean variable, so the onpostexecute () method will be called soon, and this method is also run in the main thread. Then, we will pop up the corresponding toast prompt according to the download results, so as to complete the whole downloadtask task.

To put it simply, the trick of using asynctask is to execute specific time-consuming tasks in the doinbackground () method, perform UI operations in the onprogressupdate () method, and perform the finishing work of some tasks in the onpostexecute () method.

If you want to start this task, just write the following code:

new DownloadTask().execute();

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>