插件式换肤框架搭建 - 资源加载源码分析

资源加载源码分析

1.首先我们来看一下ImageView是如何加载资源的:

     public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        ......

        final TypedArray a = context.obtainStyledAttributes(
                attrs, R.styleable.ImageView, defStyleAttr, defStyleRes);

        final Drawable d = a.getDrawable(R.styleable.ImageView_src);
        if (d != null) {
            setImageDrawable(d);
        }

......}

    @Nullable
    public Drawable getDrawable(@StyleableRes int index) {
        return getDrawableForDensity(index, 0);
    }

    @Nullable
    public Drawable getDrawableForDensity(@StyleableRes int index, int density) {
        if (mRecycled) {
            throw new RuntimeException("Cannot make calls to a recycled instance!");
        }

        final TypedValue value = mValue;
        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);
            }

            if (density > 0) {
                // If the density is overridden, the value in the TypedArray will not reflect this.
                // Do a separate lookup of the resourceId with the density override.
                mResources.getValueForDensity(value.resourceId, density, value, true);
            }
            //加载资源其实是通过mResources去获取的
            return mResources.loadDrawable(value, value.resourceId, density, mTheme);
        }
        return null;
    }

2.Resource创建过程分析:

@Deprecated
    public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
        this(null);
        mResourcesImpl = new ResourcesImpl(assets, metrics, config, new DisplayAdjustments());
    }

AssetManager创建源码:

private static void ensureSystemAssets() {
        synchronized (sSync) {
            if (sSystem == null) {
                AssetManager system = new AssetManager(true);
                system.makeStringBlocks(null);
                sSystem = system;
            }
        }

aseet对象核心方法:

 
public final int addAssetPath(String path) {
    return  addAssetPathInternal(path, false);
}

private final int addAssetPathInternal(String path, boolean appAsLib) {
        synchronized (this) {
            int res = addAssetPathNative(path, appAsLib);
            makeStringBlocks(mStringBlocks);
            return res;
        }
}

private native final int addAssetPathNative(String path, boolean appAsLib);

 path指的是资源apk路径。

换肤实战

public class MainActivity extends AppCompatActivity {

    public static final int REQUEST_PERMISSION_CODE = 0x01;

    private boolean isGetPermission = false;

    private static String[] PERMISSIONS_STORAGE = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
            if (ActivityCompat.checkSelfPermission(this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this,
                        PERMISSIONS_STORAGE, REQUEST_PERMISSION_CODE);
            }else{
                isGetPermission = true;
            }
        }
        Button btnC = findViewById(R.id.btn_change);
        final ImageView iv_ = findViewById(R.id.iv_);
        if (isGetPermission){
            btnC.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    try {
                        Resources superRes = getResources();
                        // 创建AssetManager,但是不能直接new所以只能通过反射
                        AssetManager assetManager = AssetManager.class.newInstance();
                        // 反射获取addAssetPath方法
                        Method addAssetPathMethod = AssetManager.class.getDeclaredMethod("addAssetPath",String.class);
                        // 皮肤包的路径:  本地sdcard/plugin.skin
                        String skinPath = Environment.getExternalStorageDirectory().getAbsolutePath()
                                + File.separator+"plugin.skin";
                        // 反射调用addAssetPath方法
                        addAssetPathMethod.invoke(assetManager, skinPath);
                        // 创建皮肤的Resources对象
                        Resources skinResources = new Resources(assetManager,superRes.getDisplayMetrics(),superRes.getConfiguration());
                        // 通过资源名称,类型,包名获取Id
                        int bgId = skinResources.getIdentifier("lzy","drawable","com.example.haunfu01");
                        Drawable bgDrawable = skinResources.getDrawable(bgId);
                        // 设置背景
                        iv_.setImageDrawable(bgDrawable);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }



    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_PERMISSION_CODE
                &&grantResults[0]==0&&grantResults[1]==0) {
            isGetPermission = true;
        }
    }


}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AD钙奶-lalala

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值