• FrameWork内核解析之布局加载与资源系统(三)


    阿里P7Android高级架构进阶视频免费学习请点击:https://space.bilibili.com/474380680
    本篇文章将继续从以下两个内容来介绍布局加载与资源系统:

    • [ LayoutManager]
    • [ Resources 和 AssetManager]

    一、LayoutManager

    流程

    继承RecyclerView.LayoutManager
    重写onLayoutChildren来添加子View
    重写scrollVerticallyBy来实现竖向滚动
    继承RecyclerView.LayoutManager
    就一个抽象方法,重写就行了

    public class CustomLayoutManager extends RecyclerView.LayoutManager {
        @Override
        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
        }
    }
    

    onLayoutChildren

    相当于ViewGroup的 onLayout.一开始的界面构建就是这个入口

    1 在RecyclerView初始化时,会被调用两次。
    2 在调用adapter.notifyDataSetChanged()时,会被调用。
    3 在调用setAdapter替换Adapter时,会被调用。
    4 在RecyclerView执行动画时,它也会被调用。

    onLayoutChildren中的流程

    报废当前的View
    获取对应位置的子view
    添加进RecyclerView
    测量子View的宽高
    根据测量的宽高,给他们排列好位置
    注意,这一版本是没考虑缓存,全一股脑添加进RecyclerView的,目的是熟悉代码为后面铺垫
    其中的函数

    detachAndScrapAttachedViews : 是将当前Recycler中的view全部移除并放到报废缓存里,之后优先重用缓存里的view
    getDecoratedMeasuredWidth/getDecoratedMeasuredHeight 获取宽高,这个是加上了DecorateView
    的,现在没有 RecyclerView.addItemDecoration();直接理解为宽高就行
    layoutDecorated就是用来个子View排位置的
    actualHeight记录了目前的高度,为了实现LinearLayoutManager的垂直排序来的
    然后看看具体代码吧

    @Override
        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
            if (getItemCount() == 0){
                detachAndScrapAttachedViews(recycler);
                return;
            }
            //state.isPreLayout()是支持动画的
            if (getItemCount() == 0 && state.isPreLayout()){
                return;
            }
    
            detachAndScrapAttachedViews(recycler);
    
            actualHeight = 0;
            for (int i = 0 ;i < getItemCount() ; i++){
                View scrap = recycler.getViewForPosition(i);
                addView(scrap);
                measureChildWithMargins(scrap,0,0);
                int width = getDecoratedMeasuredWidth(scrap);
                int height = getDecoratedMeasuredHeight(scrap);
                layoutDecorated(scrap,0,actualHeight,width,actualHeight+height);
                actualHeight+=height;
            }
        }
    

    测试的Activity

    public class LayoutManagerActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_layout_manager);
            CustomLayoutManager customLayoutManager = new CustomLayoutManager();
            RecyclerView rv = findViewById(R.id.rv);
            rv.setLayoutManager(customLayoutManager);
            rv.setAdapter(new RecyclerView.Adapter<VH>() {
                @NonNull
                @Override
                public VH onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
                    View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_custom,viewGroup,false);
                    Log.d("LayoutManagerActivity","onCreateViewHolder " + i);
                    return new VH(view);
                }
    
                @Override
                public void onBindViewHolder(@NonNull VH viewHolder, int i) {
                    viewHolder.tv.setText(i+"");
                    if (i%2 == 0){
                        viewHolder.tv.setBackgroundColor(Color.RED);
                    }else {
                        viewHolder.tv.setBackgroundColor(Color.BLUE);
                    }
                    Log.d("LayoutManagerActivity","onBindViewHolder " + i);
                }
    
                @Override
                public int getItemCount() {
                    return 20;
                }
            });
        }
    
        private static class VH extends RecyclerView.ViewHolder{
    
            TextView tv ;
            public VH(@NonNull View itemView) {
                super(itemView);
                tv = itemView.findViewById(R.id.tv);
            }
        }
    }
    

    就可以看到布局排列好了.但是

    onCreateViewHolder调用了20次,onBindViewHolder也调用了20.不能滑动
    滑动
    canScrollVertically返回true就是可以垂直滑动
    scrollVerticallyBy是滑动具体的逻辑
    scrollVerticallyBy的参数要说明下

    参数:
    dy : 是当前滑动的距离,界面向下滚动的时候,dy为正,向上滚动的时候dy为负
    返回的值: 如果Math.abs(返回值)小于dy,说明到达边界了,这里简单的处理下,如果到达边界了直接返回0

    逻辑
    通过totalScrollY来记录已经滑动的总距离
    向下滚动的时候,如果总距离超过了子view的总高度-屏幕高度,说明到达下边界了
    向上滚动的时候,如果总距离小于等于0,就是到达了上边界
    其他就是正常情况了,使用offsetChildrenVertical来滚动界面
    具体如下

    @Override
        public boolean canScrollVertically() {
            return true;
        }
    
    
        @Override
        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
            //界面向下滚动的时候,dy为正,向上滚动的时候dy为负
    
            //向下滚动的时候,最下面的值不能超过总值,
            //向上滚动的时候,最上面的值不能小于0
            int willScrollTo = totalScrollY + dy;
            Log.d(TAG,"scrollVerticallyBy " + dy + " totalScrollY " + totalScrollY);
            if (willScrollTo >= actualHeight-getHeight()){
                offsetChildrenVertical(-1*(actualHeight - getHeight() - totalScrollY));
                totalScrollY = actualHeight- getHeight();
                return 0;
            }
            if (willScrollTo <= 0){
                offsetChildrenVertical(totalScrollY);
                totalScrollY = 0;
                return 0;
            }
            offsetChildrenVertical(dy*-1);
            totalScrollY +=dy;
    
            return dy;
        }
    

    这样就完成了简陋版的LinearLayoutManager.完整代码

    /**
     * 只有填充,滑动,没有回收
     */
    public class CustomLayoutManager extends RecyclerView.LayoutManager {
        private final String TAG = "feifeifei";
    
        private int actualHeight = 0;
        private int totalScrollY = 0;
        @Override
        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
        }
    
        @Override
        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
            if (getItemCount() == 0){
                detachAndScrapAttachedViews(recycler);
                return;
            }
            //state.isPreLayout()是支持动画的
            if (getItemCount() == 0 && state.isPreLayout()){
                return;
            }
    
            detachAndScrapAttachedViews(recycler);
    
            actualHeight = 0;
            for (int i = 0 ;i < getItemCount() ; i++){
                View scrap = recycler.getViewForPosition(i);
                addView(scrap);
                measureChildWithMargins(scrap,0,0);
                int width = getDecoratedMeasuredWidth(scrap);
                int height = getDecoratedMeasuredHeight(scrap);
                layoutDecorated(scrap,0,actualHeight,width,actualHeight+height);
                actualHeight+=height;
            }
        }
    
        @Override
        public boolean canScrollVertically() {
            return true;
        }
    
    
        @Override
        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
            //界面向下滚动的时候,dy为正,向上滚动的时候dy为负
    
            //向下滚动的时候,最下面的值不能超过总值,
            //向上滚动的时候,最上面的值不能小于0
            int willScrollTo = totalScrollY + dy;
            Log.d(TAG,"scrollVerticallyBy " + dy + " totalScrollY " + totalScrollY);
            if (willScrollTo >= actualHeight-getHeight()){
                offsetChildrenVertical(-1*(actualHeight - getHeight() - totalScrollY));
                totalScrollY = actualHeight- getHeight();
                return 0;
            }
            if (willScrollTo <= 0){
                offsetChildrenVertical(totalScrollY);
                totalScrollY = 0;
                return 0;
            }
            offsetChildrenVertical(dy*-1);
            totalScrollY +=dy;
    
            return dy;
        }
    }
    

    加入回收功能

    其实就是基于上边的简陋版本进行扩展

    onLayoutChildren的时候不添加全部view,只添加可视范围内的View
    滑动的时候要更复杂一点
    如果向下滚动,先往RecyclerView下面添加即将展示的View
    如果往上滚动,就往RecyclerView上面添加即将展示的View
    添加完View后就调用offsetChildrenVertical进行滚动
    完了后检查是否有子View离开了可视界面,如果不可见了,就是用removeAndRecycleView来移除掉
    onLayoutChildren
    与之前不同的就是最后几句,如果超过RecyclerView的高度了,就不Add了

     @Override
        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
            Log.d(TAG,"onLayoutChildren ");
            if (getItemCount() == 0){
                detachAndScrapAttachedViews(recycler);
                return;
            }
            //state.isPreLayout()是支持动画的
            if (getItemCount() == 0 && state.isPreLayout()){
                return;
            }
            //将当前Recycler中的view全部移除并放到报废缓存里,之后优先重用缓存里的view
            detachAndScrapAttachedViews(recycler);
    
            int actualHeight = 0;
            for (int i = 0 ;i < getItemCount() ; i++){
                View scrap = recycler.getViewForPosition(i);
                addView(scrap);
                measureChildWithMargins(scrap,0,0);
                int width = getDecoratedMeasuredWidth(scrap);
                int height = getDecoratedMeasuredHeight(scrap);
                layoutDecorated(scrap,0,actualHeight,width,actualHeight+height);
                actualHeight+=height;
                //超出界面的就不画了,也不add了
                if (actualHeight > getHeight()){
                    break;
                }
            }
        }
    

    scrollVerticallyBy
    之前说了,分为填充,滚动,回收

    @Override
        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
            Log.d("feifeifei","getChildCount() " + getChildCount() + " recycler.getScrapList().size() " + recycler.getScrapList().size());
    
            //界面向下滚动的时候,dy为正,向上滚动的时候dy为负
    
            //向下滚动的时候,最下面的值不能超过总值,
            //向上滚动的时候,最上面的值不能小于0
       
            //填充
            fill(dy,recycler,state);
            //滚动
            offsetChildrenVertical(dy*-1);
    
            //回收已经离开界面的
            recycleOut(dy,recycler,state);
    
    
            return dy;
        }
    

    填充

    例如向下滚动

    通过getChildAt获取最后一个View
    再通过getPosition获取这个View的Adapter中的位置,最后一个了,就不要继续填充了,因为没有了,如果有下一个,就继续
    这里还没有滑动,但是即将滑动的距离dy传进来了,如果最后一个View滑动dy后小于RecyclerView的高度了说明最后一个View已经全部出现在界面上了,之后就是空白了,需要添加新的子View
    那就做获取,测量,添加操作
    向上滚动是一样的逻辑

    private void fill(int dy, RecyclerView.Recycler recycler, RecyclerView.State state){
            //向下滚动
            if (dy > 0){
                //先在底部填充
                View  lastView = getChildAt(getChildCount() -1);
                int lastPos = getPosition(lastView);
                if (lastPos == getChildCount()-1){
                    return;
                }
                Log.d("feifeifei","lastView top" + lastView.getTop() + " bottom " + lastView.getBottom());
                if (lastView.getBottom() -  dy < getHeight()){
                    View scrap = recycler.getViewForPosition(lastPos+1);
                    addView(scrap);
                    measureChildWithMargins(scrap,0,0);
                    int width = getDecoratedMeasuredWidth(scrap);
                    int height = getDecoratedMeasuredHeight(scrap);
                    layoutDecorated(scrap,0,lastView.getBottom(),width,lastView.getBottom()+height);
                }
            }else {
                //向上滚动
                //现在顶部填充
                View  firstView = getChildAt(0);
                Log.d("feifeifei","firstView top" + firstView.getTop() + " bottom " + firstView.getBottom());
                int layoutPostion = getPosition(firstView);
                if (layoutPostion == 0){
                    return;
                }
                if (firstView.getTop() >= 0 ){
                    View scrap = recycler.getViewForPosition(layoutPostion -1);
                    addView(scrap,0);
                    measureChildWithMargins(scrap,0,0);
                    int width = getDecoratedMeasuredWidth(scrap);
                    int height = getDecoratedMeasuredHeight(scrap);
                    layoutDecorated(scrap,0,firstView.getTop() - height,width,firstView.getTop());
                }
            }
        }
    

    滚动

    滚动就是直接用offsetChildrenVertical(dy*-1);但是需要和简陋版一样,需要搞定边界问题
    例如: 到达上边界后,滑动的距离不是dy,而是第一个View还剩下多少距离可以滑动,代码如下

            int canScroll = dy;
            if (dy>0){
                View  lastView = getChildAt(getChildCount() -1);
                int lastPos = getPosition(lastView);
                if (lastPos >= getItemCount()-1){
                    if (lastView.getBottom() - dy < getHeight()){
                        canScroll = lastView.getBottom() - getHeight();
                        offsetChildrenVertical(canScroll*-1);
                        return 0;
                    }
                }
            }else {
                View  firView = getChildAt(0);
                int firstPos = getPosition(firView);
                if (firstPos <= 0){
                    if (firView.getTop() - dy >= 0){
                        canScroll = firView.getTop();
                        offsetChildrenVertical(canScroll*-1);
                        return 0;
                    }
                }
            }
    

    回收

    通过getChildCount() 获取当前所有的子View
    例如向上滚动,name就回收最下面的,最下面的View的top滑动后超出了RecyclerView的高度,说明这个View全部在界面外了,可以回收了,使用removeAndRecycleView移除并回收
    向下滚动就判断顶部的Bottom是否小于0

        private void recycleOut(int dy, RecyclerView.Recycler recycler, RecyclerView.State state){
            for (int i = 0 ; i <getChildCount() ;i++){
                View view = getChildAt(i);
                Log.d("feifeifei","recycleOut position "+ i + " top " + view.getTop() + " bottom " + view.getBottom());
                if (dy >0){
                    if (view.getBottom()-dy <0){
                        Log.d("feifeifei","recycleOut " + i);
                        removeAndRecycleView(view,recycler);
                    }
                }else {
                    if (view.getTop()-dy > getHeight()){
                        Log.d("feifeifei","recycleOut " + i);
                        removeAndRecycleView(view,recycler);
                    }
                }
            }
        }
    

    这样带回收的LayoutManager也完成了,全部代码如下

    /**
     * 填充,滑动,回收
     */
    public class CustomLayoutManager2 extends RecyclerView.LayoutManager {
        private final String TAG = CustomLayoutManager2.class.getSimpleName();
    
    
        @Override
        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
        }
    
    //    1 在RecyclerView初始化时,会被调用两次。
    //    2 在调用adapter.notifyDataSetChanged()时,会被调用。
    //    3 在调用setAdapter替换Adapter时,会被调用。
    //    4 在RecyclerView执行动画时,它也会被调用。
        @Override
        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
            Log.d(TAG,"onLayoutChildren ");
            if (getItemCount() == 0){
                detachAndScrapAttachedViews(recycler);
                return;
            }
            //state.isPreLayout()是支持动画的
            if (getItemCount() == 0 && state.isPreLayout()){
                return;
            }
            //将当前Recycler中的view全部移除并放到报废缓存里,之后优先重用缓存里的view
            detachAndScrapAttachedViews(recycler);
    
            int actualHeight = 0;
            for (int i = 0 ;i < getItemCount() ; i++){
                View scrap = recycler.getViewForPosition(i);
                addView(scrap);
                measureChildWithMargins(scrap,0,0);
                int width = getDecoratedMeasuredWidth(scrap);
                int height = getDecoratedMeasuredHeight(scrap);
                layoutDecorated(scrap,0,actualHeight,width,actualHeight+height);
                actualHeight+=height;
                //超出界面的就不画了,也不add了
                if (actualHeight > getHeight()){
                    break;
                }
            }
        }
    
        @Override
        public boolean canScrollVertically() {
            return true;
        }
    
    
        @Override
        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
            Log.d("feifeifei","getChildCount() " + getChildCount() + " recycler.getScrapList().size() " + recycler.getScrapList().size());
    
            //界面向下滚动的时候,dy为正,向上滚动的时候dy为负
    
            //向下滚动的时候,最下面的值不能超过总值,
            //向上滚动的时候,最上面的值不能小于0
            int canScroll = dy;
            if (dy>0){
                View  lastView = getChildAt(getChildCount() -1);
                int lastPos = getPosition(lastView);
                if (lastPos >= getItemCount()-1){
                    if (lastView.getBottom() - dy < getHeight()){
                        canScroll = lastView.getBottom() - getHeight();
                        offsetChildrenVertical(canScroll*-1);
                        return 0;
                    }
                }
            }else {
                View  firView = getChildAt(0);
                int firstPos = getPosition(firView);
                if (firstPos <= 0){
                    if (firView.getTop() - dy >= 0){
                        canScroll = firView.getTop();
                        offsetChildrenVertical(canScroll*-1);
                        return 0;
                    }
                }
            }
    
            //底部填充
            fill(dy,recycler,state);
            //滚动
            offsetChildrenVertical(dy*-1);
    
            //回收已经离开界面的
            recycleOut(dy,recycler,state);
    
    
            return dy;
        }
    
        private void fill(int dy, RecyclerView.Recycler recycler, RecyclerView.State state){
            //向下滚动
            if (dy > 0){
                //先在底部填充
                View  lastView = getChildAt(getChildCount() -1);
                int lastPos = getPosition(lastView);
                if (lastPos == getChildCount()-1){
                    return;
                }
                Log.d("feifeifei","lastView top" + lastView.getTop() + " bottom " + lastView.getBottom());
                if (lastView.getBottom() -  dy < getHeight()){
                    View scrap = recycler.getViewForPosition(lastPos+1);
                    addView(scrap);
                    measureChildWithMargins(scrap,0,0);
                    int width = getDecoratedMeasuredWidth(scrap);
                    int height = getDecoratedMeasuredHeight(scrap);
                    layoutDecorated(scrap,0,lastView.getBottom(),width,lastView.getBottom()+height);
    //                bottomItemPos++;
                }
            }else {
                //向上滚动
                //现在顶部填充
                View  firstView = getChildAt(0);
                Log.d("feifeifei","firstView top" + firstView.getTop() + " bottom " + firstView.getBottom());
                int layoutPostion = getPosition(firstView);
                if (layoutPostion == 0){
                    return;
                }
                if (firstView.getTop() >= 0 ){
                    View scrap = recycler.getViewForPosition(layoutPostion -1);
                    addView(scrap,0);
                    measureChildWithMargins(scrap,0,0);
                    int width = getDecoratedMeasuredWidth(scrap);
                    int height = getDecoratedMeasuredHeight(scrap);
                    layoutDecorated(scrap,0,firstView.getTop() - height,width,firstView.getTop());
                }
            }
        }
    
            private void recycleOut(int dy, RecyclerView.Recycler recycler, RecyclerView.State state){
                for (int i = 0 ; i <getChildCount() ;i++){
                    View view = getChildAt(i);
    
        //            Log.d("feifeifei","recycleOut position "+ i + " getDecoratedTop " + getDecoratedTop(view) + " getDecoratedBottom " + getDecoratedBottom(view));
                    Log.d("feifeifei","recycleOut position "+ i + " top " + view.getTop() + " bottom " + view.getBottom());
    
                    if (dy >0){
                        if (view.getBottom()-dy <0){
                            Log.d("feifeifei","recycleOut " + i);
                            removeAndRecycleView(view,recycler);
                        }
                    }else {
                        if (view.getTop()-dy > getHeight()){
                            Log.d("feifeifei","recycleOut " + i);
                            removeAndRecycleView(view,recycler);
                        }
                    }
                }
            }
    }
    

    然后通过adapter打印日志,onCreateViewHolder只打印了7次(我的界面上显示的7个item),然后滚动界面的时候,onBindViewHolder依次打印.看来回收还是成功的.这样一个简单版的带回收的LinearLayoutManager就好了

    二、Resources 和 AssetManager

    在 Android 开发中我们使用 Resources 来获取 res 目录下的各种与设备相关的资源。而使用 AssetManager 来获取 assets 目录下的资源。

    一般来说 Resources 对象通过 Context 获得。
    appContext 中的 resources 是在创建之后通过如下代码设置。
    context.setResources(packageInfo.getResources());
    而 LoadedApk 中则是通过如下代码创建:

                mResources = ResourcesManager.getInstance().getResources(null, mResDir,
                        splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
                        Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
                        getClassLoader());
    

    其中 mResDir 对应 ApplicationInfo.sourceDir 字段

        /**
         * Full path to the base APK for this application.
         */
        public String sourceDir;
    

    ResourcesManager.getInstance().getResources 的主要逻辑如下:

     final ResourcesKey key = new ResourcesKey(
                        resDir,
                        splitResDirs,
                        overlayDirs,
                        libDirs,
                        displayId,
                        overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
                        compatInfo);
                classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
                return getOrCreateResources(activityToken, key, classLoader);
    

    getOrCreateResources 主要逻辑如下:

     // 1) 先创建 ResourcesImpl
     ResourcesImpl resourcesImpl = createResourcesImpl(key);
    // 2) 再创建 Resources
     resources = getOrCreateResourcesLocked(classLoader, resourcesImpl, key.mCompatInfo);
    createResourcewImpl 主要逻辑如下:
    
      final AssetManager assets = createAssetManager(key);
            if (assets == null) {
                return null;
            }
    
            final DisplayMetrics dm = getDisplayMetrics(key.mDisplayId, daj);
            final Configuration config = generateConfig(key, dm);
            final ResourcesImpl impl = new ResourcesImpl(assets, dm, config, daj);
    
            return impl;
    

    其中 createAssetManager(key) 的主要逻辑如下:

    // 1) 创建 assets 对象实例。
      AssetManager assets = new AssetManager();
    // 2) 添加各资源目录。
    assets.addAssetPath(key.mResDir)
    assets.addAssetPath(splitResDir) 
    assets.addOverlayPath(idmapPath);
    assets.addAssetPathAsSharedLibrary(libDir) 
    

    最终 Resources 的创建逻辑如下:

    // getOrCreateResourcesLocked
            Resources resources = compatInfo.needsCompatResources() ? new CompatResources(classLoader)
                    : new Resources(classLoader);
            resources.setImpl(impl);
    

    以 Resouces.getString 来查看资源的读取流程

    1)调用 getText

     public String getString(@StringRes int id) throws NotFoundException {
            return getText(id).toString();
        }
    

    2)通过 resourcesImpl 调用 AssetsManager 的 getResourceText

        @NonNull public CharSequence getText(@StringRes int id) throws NotFoundException {
            CharSequence res = mResourcesImpl.getAssets().getResourceText(id);
            if (res != null) {
                return res;
            }
            throw new NotFoundException("String resource ID #0x"
                    + Integer.toHexString(id));
        }
    

    3)getResourceText

    @Nullable
     final CharSequence getResourceText(@StringRes int resId) {
         synchronized (this) {
             final TypedValue outValue = mValue;
             if (getResourceValue(resId, 0, outValue, true)) {
                 return outValue.coerceToString();
             }
             return null;
         }
     }
    

    4)getResourceValue

        final boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
                boolean resolveRefs) {
            synchronized (this) {
                final int block = loadResourceValue(resId, (short) densityDpi, outValue, resolveRefs);
                if (block < 0) {
                    return false;
                }
    
                // Convert the changing configurations flags populated by native code.
                outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
                        outValue.changingConfigurations);
    
                if (outValue.type == TypedValue.TYPE_STRING) {
                    outValue.string = mStringBlocks[block].get(outValue.data);
                }
                return true;
            }
        }
    

    5)最后通过 loadResourceValue 这一原生方法读取。

       /** Returns true if the resource was found, filling in mRetStringBlock and
         *  mRetData. */
        private native final int loadResourceValue(int ident, short density, TypedValue outValue,
                boolean resolve);
    

    阿里P7Android高级架构进阶视频免费学习请点击:https://space.bilibili.com/474380680
    参考 https://www.jianshu.com/p/f775cfcae2f6
    https://www.jianshu.com/p/1799e16c80f9

  • 相关阅读:
    Python的四种常见数据结构比较
    LeetCode Notes_#53 Maximum Subarray
    LeetCode Notes_#38 Count and Say
    LeetCode Notes_#6 Zigzag Conversion
    LeetCode Notes_#5 Longest Palindromic Substring
    《美国纽约摄影学院摄影教材》
    《艺术的故事》
    《Don't make me think》
    《Geospatial Data Science Techniques and Applications》
    《程序员的自我修养:链接、装载与库(完整版).pdf》
  • 原文地址:https://www.cnblogs.com/Android-Alvin/p/11958449.html
Copyright © 2020-2023  润新知