【Android 内核研究】理解Context

写在前面的话

非常感谢柯元旦所赠的《Android内核剖析》一书。通过对本书的学习,让我对Android内核有了更深一层次的理解。本文是《Android内核剖析》的学习笔记。

Context是什么

一个Context意味着一个场景,一个场景就是用户和操作系统交互的一个过程。在广义上,这个所谓的过程应该包括前台界面和后台数据。

举个例子,比如当你打电话的时候,场景包括电话程序对应的界面以及隐藏在界面后的数据。

从程序的角度来看,一个Activity就是一个Context,一个Service也是一个Context。

从语义的角度来看一下Context。谷歌程序员把“场景”抽象为Context类,他们认为用户和操作系统的每一次交互都是一个场景,比如打电话,发短信。

从代码的角度来看,Activity类基于Context,而Service类也基于Context类。值得一提的是,Activity除了基于Context类外,还实现了一些其他重要接口。

从设计的角度来看,interface仅仅是某些功能的标记,而extends才是类的本质和实现。


Context相关类的继承关系

相关类介绍

Context

/frameworks/base/core/java/android/content/Context.java

抽象类,提供了一组通用的API。

/**
 * Interface to global information about an application environment.  This is
 * an abstract class whose implementation is provided by
 * the Android system.  It
 * allows access to application-specific resources and classes, as well as
 * up-calls for application-level operations such as launching activities,
 * broadcasting and receiving intents, etc.
 */
public abstract class Context { ... }

ContextIml.java

/frameworks/base/core/java/android/app/ContextImpl.java

ContextImpl是Context的具体实现类,该类实现了Context类的所有功能。注意,该函数的大部分功能都是直接调用其成员变量mPackageInfo去完成,它是一个delegate。

/**
 * Common implementation of Context API, which provides the base
 * context object for Activity and other application components.
 */
class ContextImpl extends Context {
    private final static String TAG = "ApplicationContext";
    private final static boolean DEBUG = false;
    private final static boolean DEBUG_ICONS = false;

    private static final Object sSync = new Object();
    private static AlarmManager sAlarmManager;
    private static PowerManager sPowerManager;
    private static ConnectivityManager sConnectivityManager;
    private static ThrottleManager sThrottleManager;
    private static WifiManager sWifiManager;
    private static LocationManager sLocationManager;
    private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs =
            new HashMap<String, SharedPreferencesImpl>();

    private AudioManager mAudioManager;
    /*package*/ LoadedApk mPackageInfo;
    private Resources mResources;
    /*package*/ ActivityThread mMainThread;
    private Context mOuterContext;
    private IBinder mActivityToken = null;
    private ApplicationContentResolver mContentResolver;
    private int mThemeResource = 0;
    private Resources.Theme mTheme = null;
    private PackageManager mPackageManager;
    private NotificationManager mNotificationManager = null;
    private ActivityManager mActivityManager = null;
    private WallpaperManager mWallpaperManager = null;
    private Context mReceiverRestrictedContext = null;
    private SearchManager mSearchManager = null;
    private SensorManager mSensorManager = null;
    private StorageManager mStorageManager = null;
    private Vibrator mVibrator = null;
    private LayoutInflater mLayoutInflater = null;
    private StatusBarManager mStatusBarManager = null;
    private TelephonyManager mTelephonyManager = null;
    private ClipboardManager mClipboardManager = null;
    private boolean mRestricted;
    private AccountManager mAccountManager; // protected by mSync
    private DropBoxManager mDropBoxManager = null;
    private DevicePolicyManager mDevicePolicyManager = null;
    private UiModeManager mUiModeManager = null;
    private DownloadManager mDownloadManager = null;
    private NfcManager mNfcManager = null;

    private final Object mSync = new Object();

    private File mDatabasesDir;
    private File mPreferencesDir;
    private File mFilesDir;
    private File mCacheDir;
    private File mExternalFilesDir;
    private File mExternalCacheDir;

    private static long sInstanceCount = 0;

    private static final String[] EMPTY_FILE_LIST = {};

    ...
}

ContextWrapper类

\frameworks\base\core\java\android\content\ContextWrapper.java

该类只是对Context类的一种包装,该类的构造函数包含了一个真正的Context引用,即ContextImpl对象。

