资源加载源码分析
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;
}
}
}