Android API guide, threads and processes

Overview:

In the android system, when the application starts, the android system uses a single thread of execution to start a new Linux process for the application. By default, the same application

All of the components run in the same process and thread (called the "main" thread). If an application component is started and the application already has a process (because there are other

Other components), the component will start in this process and use the same thread of execution. However, you can arrange for other components in the application to run in a separate process, and for any

The process creates additional threads.

process:

By default, all components in an application run in the same process. However, if you find that you need to control the process to which a component belongs, you can

Do this in the file. If you want to put a component in a separate process to execute. You can configure the android:process attribute of the component in the manifest file . The components that support this attribute are:

<Activity>, <Service>, <Receiver>, and <Provider> are the four major components in the android app. In addition, this attribute is also supported under the <Application> element, which is the default for the entire application

process.

Process life cycle:

The Android system will keep the application process as long as possible, but in order to create a new process or run a more important process, it is necessary to clear the old process to reclaim the memory. To determine which to keep or terminate

Process, the system will put each process into the "importance hierarchy" according to the running components in the process and the status of these components. When necessary, the system will eliminate the least important process first, but

The latter are less important processes, and so on, to recover system resources. There are 5 levels of importance hierarchy.

1. Foreground process

The process necessary for the user's current operation. If a process meets any of the following conditions, it is regarded as a foreground process:

a. The user is interacting  (  the   method that has been called  ) ActivityActivityonResume()

b.       One  Service, the latter is bound to the Activity that the user is interacting with

c. is running in the "foreground"  (service has been called  ) ServicestartForeground()

d. Is executing a life cycle callback  ( ,  or  ) ServiceonCreate()onStart()onDestroy()

e. is executing its  onReceive() method BroadcastReceiver

2. Visible process

There is no foreground component, but it still affects the progress of what the user sees on the screen. If a process meets any of the following conditions, it is considered a visible process:

Not in the foreground, but still visible to the user  Activity(its  method has been called  onPause()). For example, if the foreground Activity starts a dialog box, allowing to display the previous

Activity, this may happen.

Bind to the visible (or foreground) Activity Service

Visible processes are regarded as extremely important processes, unless they must be terminated in order to maintain all foreground processes running at the same time, otherwise the system will not terminate these processes.

3. Service process

A process that is running  a service that has been started using a  startService()method and is not part of the two higher-class processes mentioned above. Although service processes are not directly related to what the user sees, they

Usually performing some operations that the user cares about (for example, playing music in the background or downloading data from the network). Therefore, unless the memory is not enough to maintain all foreground and visible processes running at the same time, the system

Keep the service process running.

4. 后台进程

包含目前对用户不可见的 Activity 的进程(已调用 Activity 的 onStop() 方法)。这些进程对用户体验没有直接影响,系统可能随时终止它们,

以回收内存供前台进程、可见进程或服务进程使用。 通常会有很多后台进程在运行,因此它们会保存在 LRU (最近最少使用)列表中,以确保包含用户

最近查看的 Activity 的进程最后一个被终止。如果某个 Activity 正确实现了生命周期方法,并保存了其当前状态,则终止其进程不会对用户体验产生明

显影响,因为当用户导航回该 Activity 时,Activity 会恢复其所有可见状态。

5. 空进程

不含任何活动应用组件的进程。保留这种进程的的唯一目的是用作缓存,以缩短下次在其中运行组件所需的启动时间。 为使总体系统资源在进程

缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。

Android 系统在内存紧张的情况下, 会执行内存释放以满足当前使用。上面优先级是android系统保留内存使用的顺序。空进程会在内存紧张的时候

马上被释放, 前台进程正在和用户交互, 这个进程Android是不会去回收的。就是说基本不可能主动去回收一个前台进程

线程:

应用启动后, 系统会分配进程。同时会为应用创建一个 主线程/UI线程

如果 UI 线程需要处理所有任务,则执行耗时很长的操作(例如,网络访问或数据库查询)将会阻塞整个 UI。如果 UI 线程被阻塞超过几秒钟时间

