基于 Android Q 10.0 系统 LayoutInflater源码解析


我们知道Android程序运行是需要字节码的,在开发中布局使用的是View,而我们明明写的是XML文件,如何把XML文件转成View字节码呢?

没错,这就是LayoutInflater类的用途——xml文件解析成view的字节码

LayoutInflater的实例化有以下三种方式:

LayoutInflater inflater = LayoutInflater.from(context); 
LayoutInflater inflater = getLayoutInflater();  //需要在Activity派生类下才可以使用
LayoutInflater inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

以上三种方式最终的实现都是下面呢这段代码:

 LayoutInflater mLayoutInflater =
          (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

看起来好像很简单,获取系统服务得到了一个LayoutInflater对象,难点是:

@SystemService(Context.LAYOUT_INFLATER_SERVICE)
public abstract class LayoutInflater {
   //这是个抽象类,上文中的mLayoutInflater到底是LayoutInflater的哪个派生类的实例呢?
}

1 Context.java

public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);

这是一个抽象方法并没有具体实现,我们一般的context传入的都是Activity

2 Activity.java

@Override
public Object getSystemService(@ServiceName @NonNull String name) {
    if (getBaseContext() == null) {
        throw new IllegalStateException(
                "System services not available to Activities before onCreate()");
    }

    if (WINDOW_SERVICE.equals(name)) {
        return mWindowManager;
    } else if (SEARCH_SERVICE.equals(name)) {
        ensureSearchManager();
        return mSearchManager;
    }
    //交给其父类处理
    return super.getSystemService(name);
}

3 ContextThemeWrapper.java

@Override
public Object getSystemService(String name) {
    if (LAYOUT_INFLATER_SERVICE.equals(name)) {
        if (mInflater == null) {
          //name就是LAYOUT_INFLATER_SERVICE,现在陷入到了鸡生蛋蛋生鸡的问题
          // getBaseContext()是什么?或许能从这里找到新的内容?
            mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
        }
        return mInflater;
    }
    return getBaseContext().getSystemService(name);
}

//也是返回一个Context,猜想会不会activity的mInflater其实就是这个mBase的mInflater呢?
public Context getBaseContext() {
        return mBase;
    }

//找找这个mBase在哪里被赋值的

4 ContextWrapper.java

赋值的操作只有在这里出现,所以修改Base属性的地方只可能调用这两个方法

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

//attachBaseContext看起来有点眼熟,感觉可能性更大点
protected void attachBaseContext(Context base) {
    if (mBase != null) {
        throw new IllegalStateException("Base context already set");
    }
    mBase = base;
}

Back 2 Activity.java

Activity.java<--ContextThemeWrapper.java<--ContextWrapper.java

  
@Override
protected void attachBaseContext(Context newBase) {
  // 这行代码层层转交给父类的父类ContextWrapper去执行
    super.attachBaseContext(newBase);
    if (newBase != null) {
        newBase.setAutofillClient(this);
        newBase.setContentCaptureOptions(getContentCaptureOptions());
    }
}

//继续看看attachBaseContext在哪里使用的
final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
       //下面调用绑定context
        attachBaseContext(context);
        mFragments.attachHost(null /*parent*/);
       //Activity其实创建了一个新的PhoneWindow对象
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
       // Activity的mLayoutInflater设置了私有工厂,工厂就是这个Activity,后续会在提到
        mWindow.getLayoutInflater().setPrivateFactory(this);
}

//attach又在哪里被调用了呢?
其实是在ActivityThread.java中的performLaunchActivity方法,上篇博客没有提到,所以这里补充一下下

5 ActivityThread.java

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
     //其实appContext是一个ContextImpl对象
    ContextImpl appContext = createBaseContextForActivity(r);
    //context设置了outerContext是activity,后面会用到
    appContext.setOuterContext(activity);
    //Activity也是attach这个appContext
    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,
                        r.assistToken); 
   ...
}

//如果有疑惑可以继续往下深挖是不是一个ContextImpl实例,确实返回的是ContextImpl对象
createBaseContextForActivity()-->ContextImpl.createActivityContext()--> ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
                activityToken, null, 0, classLoader, null);

Back 3 ContextThemeWrapper.java

@Override
public Object getSystemService(String name) {
    if (LAYOUT_INFLATER_SERVICE.equals(name)) {
        if (mInflater == null) {
            //等价于  mInflater = LayoutInflater.from(new ContextImpl()).cloneInContext(this);
            //等价于  new ContextImpl().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
        }
        return mInflater;
    }
    return getBaseContext().getSystemService(name);
}

6 ContextImpl.java

@Override
public Object getSystemService(String name) {
    return SystemServiceRegistry.getSystemService(this, name);
}

7 SystemServiceRegistry.java

public static Object getSystemService(ContextImpl ctx, String name) {
    ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    return fetcher != null ? fetcher.getService(ctx) : null;
}

//SYSTEM_SERVICE_FETCHERS是一个map
 private static final Map<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new ArrayMap<String, ServiceFetcher<?>>();

//在哪里map进行写操作的呢?

private static <T> void registerService(String serviceName, Class<T> serviceClass,
            ServiceFetcher<T> serviceFetcher) {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    }
//类初始化的时候就进行注册,基本上所有context.getSystemService都是在这里进行注册的
static {
  ...
   registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
                new CachedServiceFetcher<LayoutInflater>() {
            @Override
            public LayoutInflater createService(ContextImpl ctx) {
                //经过一番找寻,我们锁定上文中的mLayoutInflate是PhoneLayoutInflater对象
                return new PhoneLayoutInflater(ctx.getOuterContext());
            }});
  ...
}

Back 3 ContextThemeWrapper.java

@Override
public Object getSystemService(String name) {
    if (LAYOUT_INFLATER_SERVICE.equals(name)) {
        if (mInflater == null) {
            //等价于  mInflater = new PhoneLayoutInflater(ctx.getOuterContext()).cloneInContext(this)
            mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
        }
        return mInflater;
    }
    return getBaseContext().getSystemService(name);
}

8 PhoneLayoutInflater.java

public class PhoneLayoutInflater extends LayoutInflater {
    private static final String[] sClassPrefixList = {
        "android.widget.",
        "android.webkit.",
        "android.app."
    };

 
    public PhoneLayoutInflater(Context context) {
        super(context);
    }

    protected PhoneLayoutInflater(LayoutInflater original, Context newContext) {
        super(original, newContext);
    }

  
    @Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
        for (String prefix : sClassPrefixList) {
            try {
                View view = createView(name, prefix, attrs);
                if (view != null) {
                    return view;
                }
            } catch (ClassNotFoundException e) {
                // In this case we want to let the base class take a crack
                // at it.
            }
        }

        return super.onCreateView(name, attrs);
    }

  //1   其实是拷贝自调用PhoneLayoutInflater(LayoutInflater original, Context newContext)
    public LayoutInflater cloneInContext(Context newContext) {
        return new PhoneLayoutInflater(this, newContext);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值