Programming from 51 years old Note Thread summary

Multithreaded summary is here

Um

I'm afraid, so in a nutshell, a memo of multi-thread processing

■ ** Thread ** class extension | ** Runnable ** interface inheritance ** Communication with UI thread **   view#post(Runnable)   View#postDelayed(Runnable.long)   runOnUiThread(Runnable) ■ ** AsyncTask ** class ** Processing and UI thread communication ** With execute (), doInBackground (), postExecute (), etc. ■ ** Handler ** class ** Realizes communication between multiple threads (OK even if it is not a UI thread) **   Message   Runnable

■Thread(Thread/Runnable) Android now runs on one Linux process, using one thread. This thread is called a single thread, and MainActivity.java runs in a single thread. Here, the thread in which MainActivity runs is called the main thread and is described. Only the main thread can handle UI parts directly, and to operate UI parts from other threads, a dedicated method is used.

MainActivity plays the role of an interface operated by the user, so if the main thread performs time-consuming processing, the operation screen will become unresponsive or the overall processing will slow down, making it difficult to use. It ends up.

Therefore, in order to maintain the ease of use of the application, design the processing that is not related to user operation to be processed separately using another thread (multithread). It seems that separate thread processing is performed using either the Thread class or the Runnable interface.

** ** Thread is a "public class Thread extends Object implements Runnable", which is a class that inherits Runnable. Runnable is "public interface Runnable". If you want to use the constants and methods of the Thread class, extend the Thread class! If not, why not inherit Runnable? Does that mean?

Since another thread is also processed on the same Linux process as the main thread, if there is a problem with a single process, consider launching another Linux process (multi-process) and creating another thread as needed. You may (Manifest.java).

□Thread

In a subclass of Thread


public void onCreate(){
       SubThread subThread = new SubThread();
       subThread.start();
}

class SubThread extends Thread{
      public void run(){
             // todo
      }
}

□Runnable Although it is a description of Runnable, there are three familiar description methods.

Anonymous functional


new Thread(new Runnable(){
    @Override 
    public void run(){
           // todo
    }
}).start();

Using an instance of Thread


public void onCreate(){
       MyRunnable myRunnable = new MyRunnable();
       Thread     thread     = new Thread(myRunnable);
       Thread.start();
}

class MyRunnable implement Runnable{
      @Override 
      public void run(){
             // todo
      }
}

Call Thread class directly


public void onCreate(){
       Thread thread = new Thread(MyRunnable());
}

class MyRunnable implement Runnable{
      @Override 
      public void run(){
             // todo
      }
}

Thread stop processing

--Thread running on Service --If there is Service, Service will not be started twice. --Stop with cancel ()

MainActivity.java



@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //Get the start and stop button objects!
    Button btn_start = findViewById(R.id.btn_start);
    Button btn_stop  = findViewById(R.id.btn_stop);
    
    final Intent intent = new Intent(this,MyService.class);
    btn_start.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view) {
            
            //If MyService is not started, start it!
            if(!MyService.serviceState) {
                startForegroundService(intent);
            }
        }
    });

    btn_stop.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view) {
            // stopService()So, I'll call onDestroy of MyService ~
            stopService(intent);
        }
    });
}

MyService.java



public class MyService extends Service {

    // serviceState =If true, MyService has already started
    // threadState  =If true, Thread will continue to run
    static boolean serviceState;
    boolean threadState;

    public MyService() {
        serviceState = true;
        threadState  = true;
    }

    @Override
    public int onStartCommand(Intent intent,int flags,int startId){

        //Set up Notification content!
        Notification notification;
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this,"id");
        notification = builder.setSmallIcon(R.drawable.notification_icon)
                              .setContentTitle("sanple")
                              .setContentText("text")
                              .build();

        //Set the Notification channel and importance!
        int importance = NotificationManager.IMPORTANCE_LOW;
        NotificationChannel channel = new NotificationChannel("id","name",importance);
        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(channel);
        startForeground(1,notification);