(目前大约是 5 秒钟),用户就会看到一个让人厌烦的“应用无响应”(ANR) 对话框。

线程的注意事项有两点: 1. 不能通过 额外的工作线程(也就是除了 主线程 之外的线程)操作UI。 2. 不能阻塞UI线程。

例如: 点击事件下载文件, 下载完成之后,更新textView:

public void onClick(View v) {
    new Thread(
            new Runnable() {
                @Override
                public void run() {
                    try {
                        // 让线程睡眠2s, 模拟耗时
                        Thread.sleep(2000);
                        // 下载完成
                        textView.setText("下载完成");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    ).start();
}

代码感觉没什么问题,可是一运行的时候就报错了:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

这个错误就是说, 只有创建这个view的线程才可以操作这个view。意思就是别的线程不能操作主线程的UI。 上面的代码中, textView.setText("下载完成“);这行代码就是在操作主线程UI了。报错就是因为这行代码。


Android 提供了几种途径来从其他线程访问 UI 线程。

1. Activity.runOnUiThread(Runnable)

2. View.post(Runnable)

3. View.postDelay(Runnable, long)

代码改造:

public void onClick(View v) {
        /*new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        try {

                            // 让线程睡眠2s, 模拟耗时
                            Thread.sleep(2000);

                            // 下载完成
//                            textView.setText("下载完成");

                            runOnUiThread();

                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
        ).start();*/

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                try {

                    // 让线程睡眠2s, 模拟耗时
                    Thread.sleep(2000);

                    // 下载完成
                    textView.setText("下载完成");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }

这样就完成改造了。 在运行后就没问题了。 下载完成后, View 显示”下载完成“字样。 其实这个方法也可以很直观的看出他的功能, runOnUiThread(Runnable), 运行在UI

线程中, 参数是一个Runnable对象。 可猜测这个方法将Runnable里面的执行方法放到UI线程中,使用这个方法的时候, 在这个方法里面的操作就相当于在UI线程中操作了。所以我们就可以理所当然的可以更新UI组件了。。。, 其他两个方法用法都差不多。


使用上面提供出来的三种方法, 当然可以实现和UI线程的交互, 但是,随着操作日趋复杂,这类代码也会变得复杂且难以维护。 要通过工作线程处

理更复杂的交互,可以考虑在工作线程中使用 Handler 处理来自 UI 线程的消息。官方认为最好的解决方案或许是扩展 AsyncTask 类,此类简化了与 UI

进行交互所需执行的工作线程任务。


AsyncTask使用:

AsyncTask 允许对用户界面执行异步操作。它会先阻塞工作线程中的操作,然后在 UI 线程中发布结果,而无需您亲自处理线程和/或处理程序。

要使用它,必须创建 AsyncTask 子类并实现 doInBackground() 回调方法,该方法将在后台线程池中运行。要更新 UI,必须实现 onPostExecute() 

以传递doInBackground() 返回的结果并在 UI 线程中运行,这样,您即可安全更新 UI。稍后,您可以通过从 UI 线程调用 execute() 来运行任务。

使用AsyncTask类来改造上面的代码:

public class MyAsyncTask extends AsyncTask<String, Void, String> {
    @Override
    protected String doInBackground(String... params) {
        try {

            // 让线程睡眠2s, 模拟耗时
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "下载完成";
    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        textView.setText(s);
    }
}


AsyncTask 实现类, 重写doInBackgroud方法,和onPostExecute方法。同样也实现了耗时操作的功能。AsyncTask类中还有其他几个方法,可以

很好的与UI线程交互。需要详细了解的,可以去看看这个api接口。


Android 还有一个进程间的通信: IPC机制。是本地进程和远程进程间的通信。这个东西, 后面在研究。


感觉进程和线程这两个名词很容易搞混淆。所以这两者之间的关系必须要有比较深刻的认识!!!!







Guess you like

Origin blog.csdn.net/u011326269/article/details/51758533