/**
 * Proxying implementation of Context that simply delegates all of its calls to
 * another Context.  Can be subclassed to modify behavior without changing
 * the original Context.
 */
public class ContextWrapper extends Context {
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }

    /**
     * Set the base context for this ContextWrapper.  All calls will then be
     * delegated to the base context.  Throws
     * IllegalStateException if a base context has already been set.
     *
     * @param base The new base context for this wrapper.
     */
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

    /**
     * @return the base context as set by the constructor or setBaseContext
     */
    public Context getBaseContext() {
        return mBase;
    }

    @Override
    public AssetManager getAssets() {
        return mBase.getAssets();
    }

    @Override
    public Resources getResources()
    {
        return mBase.getResources();
    }

    @Override
    public PackageManager getPackageManager() {
        return mBase.getPackageManager();
    }

    @Override
    public ContentResolver getContentResolver() {
        return mBase.getContentResolver();
    }

    @Override
    public Looper getMainLooper() {
        return mBase.getMainLooper();
    }

    @Override
    public Context getApplicationContext() {
        return mBase.getApplicationContext();
    }

    @Override
    public void setTheme(int resid) {
        mBase.setTheme(resid);
    }
    ...
}

ContextThemeWrapper类

/frameworks/base/core/java/android/view/ContextThemeWrapper.java

该类内部包含了主题(Theme)相关的接口,即android:theme属性指定的。只有Activity需要主题,而Service不需要主题,所以Service直接继承自ContextWrapper类。

/**
 * A ContextWrapper that allows you to modify the theme from what is in the
 * wrapped context.
 */
public class ContextThemeWrapper extends ContextWrapper {
    private Context mBase;
    private int mThemeResource;
    private Resources.Theme mTheme;
    private LayoutInflater mInflater;

    public ContextThemeWrapper() {
        super(null);
    }

    public ContextThemeWrapper(Context base, int themeres) {
        super(base);
        mBase = base;
        mThemeResource = themeres;
    }

    @Override protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
        mBase = newBase;
    }

    @Override public void setTheme(int resid) {
        mThemeResource = resid;
        initializeTheme();
    }

    @Override public Resources.Theme getTheme() {
        if (mTheme != null) {
            return mTheme;
        }

        if (mThemeResource == 0) {
            mThemeResource = com.android.internal.R.style.Theme;
        }
        initializeTheme();

        return mTheme;
    }

    @Override public Object getSystemService(String name) {
        if (LAYOUT_INFLATER_SERVICE.equals(name)) {
            if (mInflater == null) {
                mInflater = LayoutInflater.from(mBase).cloneInContext(this);
            }
            return mInflater;
        }
        return mBase.getSystemService(name);
    }

    /**
     * Called by {@link #setTheme} and {@link #getTheme} to apply a theme
     * resource to the current Theme object.  Can override to change the
     * default (simple) behavior.  This method will not be called in multiple
     * threads simultaneously.
     *
     * @param theme The Theme object being modified.
     * @param resid The theme style resource being applied to <var>theme</var>.
     * @param first Set to true if this is the first time a style is being
     *              applied to <var>theme</var>.
     */
    protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {
        theme.applyStyle(resid, true);
    }

    private void initializeTheme() {
        final boolean first = mTheme == null;
        if (first) {
            mTheme = getResources().newTheme();
            Resources.Theme theme = mBase.getTheme();
            if (theme != null) {
                mTheme.setTo(theme);
            }
        }
        onApplyThemeResource(mTheme, mThemeResource, first);
    }
}

究其根本,Activity、Service、Application都是Context的子类。所以,一个App中Context的数量就是Activity的数量 + Sercice的数量 + Application的数量(通常是1个)。


何时创建Context 

应用程序创建Context实例有如下几种情况:

  • 创建Application对象的时候, 而且整个App共一个Application对象
  • 创建Service对象的时候
  • 创建Activity对象的时候

1. 创建Application对象的时机

每个应用程序在第一次启动时,都会首先创建Application对象。如果对应用程序启动一个Activity(startActivity)流程比较清楚的话,创建Application的时机在创建handleBindApplication()方法中,该函数位于 ActivityThread.java类中,代码如下:

