android应用换肤之加载插件资源的Demo

首先了解一下Google加载资源源码

效果图

android应用换肤之加载插件资源的Demo_第1张图片
效果图.gif

ImageView中加载src源码

final Drawable d = a.getDrawable(R.styleable.ImageView_src);

getDrawable源码

 if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
            if (value.type == TypedValue.TYPE_ATTRIBUTE) {
                throw new UnsupportedOperationException(
                        "Failed to resolve attribute at index " + index + ": " + value);
            }
            return mResources.loadDrawable(value, value.resourceId, mTheme);
        }

可以看到最终调用Resource中的loadDrawable方法

我们都知道我们可以通过代码getResource去加载资源,那么getResource是怎么加载的呢?

获取getResources源码,目的了解获取resource怎么去实例化的,一步一步走下去

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

发现调用的Content中的抽象方法getResource方法

查看Context的实现类ContextImpl中的getResource的方法

  @Override
    public Resources getResources() {
        return mResources;
    }

查看mResource怎么被赋值的
mResources = resources;
Resources resources = packageInfo.getResources(mainThread);

getResource源码

 public Resources getResources(ActivityThread mainThread) {
        if (mResources == null) {
            mResources = mainThread.getTopLevelResources(mResDir, mSplitResDirs, mOverlayDirs,
                    mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, this);
        }
        return mResources;
    }

查看ActivityThread中getTopLevelResources源码

 Resources getTopLevelResources(String resDir, String[] splitResDirs, String[] overlayDirs,
            String[] libDirs, int displayId, Configuration overrideConfiguration,
            LoadedApk pkgInfo) {
        return mResourcesManager.getTopLevelResources(resDir, splitResDirs, overlayDirs, libDirs,
                displayId, overrideConfiguration, pkgInfo.getCompatibilityInfo(), null);
    }

查看ResourceManager中getTopLevelResources源码

//实际最终是new出来的一个对象
 r = new Resources(assets, dm, config, compatInfo, token);
 AssetManager assets = new AssetManager();
  if (resDir != null) {
            if (assets.addAssetPath(resDir) == 0) {
                return null;
            }
        }

资源加载的总结:所有的资源加载通过Resource -> 构建对象是直接new的对象 -> AssetManager 其实是Resource的核心实例 -> 最终是通过AssetManager获取,然后通过addAssetPath将路径加载进去

案例:首先我们准备资源的apk,修改apk名字为meinv.skin:保存到本地手机中,我这里是直接拖到虚拟机/Download目录下的
代码很简单,直接粘贴了,注意源码中有{@hide}代表不能直接new必须通过反射获取实例

public void onClick(View view){
     Resources superResource = getResources();

     try {
         AssetManager assets = AssetManager.class.newInstance();//{@hide}

         Method method = AssetManager.class.getDeclaredMethod("addAssetPath", String.class);
         method.invoke(assets, Environment.getExternalStorageDirectory().getAbsolutePath()
                 + File.separator + "Download"+File.separator+"meinv.skin");

         Resources resources = new Resources
                 (assets, superResource.getDisplayMetrics(), superResource.getConfiguration());
         //获得资源的id
         int resourceId = resources.getIdentifier("image_src", "drawable", "com.hbwj.kanyuanma");
         Drawable drawable = resources.getDrawable(resourceId);
         skin_imageView.setImageDrawable(drawable);
     } catch (Exception e) {
         e.printStackTrace();
     }
 }

你可能感兴趣的:(android应用换肤之加载插件资源的Demo)