Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

源码中的单例模式 #30

Open
cnwutianhao opened this issue Mar 12, 2024 · 0 comments
Open

源码中的单例模式 #30

cnwutianhao opened this issue Mar 12, 2024 · 0 comments

Comments

@cnwutianhao
Copy link
Owner

cnwutianhao commented Mar 12, 2024

本文是基于 Android 14 的源码解析

在 Android 系统中,我们经常会通过 Context 获取系统级别的服务,如 WindowsManagerService、ActivityManagerService 等,更常用的是一个 LayoutInflater 的类,这些服务会在合适的时候以单例的形式注册在系统中,在我们需要的时候就通过 Context 的 getSystemService(String name) 获取。

我们以 LayoutInflater 为例来说明,平时我们使用 LayoutInflater 较为常见的地方是在 RecyclerView 的 onCreateViewHolder 方法中:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TestViewHolder {
    return TestViewHolder(
        ListItemTestBinding.inflate(
            LayoutInflater.from(parent.context), parent, false
        )
    )
}

通常我们使用 LayoutInflater.from(Context context) 来获取 LayoutInflater 服务,下面看看源码实现:

public static LayoutInflater from(@UiContext Context context) {
    LayoutInflater LayoutInflater =
            (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    if (LayoutInflater == null) {
        throw new AssertionError("LayoutInflater not found.");
    }
    return LayoutInflater;
}

可以看到 from(Context context) 函数内部调用的是 Context 类的 getSystemService(String name) 方法,我们跟踪到 Context 类看到,该类是抽象类:

public abstract class Context {
    ...
}

onCreateViewHolder 中使用的 Context 对象的具体实现类是什么呢?其实在 Application、Activity、Service 中都会存在一个 Context 对象,即 Context 的总个数为 Activity 个数 + Service 个数 + 1。而 RecyclerView 通常都是显示在 Activity 中,那么我们就以 Activity 中的 Context 来分析。

我们知道,一个 Activity 的入口是 ActivityThread 的 main 函数,在 main 函数中创建一个新的 ActivityThread 对象,并且启动消息循环(UI线程),创建新的 Activity、新的 Context 对象,然后将该 Context 对象传递给 Activity。下面看看 ActivityThread 源代码:

// 源码路径:/frameworks/base/core/java/android/app/ActivityThread.java

public static void main(String[] args) {
    ...

    // 主线程消息循环
    Looper.prepareMainLooper();

    ...

    // 创建ActivityThread对象
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);

    ...

    Looper.loop();

    ...
}
// 源码路径:/frameworks/base/core/java/android/app/ActivityThread.java

private void attach(boolean system, long startSeq) {
    ...

    // 不是系统应用的情况
    if (!system) {
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                UserHandle.myUserId());
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        final IActivityManager mgr = ActivityManager.getService();
        try {
            // 关联 mAppThread
            mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
            ...
        }
        
        ...
    } else {
        ...
    }

    ...
}

在 main 方法中,创建一个 ActivityThread 对象后,调用了其 attach 函数,并且参数为 false。在 attach 函数中,参数为 false 的情况下(即非系统应用),会通过 Binder 机制与 ActivityManager Service 通信,并且最终调用 handleLaunchActivity 函数,我们看看该函数的实现:

// 源码路径:/frameworks/base/core/java/android/app/ActivityThread.java

public Activity handleLaunchActivity(ActivityClientRecord r,
        PendingTransactionActions pendingActions, int deviceId, Intent customIntent) {
    ...

    final Activity a = performLaunchActivity(r, customIntent);

    ...
}
// 源码路径:/frameworks/base/core/java/android/app/ActivityThread.java

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...

    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        // 创建Activity
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);

        ...
    } catch (Exception e) {
        ...
    }

    try {
        // 创建 Application 对象
        Application app = r.packageInfo.makeApplicationInner(false, mInstrumentation);

        ...

        if (activity != null) {
            // 获取 Context 对象
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config =
                    new Configuration(mConfigurationController.getCompatConfiguration());
            
            ...

            // 将 appContext 等对象 attach 到 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.activityConfigCallback,
                    r.assistToken, r.shareableActivityToken);

            ...
            
            if (r.isPersistable()) {
                ...
            } else {
                // 调用 Activity 的 onCreate 方法
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }

            ...
        }
        r.setState(ON_CREATE);

    } catch (SuperNotCalledException e) {
        ...
    } catch (Exception e) {
        ...
    }

    return activity;
}
// 源码路径:/frameworks/base/core/java/android/app/ActivityThread.java

private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
    final int displayId = ActivityClient.getInstance().getDisplayId(r.token);
    // 创建 Context 对象, 可以看到实现类是 ContextImpl
    ContextImpl appContext = ContextImpl.createActivityContext(
            this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);

    final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
    String pkgName = SystemProperties.get("debug.second-display.pkg");
    if (pkgName != null && !pkgName.isEmpty()
            && r.packageInfo.mPackageName.contains(pkgName)) {
        for (int id : dm.getDisplayIds()) {
            if (id != DEFAULT_DISPLAY) {
                Display display =
                        dm.getCompatibleDisplay(id, appContext.getResources());
                appContext = (ContextImpl) appContext.createDisplayContext(display);
                break;
            }
        }
    }
    return appContext;
}

通过上面的代码分析可以知道,Context 的实现类为 ComtextImpl。我们继续跟踪 ContextImpl 类:

// 源码路径:/frameworks/base/core/java/android/app/ContextImpl.java

class ContextImpl extends Context {

    ...

    @UnsupportedAppUsage
    final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();

    ...

    @Override
    public Object getSystemService(String name) {
        ...

        return SystemServiceRegistry.getSystemService(this, name);
    }

    ...
}
// 源码路径:/frameworks/base/core/java/android/app/SystemServiceRegistry.java

public final class SystemServiceRegistry {
    ...

    // Service 容器
    private static final Map<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new ArrayMap<String, ServiceFetcher<?>>();
    private static int sServiceCacheSize;

    ...

    // 静态语句块,第—次加载该类时执行(只执行—次,保证实例的唯一性)
    static {
        registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
                new CachedServiceFetcher<LayoutInflater>() {
            @Override
            public LayoutInflater createService(ContextImpl ctx) {
                return new PhoneLayoutInflater(ctx.getOuterContext());
            }});
    }

    ...

    public static Object[] createServiceCache() {
        return new Object[sServiceCacheSize];
    }

    // 根据 key 获取对应的服务
    public static Object getSystemService(ContextImpl ctx, String name) {
        ...
        
        final ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        
        ...

        final Object ret = fetcher.getService(ctx);
        
        ...

        return ret;
    }

    // 注册 Service
    private static <T> void registerService(@NonNull String serviceName,
            @NonNull Class<T> serviceClass, @NonNull ServiceFetcher<T> serviceFetcher) {
        ...

        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
        
        ...
    }

    ...
}

从 ContextImpl 类的部分代码中可以看到,在虚拟机第一次加载该类时会注册各种 ServiceFetcher,其中就包含了 LayoutInflater Service。将这些服务以键值对的形式存储在一个 Map 中,用户使用时只需要根据 key 来获取到对应的 ServiceFetcher,然后通过 ServiceFetcher 对象的 getService 函数来获取具体的服务对象。当第一次获取时,会调用 ServiceFetcher 的 createService 函数创建服务对象,然后将该对象缓存到一个列表中,下次再取时直接从缓存中获取,避免重复创建对象,从而达到单例的效果。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant