• 进程和线程


    进程和线程

    标签(空格分隔): Android API指导


    此文档介绍Android应用的进程和线程是如何工作的。

    进程

    默认的,同一个应用中的所有组件都是运行在同一个进程。
    所有组件在manifest文件中可以通过android:process属性来指定运行的进程。

    进程生命周期

    Android系统会给每个进程分级,如果系统需要回收内存时,就先销毁优先级低的进程,各层级如下(序号越高,重要性越低,越容易被销毁):

    1. 前台进程
      用户正在使用的,有如下场景:
    • 与用户交互的Activity界面(onResume已经执行)
    • 绑定到与用户正在交互界面的Service
    • 在前台运行的Service(用startForeground启动)
    • 正在执行生命周期回调函数的Service(onCreate、onStart、onDestroy)
    • 正在执行onReceiver的BroadcastReceiver

    一般来说,某个时间点上只有少数的前台进程在运行。他们只有在内存低到无法继续运行的时候才有可能会被销毁。
    3. 可视进程
    进程不包含前台组件,但仍是用户可见的,有如下场景:

    • Activity不在前台,但是仍然是可见的(onPause已经执行),例如A弹出前台对话框B,B不能完全覆盖A时。
    • 绑定到可见或者前台Activity的service
    1. 服务进程
      由startService启动的服务,并且不在1和2场景中。
    2. 后台进程
      承载不可见的Activity(onStop已经执行)
    3. 空进程
      不承载任何组件的进程

    线程

    Android UI是单线程模型,应用中所有组件的实例都在同一个UI线程中执行,当UI线程阻塞时,会无法分发用户的点击事件导致ANR。
    另外,UI线程是非线程安全的,所有与用户界面相关的交互必须都放在UI线程中,而不是用其他工作线程,因此,对于Android线程模型来说有两条简单的规则:

    1. 不要阻塞UI线程
    2. 不要在UI线程之外的其他线程中访问UI元素

    工作线程

    对于第一条规则,可以将耗时的操作放在新线程中,比如咋新线程中下载一个图片:

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

    但是上述代码又违反了第二条规则,在非UI线程中使用了界面元素mImageView。
    为了避免这个问题,Android提供了如下方法:

    • Activity.runOnUiThread(Runnable)
    • View.post(Runnable)
    • View.postDelayed(Runnable, long)

    例如,可以这么用:

    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();
    }
    

    然而对于复杂的操作,上述代码很难维护,你可以使用Handler来处理,也可以扩展AsyncTask类

    使用AsyncTask

    AsyncTask允许执行UI元素的异步操作,它会在工作线程中执行阻塞UI的操作,然后将结果发送给UI线程,而不需要你自己处理线程。
    使用方法:继承AsyncTask,实现在后台线程池执行的doInBackground,实现onPostExecute来更新UI。
    例子:

    public void onClick(View v) {
        new DownloadImageTask().execute("http://example.com/image.png");
    }
    
    private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
        /** 系统在工作线程中执行这个动作,其中入参是由AsyncTask.execute()提供 */
        protected Bitmap doInBackground(String... urls) {
            return loadImageFromNetwork(urls[0]);
        }
        
        /** 系统调用这个刷新UI界面,其中result是doInBackground()的返回值 */
        protected void onPostExecute(Bitmap result) {
            mImageView.setImageBitmap(result);
        }
    }
    
    1. AsyncTask用之前,建议看一下SDK文档
    2. 运行时的配置变化(比如横竖屏)会销毁你的工作线程,可以查看Shelves例子代码。

    线程安全方法

    某些情况下,你写的方法可能被多个线程调用,那就需要这个方法是线程安全的。
    像Service的onBind,ContentProvider的query、insert、delete、update、getType都是类似需要线程安全的函数。

    进程间通讯

    IPC,RPC,详见Service章节

  • 相关阅读:
    Probability theory
    python Memo
    numpy 札记
    linux LVM 逻辑卷
    关于TF-IDF的一些见解
    Python之list、dict、np等常用数值运算
    Python之matplotlib绘图
    Python之打开网页
    Python之获取地址经纬度
    两台电脑直接共享文件
  • 原文地址:https://www.cnblogs.com/konger/p/3978246.html
Copyright © 2020-2023  润新知