[java] view plaincopyprint?

  1. //创建Application时同时创建的ContextIml实例
  2. private final void handleBindApplication(AppBindData data){
  3. ...
  4. ///创建Application对象
  5. Application app = data.info.makeApplication(data.restrictedBackupMode, null);
  6. ...
  7. }
  8. public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
  9. ...
  10. try {
  11. java.lang.ClassLoader cl = getClassLoader();
  12. ContextImpl appContext = new ContextImpl();    //创建一个ContextImpl对象实例
  13. appContext.init(this, null, mActivityThread);  //初始化该ContextIml实例的相关属性
  14. ///新建一个Application对象
  15. app = mActivityThread.mInstrumentation.newApplication(
  16. cl, appClass, appContext);
  17. appContext.setOuterContext(app);  //将该Application实例传递给该ContextImpl实例
  18. }
  19. ...
  20. }

2. 创建Activity对象的时机

通过startActivity()或startActivityForResult()请求启动一个Activity时,如果系统检测需要新建一个Activity对象时,就会回调handleLaunchActivity()方法,该方法继而调用performLaunchActivity()方法,去创建一个Activity实例,并且回调onCreate(),onStart()方法等, 函数都位于 ActivityThread.java类,代码如下:

[java] view plaincopyprint?

  1. //创建一个Activity实例时同时创建ContextIml实例
  2. private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {
  3. ...
  4. Activity a = performLaunchActivity(r, customIntent);  //启动一个Activity
  5. }
  6. private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) {
  7. ...
  8. Activity activity = null;
  9. try {
  10. //创建一个Activity对象实例
  11. java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
  12. activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
  13. }
  14. if (activity != null) {
  15. ContextImpl appContext = new ContextImpl();      //创建一个Activity实例
  16. appContext.init(r.packageInfo, r.token, this);   //初始化该ContextIml实例的相关属性
  17. appContext.setOuterContext(activity);            //将该Activity信息传递给该ContextImpl实例
  18. ...
  19. }
  20. ...
  21. }

3. 创建Service对象的时机

通过startService或者bindService时,如果系统检测到需要新创建一个Service实例,就会回调handleCreateService()方法,完成相关数据操作。handleCreateService()函数位于 ActivityThread.java类,代码如下:

[java] view plaincopyprint?

  1. //创建一个Service实例时同时创建ContextIml实例
  2. private final void handleCreateService(CreateServiceData data){
  3. ...
  4. //创建一个Service实例
  5. Service service = null;
  6. try {
  7. java.lang.ClassLoader cl = packageInfo.getClassLoader();
  8. service = (Service) cl.loadClass(data.info.name).newInstance();
  9. } catch (Exception e) {
  10. }
  11. ...
  12. ContextImpl context = new ContextImpl(); //创建一个ContextImpl对象实例
  13. context.init(packageInfo, null, this);   //初始化该ContextIml实例的相关属性
  14. //获得我们之前创建的Application对象信息
  15. Application app = packageInfo.makeApplication(false, mInstrumentation);
  16. //将该Service信息传递给该ContextImpl实例
  17. context.setOuterContext(service);
  18. ...
  19. }

另外,需要注意的是,通过对ContextImp的分析可知,其方法的大多数操作都是直接调用其属性mPackageInfo(该属性类型为PackageInfo)的相关方法而来。这说明ContextImpl是一个轻量级的类,而PackageInfo才是真正重量级的类。而一个App里的所有ContextIml实例,都对应同一个packageInfo对象。

参考资料

http://blog.csdn.net/qinjuning/article/details/7310620

时间: 2024-11-13 12:01:42

【Android 内核研究】理解Context的相关文章

全面理解Context

(一).Android源码分析-全面理解Context (二).Android技术精髓-理解Context [源码]  

《深入理解Android内核设计思想》已陆续在全国各大书店及网上书店上市,感谢大家一直以来的支持~~

今天星期六了,不知道兄弟姐妹们有没有休息,妮子还在上班,努力着上班.最近总是给大家分享点技术有关的文章!好久没静下心和大家聊聊天.继续第三篇,谈SEOer论行业心态!我们每时每刻都在学习,百度也在每时每刻在更新算法.之前做的可能是对的,但现在不一定会对,为什么.之前觉得发外链就有排名,但现在发外链也不一定有排名.因为百度把我们之前认知的都给否定了.对今天谈谈如何否定曾经一些错误认识. 否定心态 在学习的路上,如何去分辨那些才是对的,那些是好的.这些都是客观性认为,在客观性中否定.妮子现在写的文章

