聊聊Android中的Context-初步分析Android中Context的实现

说到Context,大家一定非常熟悉,Android中的很多操作都和Context有关,比如打开activity、发送广播、打开本包下文件夹和数据库、获取classLoader、获取资源等等。那么这个Context究竟是何方神圣,我们不得而知,仅仅止步于如何使用Context,本篇将和大家一起聊聊Android中的Context。

Context架构设计

abm

Android Context的设计完美的体现了装饰模式,装饰模式的思想是在不改变原来类文件和使用继承的情况下动态的扩展类的功能。Context就是一个抽象接口,ContextImpl是该接口的实现,而ContextWrapper就是装饰者,Application,Service等等就是更加具体的装饰者。而这些接口实现和装饰者在Android中是如何联系在一起的呢?我们继续往下分析。

创建Context

我们知道有很多操作都依赖Context,比如启动Activity,启动Service……那么这些Context是在什么时候创建的呢?ActivityThread的main函数是应用程序的入口,我们就从main函数开始分析:

    public static void main(String[] args) {
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

继续看下ActivityThread的attach方法:

    private void attach(boolean system, long startSeq) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                @Override
                public void run() {
                    ensureJitEnabled();
                }
            });
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManager.getService();
            try {
                mgr.attachApplication(mAppThread, startSeq);//作用在于将mAppThread传递到AMS进程去,最后在AMS的attachApplicationLocked方法中会调用mAppThread的bindApplication方法
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        } else {//系统进程,暂不分析
        }
    }

根据分析,继续查看ApplicationThread的bindApplication方法,这里就不一一罗列代码了直接查看最终调用处理的handleBindApplication方法:

    private void handleBindApplication(AppBindData data) {
        long st_bindApp = SystemClock.uptimeMillis();
        // Note when this process has started.
        Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
        // send up app name; do this *before* waiting for debugger
        Process.setArgV0(data.processName);
        android.ddm.DdmHandleAppName.setAppName(data.processName,
                                                UserHandle.myUserId());
        VMRuntime.setProcessPackageName(data.appInfo.packageName);
 
        data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);//创建LoadedApk,LoadedApk就是Apk文件在内存中的表示
 
        try {
            app = data.info.makeApplication(data.restrictedBackupMode, null);//为应用创建Application
            mInitialApplication = app;
            try {
                mInstrumentation.callApplicationOnCreate(app);//调用Application的onCreate方法
            } catch (Exception e) {
            }
        } finally {
        }
    }

继续看下LoadedApk的makeApplication方法:

    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        Application app = null;
        try {
            java.lang.ClassLoader cl = getClassLoader();
            if (!mPackageName.equals("android")) {
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        "initializeJavaContextClassLoader");
                initializeJavaContextClassLoader();
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;
        return app;
    }
 
    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = getFactory(context.getPackageName())
                .instantiateApplication(cl, className);
        app.attach(context);
        return app;
    }
 
    final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }
 
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

终于守得云开见月明,终于在makeApplication看见创建ContextImpl,从Context架构设计一节中我们知道Application是一个装饰者,用来装饰谁呢?Context的实现类ContextImpl。当我们创建完Application时,此时Application中的mBase指向的就是我们通过createAppContext,其赋值的地方就是app.attach(context)。同时ContextImpl也通过设置setOuterContext与Application关联。同样的我们创建Activity和Service的时候也会创建对应的ContextImpl并且设置与ContextImpl关联。那么他们设置的关联有什么作用呢?答案肯定是有的,当我们在Activity中或者Application或者Service中或者调用某个Context的getBaseContext方法的时候,获取的便是这个ContextImp。再来看下Activity创建过程是如何管理ContextImpl的:

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
        }
 
        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
 
            if (activity != null) {
                appContext.setOuterContext(activity);
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);
            }
    }

其创建管理过程基本和Application相似。在类推一下Service估计也是一样,事实也是如此:

    private void handleCreateService(CreateServiceData data) {
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
        } catch (Exception e) {
        }
 
        try {
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
 
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            service.onCreate();
            mServices.put(data.token, service);
            try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
        }
    }

Android四大组件其中Activity和Service由于本身就是Context的子类并且在创建的时候又各自关联了ContextImpl,因此他们自身都是存在Context上下文的。

获取各种Context

最常见的方法就是通过this指针,当我们在Activity中,我们就可以通过this,来获取Activity的上下文Context,并且干点事情。这是最简单的获取Context的方式,Android还提供了一些其他的接口用来获取各种类型的Context。比如:getBaseContext(顾名思义,获取mBase所指的ContextImpl对象),getApplicationContext(获取的Application对象),getApplication(Activity和Service中有,获取所属的Application对象)。

写在最后

本篇文章在于讲解Android中Context的设计实现,以及初步了解Android中是如何创建使用Context,并未过多的涉及Context的使用,以及使用Context某个方法时深究其中的原理,这些都留于后面详细分析Android再一一讲解其中的原理实现。大家如果有兴趣也可以自行阅读源码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android开发Context是一个重要的概念,它代表了Android应用程序的当前状态和环境。它提供了访问应用程序资源(如布局、字符串等)和执行各种操作(如启动Activity、访问数据库等)的能力。 数据库在Android开发也是非常常见的,它用于存储和管理应用程序的数据。Android提供了SQLite数据库来支持本地数据存储。要在应用程序使用数据库,首先需要创建一个数据库实例,并获取对数据库的读写访问权限。这就是我们需要Context的原因之一。 通过Context,我们可以获取应用程序的上下文环境,包括访问数据库所需的一些关键组件,如ContentResolver和SQLiteOpenHelper。ContentResolver是用于访问应用程序的数据提供者的类,而SQLiteOpenHelper则是一个辅助类,用于管理SQLite数据库的创建和版本控制。 使用Context来访问数据库时,可以通过调用getApplicationContext()方法获取全局的应用程序上下文,或者通过调用Activity的getContext()方法获取当前活动的上下文。这样就可以使用上述提到的组件来执行与数据库相关的操作,例如插入、查询、更新和删除数据等。 总结一下,ContextAndroid是一个重要的概念,它提供了访问应用程序资源和执行各种操作的能力。而数据库则是Android开发常用的数据存储方式,通过Context可以获取对数据库的读写访问权限,并使用相关组件来操作数据库。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值