Programming memorandum process thread from 51 years old Handler -reference

For personal use

Processes and threads

https://developer.android.com/guide/components/processes-and-threads?hl=JA (2019/8/24)

Multithreaded summary is here

process

--Relationship between components, processes and threads --Manifest settings (components and processes) --Process importance hierarchy


Relationships between components, processes and threads

--When the application runs one component, the Android system starts a Linux process for single thread. -- Components
Activities / Services / Content Providers / Broadcast Receivers
Activities, services and broadcast receivers are activated with Intent (asynchronous messages).
- process / Linux process
A program running on Linux. </ font>

--By default, all components of the same application run in the same process and thread (main thread).

--When a component of your app starts, if there is another process, the component starts within that process and uses the same thread of execution.

--However, you can adjust different components in your application to run in different processes, and you can create separate threads for any process.


Manifest settings

If you want to manage the process to which a particular component belongs, specify it in the manifest file.

Manifest entries for each type of component element (\ / \ / \ / \ ) </ strong> </ font> Supports the android: process </ strong> attribute, which specifies the process that runs the component.

Depending on the ** android: process ** settings, each component can run in its own process, some components can share the same process, or different processes can be used. You can also run components of different applications in the same process (the apps must share the same Linux user id and be signed with the same certificate).

The ** \ ** element also supports ʻandroid: process`, which sets default values that apply to all components.

The Android system may shut down processes and destroy application components. When deciding on the process to discard, the system determines candidates based on relative demand. Later, I'll explain the rules that determine the process of discarding.


Process importance hierarchy

Based on the components running in the process and the state of the components, the Android system positions each process in a "priority hierarchy" and attempts to remove it from less important processes and recover system resources.

Process importance hierarchy 5 levels

  1. Foreground process
  2. Visible process
  3. Service process
  4. Background process
  5. Empty process
1. Foreground process

--Hosted by user-operated Activity </ font> ( Activity's onResume () method </ font> was called) --Binded to the activity operated by the user (hosted by Service </ font>) --Hosted a Service </ font> running in the foreground (the service called startForeground () </ font>) - onCreate (), onStart (), onDestroy () </ font> performing a lifecycle callback Service </ font> Is the host of> -Hosted the BroadcastReceiver </ font> running the onReceive () </ font> method

If you run out of memory or resources, you will need to kill the foreground process.

2. Visible process

A process that is not a foreground component but can affect the content of the notification area for the user. It is considered a visible process if:

--Although not in the foreground, it is the host of the Activity </ font> displayed to the user ( onPause () </ font> > The method was called).

--Hosted Service </ font> bound to visible (or foreground) activity.

Visible processes are of great importance and will only be killed if you need to keep the foreground process running.

3. Service process

A process that executes a service started by the startService () </ font> method and does not fall into the above two categories. Together with all foreground and visible processes, they are candidates for killing only if there is insufficient memory to continue them.

4. Background process

A process containing activities that are not visible to the user (the onStop () </ font> method was called). It can be killed at any time to recover memory. Background services are managed in a LRU (Least Recently Used) list and are terminated from the oldest operation.

If the activity implements the lifecycle method exactly and retains its current state, it will restore its visual state when it resumes even if it is killed.

5. Empty process

A process with no active application components. This process is retained for the purpose of caching the process and quickly launches the next component. This process is frequently killed.


For multiple importance components, position the process in the most important rank. Also, a process running for another process will not be positioned below the dependent / binding process (if it is positioned below it will not be able to run if the dependent process is destroyed. ).

Services are more important than the background, and for long-running activities (especially if the process lasts longer than the activity), the process should use the service rather than create a worker thread. For example, when uploading an image to the web, the activity uses a service that allows the user to continue working in the background when they leave the activity. Even broadcast receivers should use services rather than letting threads process them for long periods of time.

thread

When the application starts, the system creates a main thread for running the application. The main thread is very important for sending events (including drawing events) to the appropriate UI widgets.

The main thread also allows the app to interact with components in the Android UI toolkit (components in the android.widget / android.view </ font> package). Therefore, the main thread is also called the UI thread (in some special cases, the main thread is not the UI thread).

No separate thread is created for each instance of the component. All components running in the same process are instantiated in the UI thread and the system calls the components sent by the UI thread. Methods that respond to system callbacks always run in the process's UI thread.

(Example: When the user touches a button on the screen, the app's UI thread sends a touch event to the widget, the widget sets the touch state, and the UI thread sends an invalidation request to the event queue. Receives a request from the queue and notifies the widget of drawing)

If everything is done in a UI thread, performing time-consuming operations can block the entire UI. Also, the Android UI toolkit is not thread-safe, so you cannot interact with the UI from worker threads. All operations must be done from the UI thread. Therefore, Android's single thread model has two rules.

Single thread model rule

1. Do not block UI threads 2. Do not access the Android UI toolkit from anyone other than the UI thread </ strong> Access methods are provided from other than the UI thread. ( View can only be operated from the thread that created the View </ font> </ strong>)


Worker thread

A worker thread is a thread that does not have a UI and executes the received processing request (also called backgroundThread). The worker thread behaves as if it waits even if there is no processing request and executes it when it receives the processing request. There may be multiple worker threads depending on the processing content, and the location may be called Thread Pool. </ font>

The single-threaded model should not block UI threads for the responsiveness of the application's UI. Operations that do not need to be performed immediately are performed in a separate thread (worker thread (background thread)).

<Reference: Rule violation code </ font> >>

python


public void onClick(View v) {
    new Thread(new Runnable() {
        public void run() {
            Bitmap b = loadImageFromNetwork("http://example.com/image.png ");
            mImageView.setImageBitmap(b);
        }
    }).start();
}

Attempting to change ImageView </ font> from the worker thread instead of the UI thread violates Rule 2 (Android UI Toolkit is accessed only from the UI thread).

Access method from other than UI thread
  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable)
  • View.postDelayed(Runnable,long)

<Reference: Correction code by View.post (Runnable) </ font> >> Implement View.post (Runnable) to make it thread-safe

python


public void onClick(View v) {
    new Thread(new Runnable() {
        public void run() {
            final Bitmap bitmap =
                    loadImageFromNetwork("http://example.com/image.png ");
            mImageView.post(new Runnable() {
                public void run() {
                    mImageView.setImageBitmap(bitmap);
                }
            });
        }
    }).start();
}

Network operations are executed in a separate thread (loadImageFromNetwork ()). ImageView is operated from the UI thread (mImageView.post (new Runnable () {})).

The method of using View.post to operate a View from a UI thread is difficult to maintain as the operation becomes complicated. To handle complex interactions with worker threads, you can use Handlers on worker threads to handle messages delivered by UI threads. But the recommended method is to extend the AsyncTask class. Simplifies the execution of worker thread tasks that interact with the UI.

Use of AsyncTask

AsyncTask performs asynchronous processing. You don't have to handle the thread or Handler yourself, it blocks the operation of the worker thread and delivers the result to the UI thread.

To use AsyncTask, subclass AsyncTask </ font> and execute it in the pool of background threads doInBackground () </ font> callback Implement the method.

Implement onPostExecute () </ font> to reflect the result in the UI. onPostExecute () </ font> delivers the result of doInBackground () </ font> to the UI and updates the UI thread, so the UI Can be safely updated. The UI thread calls execute () </ font> to execute the task.

<Reference: Rewrite the above code with AsycnTask>

public void onClick(View v){
   new DownloadImageTask().execute("http://example.com/image.png ");
}

private class DownloadImageTask extends AsyncTask<String,Void,Bitmap>{
   //The system calls the following method to handle it in the worker thread,
   //   AsyncTask.execue()Deliver the parameters passed by the method
   protected Bitmap doInBackground(String... urls){
      return loadImageFromNetwork(urls[0]);
   }

   //The system calls the following method to handle in the UI thread
   //   doInBackground()Deliver the result to the method
   protected void onPostExecute(Bitmap result){
      mImageView.setImageBitmap(result);
   }
}

The UI is safer and the code is simpler because the work done by the worker thread and the work done by the UI thread are separated.

How AsyncTask works.

--Generics can be used to specify parameter type, progress value, final value of task - doInBackground () </ font> method is automatically executed on the worker thread - onPreExecute (), onPostExecute (), onProgressUpdate () </ font> are all called in the UI thread -The return value of doInBackground () </ font> is sent to onPostExecute () </ font> - publishProgress () </ font> can be called with doInBacktround () </ font>, and in the UI thread. You can run onProgressUpdate () </ font> --You can cancel a task at any time from any thread

COUSION: Problems that can occur when using worker threads
Changes in run-time settings, such as when the screen is turned around, can cause the activity to restart unexpectedly and destroy the worker thread. See the sample app source code below for how to keep the task during the restart and how to cancel the task correctly when the activity is destroyed> https://code.google.com/archive/p/ shelves /
Learn more about AsyncTask> https://developer.android.com/reference/android/os/AsyncTask.html?hl=JA

Thread-safe method

If the implemented method is called from multiple threads, create the method so that it is thread-safe.

Remotely called methods, such as methods for primarily bound services, can be called from multiple threads. When called from multiple threads, the thread that executes the method called remotely is as follows.

-A method call implemented in IBinder </ font> occurred in the same process running IBinder </ font>. If so, the thread executing the method is the calling thread. --When called from another process, the thread that executes the method is selected from the thread pool that the system keeps in the same process as IBinder </ font>. (Not executed in UI thread).

For example, the service's onBind () </ font> method is called from a UI thread in the service's process, while onBind () The methods implemented in the object returned by </ font> (such as the subclass that implements the RPC method) are called from threads in the thread pool. Since the service can have multiple clients, multiple thread pools can run the same IBinder method </ font> at the same time, so the IBinder method must be implemented to be thread safe. ..

RPC method: The method is called locally, executed remotely (in another process), and the result is returned to the caller. </ font>

Similarly, content providers can receive data requests sent by other processes. The ContentResolver </ font> class and the ContentProvider </ font> class obscure how interprocess communication is managed. However, the ContentProvider </ font> method ( query (), insert (), delete (), updater (), getType) responds to those requests. () </ Font>) is called the thread pool in the content provider's process, not the process's UI thread. These methods can be called by multiple methods at the same time, so they must be implemented to be thread-safe.

Thread safe

Control (Synchronization), arbitrate, or control another thread while one thread is running to avoid thread contention (a relationship where multiple threads access the same class, method, or variable at the same time and destroy data). Exclusive control), and make the class or method safe even if simultaneous access occurs from multiple threads.

Interprocess communication (IPC)

Android has a mechanism for interprocess communication using remote procedure call (RPC), where a method is called from an activity or other application component, then executed remotely (another process) and calls the result. Returns to. Since the system is responsible for the processing of interprocess communication, developers only need to define and implement the RPC programming interface. To run the IPC, your app must be bound to the service using bindService () </ font>. For more information> https://developer.android.com/guide/components/services.html?hl=JA

Handle You can use Handler to create Message </ font> and executable objects (such as Runnable) associated with the thread's MessageQueue </ font>. You can send and process it.

An instance of Handler is associated with a single thread and that thread's message queue.

When you create a new Handler, the Handler is assigned to the spawned thread and its message queue. The Handler can then deliver the message and the executable message queue, and can dequeue and execute the message.

Main Handler usage

--Schedule a message and make it executable at the scheduled time --Queue the message to run in a separate thread

Schedule a message

Method to use

Post Version post(Runnable)/postAtTime(java.lang.Runnable,long)/postDelayed(Runnable,Object,long)

Send Message Version sendEmptyMessege(int)/sendMessage(Message)/sendMessageAtTime(Message,long)/sendmessageDelayed(Message,long)

The Post version works by queuing an object when it receives an executable object.

The SendMassege version queues message objects. The message object holds a collection of data that will be used in the Handler's HandleMessage (Message) method. (HandleMessage (Massage) implements a subclass of Handler)

Posting or sending a Handler will allow it to be processed as soon as the message queue is ready. You can also specify the procrastination of processing and the execution time.

Later, I will explain the implementation of timing operations such as timeout processing and ticks (timer-like).

When the application runs, the main thread becomes a dedicated thread for executing message queues. Message queues manage top-level application objects such as activities, broadcasts, and receivers, as well as the windows they create.

You can use Handler to create another thread to communicate with the main application. To do this, use the post and sendMessage methods in advance.

Runnables and messages are scheduled in the Handler's message queue and run at the appropriate time.


Handler Summary

■ ** Thread ** class extension | ** Runnable ** interface inheritance ** Communication with UI thread **   view#post(Runnable)   View#postDelayed(Runnable.long)   runOnUiThread(Runnable) ■ ** AsyncTask ** class ** Processing and communication ** With execute (), doInBackground (), postExecute (), etc. ■ ** Handler ** class ** Communication between multithreads ** Responsible for communication between threads created separately   Message   Runnable

Handler Summary Summary

class android.os.Handler

Handler enables communication between UI threads and worker threads!

MessageQueue </ font> </ strong> (stacks and stores messages and Runnables) and retrieves messages and Runnables from MessageQueue in the thread that created the Handler instance > Generate Looper </ font> </ strong>. Handler realizes inter-thread communication, so it seems that it is designed so that it can be referenced by other threads </ font>.

An instance of Handler is associated with the spawned thread and message queue, and returns true when a message etc. is added to the queue. If Looper ends before the specified time elapses, Runnable will be abandoned and become False, so if False appears, the message queue may have ended!

Handler communication

--How to use Message --How to use Runnable

The Handler provides a means of communicating information between threads that have already been created. It realizes communication between worker threads as well as UI threads.

If you use Message, Looper processes handleMessage, and if you use Runnable, Runnable is executed on the UI side.

###### Case 1 of Handler and Message

Message


public class MainActivity extends AppCompatActivity {

    TextView textView;

    //UI thread(MainActivity)Create a Handler instance with
    //Now both Message Queue and Looper are UI threads.
    //Since the instance handler can be referenced from another thread
    //If you refer to the handler in another thread and post a message
    //UI thread (MainActivity)And Looper will handle it for you!
    //It's cool! !!
    //Then, please come to handler!
    Handler handler = new MyHandler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView1);

        MyLovelyMessage();
    }

    private void MyLovelyMessage() {
        //UI thread (MainActivity)Access the handler generated in
        //Put Message in handler and sendMessage!
        //The UI thread Looper should now do just fine!
        Message message = handler.obtainMessage(1);
        handler.sendMessage(message);
    }

    class MyHandler extends Handler{
        @Override
        public void handleMessage(Message message){
            //Defines what handle does in the UI thread
            //It will be executed automatically by Looper!
            String msg = String.valueOf(message.what);
            textView.setText(msg);
        }
    }
}

Simplify the above code as an internal function

Message


public class MainActivity extends AppCompatActivity {

    TextView textView;

    Handler handler = new Handler(){
      @Override
      public void handleMessage(Message message){
          String msg = String.valueOf(message.what);
          textView.setText(msg);
      }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView1);

        MyLovelyRunnable();
    }

    private void MyLovelyRunnable() {
        Message message = handler.obtainMessage(1);
        handler.sendMessage(message);
    }
}
Example using Handler and Runnable
public class MainActivity extends AppCompatActivity {

    TextView textView;

    //UI thread Handler(MainAvtivity.class)Generate with
    //Now both MessageQueue and Looper are in this thread(UI thread)Associated with
    //
    //Since the Handler instance can be referenced from other threads as well
    //In another thread, using the instance handler
    //Runnable in this thread(UI thread)If you give it to
    //This thread(UI thread side)Will be able to run Runnable
    //It's nice!
    //Now let's create an instance of Handler! !!
    Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView1);

        MyLovelyHandler();

    }

    private void MyLovelyHandler(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                //UI thread(MainActivity)The instance of Handler created in
                //It can also be referenced from other threads
                //Put Runnable on the instance handler
                //UI thread (MainActivity)Let's hand it over to and have it processed!
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText("I Love Handler");
                    }
                });
            }
        }).start();
    }
}


Handler and Service: Example of dividing a file into multiple files

Min target: api28 or above.

Created file

  • MainActivity.java
    Create Handler instance
    Run Foreground Service
  • MyService.java
    Create a Message and sendMessage
  • MyHandler sendMessage Process the sent message
When I call Service with Foreground, it crashes unless I startForeground (int, notification) on the Service side within 5 seconds, but since the code is long, I will not describe it this time and it will crash, sorry.

MainActivity.java


public class MainActivity extends AppCompatActivity {
    public static TextView textView;

    //Create a Handler object and make MessageQueue and Looper a UI thread!
    //This will store the message sent to the Handle object in the Message Queue.
    //Looper will take it out and process it! (The content of the process is MyHandler.Define it in class! )
    static MyHandler myHandler = new MyHandler();

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

        textView = findViewById(R.id.textView);

        //Create an Intent object and call Service!
        Intent intent = new Intent(this,MyService.class);
        startForegroundService(intent);

    }
}

MyService.java


public class MyService extends Service {
    public MyService() {
    }

    @Override
    public int onStartCommand(Intent intent,int flags,int startid){
        //SendMessage by putting a message on the Handle object of MainActivity!!
        //The destination is the UI thread Message Queue!
        //After that, Looper is MyHandler.Execute class and process it!!
        Message message = MainActivity.myHandler.obtainMessage(1);
        MainActivity.myHandler.sendMessage(message);
        return START_STICKY;
    }

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

MyHandler.java


//Message stored in Message Queue of UI thread
//The UI thread Looper has the following handleMessage()Will be executed!

public class MyHandler extends Handler {
    @Override
    public void handleMessage(Message message){
        String msg = String.valueOf(message.what);
        MainActivity.textView.setText(msg);
    }
}
Sample code for timer case in Handler Runnable Service

I was allowed to reference. Thank you very much. Here But I didn't understand why `myHandler.postDelayed (runnnable, milli) was called twice.