Android内核开发:理解和掌握repo工具

由于Android源码是用repo工具来管理的,因此,搞Android内核开发,首先要搞清楚repo是什么东西,它该怎么使用?作为<Android内核开发>系列文章的第二篇,我们首先谈谈对repo工具的理解和使用. 1. repo是什么? repo是一种代码版本管理工具,它是由一系列的Python脚本组成,封装了一系列的Git命令,用来统一管理多个Git仓库. 2. 为什么要用repo? 因为Android源码引用了很多开源项目,每一个子项目都是一个Git仓库,每个Git仓库都有很多分支版本,

《深入理解Android内核设计思想》

<深入理解Android内核设计思想> 基本信息 作者: 林学森 出版社:人民邮电出版社 ISBN:9787115348418 上架时间:2014-4-25 出版日期:2014 年5月 开本:16开 页码:687 版次:1-1 所属分类:计算机 > 软件与程序设计 > 移动开发 > Android 更多关于>>><深入理解Android内核设计思想> 编辑推荐 基于Android SDK最新版本 全面细致地剖析了进程/线程模型.内存管理.Bind

《深入理解Android内核设计思想》书本目录,及部分章节内容分享

第1篇 android编译篇 第1章 android系统简介 2  1.1 android系统发展历程 2  1.2 android系统特点 4  1.3 android系统框架 8 第2章 android源码下载及编译 10  2.1 android源码下载指南 10  2.1.1 基于repo和git的版本管理 10  2.1.2 android源码下载流程 11  2.2 原生态系统编译指南 12    2.2.1 建立编译环境 13    2.2.2 编译流程 15  2.3 定制产品的

Android内核开发:序

转眼间我的<Android开发实践>系列文章已经写了三十多篇了,很多文章写得还是蛮用心的,所以很感谢51CTO的编辑们经常加精和推荐.我发现通过写作的确可以逼着自己去深入了解一些平时开发中并不会去挖掘的细节,这对自己帮助挺大的,后面遇到好的主题我还会继续写下去. 以前写的<Android开发实践>这个系列主要偏向Android应用层的开发,从一开始学习Android就计划好了要往底层深入,如今正好在工作中有机会涉及Android源码开发,因此,再开辟一个系列,就叫<Andro

Android内核开发:图解Android系统的启动过程

本文是<Android内核开发>系列的第六篇文章,前面的几篇文章介绍了Android内核开发相关的基础知识,包括:Android源码的下载.版本和分支介绍.编译和烧写等等,从本文起就要开始真正地进行Android内核的学习及实战了. 学习任何软硬件系统,研究系统启动过程都是一种非常有效地起步手段,搞Android内核开发也不例外.网上有很多文章对Android启动相关代码进行分析和走读,大家可以先搜索阅读一下,我个人更喜欢更加直观的方式去理解未知的东西,包括图.表.系统输出的log信息等等,因

Android安全研究经验谈

一.安全研究做什么 攻击角度:对某个模块进行漏洞挖掘的方法,对某个漏洞进行利用的技术,通过逆向工程破解程序.解密数据,对系统或应用进行感染.劫持等破坏安全性的攻击技术等. 防御角度:查杀恶意应用的方法,检测和防范漏洞利用,为增强系统和第三方应用的安全性提供解决方案等. 通常,攻与防是相对模糊的,一种安全技术往往两端都适用,也许更值得留意的是一种技术背后的思路和意识. 二.需要具备的知识 安全涉及的知识范畴是无限的,但大多数时候可以遇到问题再去了解相关知识. 三.要掌握的理论知识 操作系统原理,非

【转】Android安全研究经验谈

本文转载自:http://www.cnblogs.com/whp2011/archive/2015/01/26/4250875.html 一.安全研究做什么 攻击角度:对某个模块进行漏洞挖掘的方法,对某个漏洞进行利用的技术,通过逆向工程破解程序.解密数据,对系统或应用进行感染.劫持等破坏安全性的攻击技术等. 防御角度:查杀恶意应用的方法,检测和防范漏洞利用,为增强系统和第三方应用的安全性提供解决方案等. 通常,攻与防是相对模糊的,一种安全技术往往两端都适用,也许更值得留意的是一种技术背后的思路和