        //Start the thread!
        new Thread(new Runnable() {
            @Override
            public void run() {
                int count = 0;

                //Run the count log every 2 seconds while threadState is true.
                while(threadState){
                    Log.d("msg",String.valueOf(count));

                    try {
                        sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count++;
                }

            }
        }).start();

        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy(){
        Log.d("msg","onDestroy");

        //StopService in MainActivity()When you call onDestroy()Is called
        //MyService is stopped, Thread is also set to stopped
        serviceState = false;
        threadState  = false;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

Thread discard, forced termination

Thread destruction (stop ()) is deprecated from API15. That said, even before that, there was a code need such as wanting to destroy Thread or forcibly terminating it, and I also recommended code that can be destroyed. However, it has been deprecated since API15. This is because thread discard leaves a lot of bad trash.

When Thread is running normally, protected objects can become unstable due to Thread discard, which can lead to unexpected behavior. Since it is difficult to find and identify objects that have been released from Thread, let's consider whether to design a program with interrupt () without discarding Thread, and from API 15 the thread is forcibly terminated. It has been deprecated. For cute and cute apps (and for users who love your app), please do not use Thread.stop () and use interrupt () to design your code!

If you still like stop ()! So, isn't it good to use it so that there are no missing people (objects, etc.)?

■ Communication between Threads

□ UI thread <-worker thread □ Worker thread <-Worker thread

□ Inter-thread communication (Handler: Looper and Queue)

Handle is a class that communicates between threads, and the thread that created the Handle instance has the functions of Queue and Looper required for communication. Information sent from other threads is stored in a queue, and Looper retrieves the stored information and processes it in the main thread (since it is processed in the main thread, UI parts can also be operated).

□ Communicate from worker thread to UI thread

It seems that UI parts cannot be operated directly from the worker thread, so use the methods and classes for operating the UI parts to act as if the operation processing of the UI parts is passed to the UI thread.

  • View.post(Runnable)
  • View.postDelayed(Runnable,long)
  • Activity.runOnUiThread(Runnable) --Handler class --Asynchronous processing of AsyncTask class

The method of manipulating View using View.post becomes difficult to maintain when the operation becomes complicated </ font>. There is also a way to use Handle in the worker thread, but AsyncTask is recommended for reference.

View.post () and View.postDelayed (), both methods on the View object. Post () from different View (TextView.post () or Button.Post ()) will be received as the same View.post () on the receiving queue side (identify the sender as TextView or EditText) Not).

・ View.post ()

public boolean post(Runnable action)

View class methods: Like TextView.post, TextEdit.post (), Button.post (), view parts can use post () and postDelayed () methods. post adds Runnable to the message queue and processes Runnable in the UI thread. If the Runnable process is successful, it will return true. If false, it seems that there are many cases where the message queue has ended.

Post in Thread class

activity_main.xml


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:id="@+id/textView"
        />

Using the Thread class


public class MainActivity extends AppCompatActivity {

    public static TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView) findViewById(R.id.textView);
        
        //Instantiate and start Thread class
        ThreadSample threadSample = new ThreadSample();
        threadSample.start();
    }
}

class ThreadSample extends Thread{
    public void run(){
        //Operate UI parts of the main activity
        // post()Since the method takes Runnable as an argument, it is as follows
        MainActivity.textView.post(new Runnable(){
            @Override
            public void run() {
                MainActivity.textView.setText("From ThreadSample");
            }
        });
    }
}
Post () in anonymous class

As a reminder, I will write it in the anonymous class as well.

python


public class MainActivity extends AppCompatActivity {

    public static TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView) findViewById(R.id.textView);

        new Thread(new Runnable() {
            @Override
            public void run() {
                textView.post(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText("From Another Thread");
                    }
                });
            }
        }).start();
    }
}

・ View.postDelayed

public boolean postDelayed(Runnable action,long delayMillis) delay ... delay; Millis ... milliseconds </ font> postDelayed adds Runnable to the message queue and, after a specified amount of time, processes the Runnable in the UI thread.

When you execute the code below, the textview will be greeted with the initial value "Hello World!", But after 5 seconds, the display will change to "From ThreadSample".

activity_main.xml


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:id="@+id/textView"
        />

In Thread class


public class MainActivity extends AppCompatActivity {

    public static TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView) findViewById(R.id.textView);
        ThreadSample threadSample = new ThreadSample();
        threadSample.start();
    }
}

class ThreadSample extends Thread{
    public void run(){
        MainActivity.textView.postDelayed(new Runnable(){
            @Override
            public void run() {
                MainActivity.textView.setText("From ThreadSample");
            }
        },5000);
    }
}

・ Activity.runOnUiThread

public final void runOnUiThread(Runnable action)

Activity class method: ** Activity can use runOnUiThread () **. Activity provides the UI screen.

runOnUiThread executes the specified action on the UI thread. If the current thread is a UI thread, the action will be executed immediately! Otherwise, the action will be added to the UI thread's event queue. It seems that the behavior works much like the post () method! ..

public class MainActivity extends AppCompatActivity {

    public static TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView) findViewById(R.id.textView);

        new Thread(new Runnable(){
            @Override
            public void run() {
                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText("runOnUiThread");
                    }
                });
            }
        }).start();
    }
}

■Handler For more information, click here "Hanler Summary" Handlers can be used to send Runnable objects and process messages associated with a thread's message queue. Instances of Handler are associated with single threads and message queues. Returns true when added to the message queue. It is not whether the process was successful. If the looper exits before the specified time has elapsed, Runnable will be abandoned. If false, suspect that the message queue has ended!

■android.os.AsyncTask public abstract class AsyncTask extends Object android.os.AsyncTask<Params,Progress,Result>

Summary here Reference code here

AsyncTask is an asynchronous process. Especially suitable for short-time asynchronous processing. ** Please use other APIs (Executor, ThreadPoolExecutor, etc.) ** for processing that runs for a long time!

Recommended Posts