zoukankan      html  css  js  c++  java
  • 进程和线程

    进程和线程

    标签(空格分隔): 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章节

  • 相关阅读:
    Leetcode Reverse Words in a String
    topcoder SRM 619 DIV2 GoodCompanyDivTwo
    topcoder SRM 618 DIV2 MovingRooksDiv2
    topcoder SRM 618 DIV2 WritingWords
    topcoder SRM 618 DIV2 LongWordsDiv2
    Zepto Code Rush 2014 A. Feed with Candy
    Zepto Code Rush 2014 B
    Codeforces Round #245 (Div. 2) B
    Codeforces Round #245 (Div. 2) A
    Codeforces Round #247 (Div. 2) B
  • 原文地址:https://www.cnblogs.com/konger/p/3978246.html
Copyright © 2011-2022 走看看