It doesn't process notifications, so it crashes immediately. Automatically go to Foreground Service when the app is launched ForegroundService, timer processing with handler.postDeployed (runnnable, mill) Resume counting with the start button Stop counting with the stop button

MainActivity.java


public class MainActivity extends AppCompatActivity {
    public static TextView textView;
    static Handler myHandler = new Handler();
    boolean signal =false;

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

        Button btnStart= findViewById(R.id.btnStart);
        Button btnStop = findViewById(R.id.btnStop);
        textView = findViewById(R.id.textView);

        final Intent intent = new Intent(this,MyService.class);
        startForegroundService(intent);
        
        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(signal == false){
                    MyService.runnable.run();
                    signal = true;
                }
            }
        });

        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                myHandler.removeCallbacks(MyService.runnable);
                signal = false;
            }
        });
    }
}

MyService.java


public class MyService extends Service {
    static Runnable runnable;
    public MyService() {
    }

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

        runnable = new Runnable() {
            int i=0;
            @Override
            public void run() {
                i++;
                String st = String.valueOf(i);
                MainActivity.textView.setText(st);
                MainActivity.myHandler.postDelayed(this,1000);
            }
        };
        
//        MainActivity.myHandler.postDelayed(runnable,1000);
        return START_STICKY;
    }

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

Recommended Posts