zoukankan      html  css  js  c++  java
  • android动态加载资源

    android动态加载资源的一个典型的例子就是app的换肤功能。在应用中不可能将所有的皮肤内置到app中,特别是在一些节日里都会有新的皮肤上线,而且为了更新皮肤而更新整个应用也是不可能的。那么以apk插件的形式提供皮肤包,应用动态的加载的这些皮肤包提供的图片才是一种可取的方式。那么问题来了,要怎么动态加载这么皮肤包呢,需要处理两个方面:

    1. 获取插件包的resource
    2. 获取插件包的resource id

    下面就从这两个方面说说怎么处理皮肤包。


    1.获取插件包中的resource

    一般我们获取resource实例的方法是直接使用context.getResource()获取的,现在要获取插件中的resource实例该方法就不适用了,我们来看看构造方法

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

    我们需要一个AssetManager的实例,如果直接实例话一个AssetManager类的话是不行的,它没有经过安装过程的处理,不能引用到一个应用中的资源。还好在AssetManager中有一个方法可以帮助我们做到这一点

     /**
         * Add an additional set of assets to the asset manager.  This can be
         * either a directory or ZIP file.  Not for use by applications.  Returns
         * the cookie of the added asset, or 0 on failure.
         * {@hide}
         */
        public final int addAssetPath(String path) {
            return  addAssetPathInternal(path, false);
        }

    这是一个hide方法,这就需要调用反射的方式来调用这个方法。

     AssetManager manager = AssetManager.class.newInstance();
     Method addAssetMethod = manager.getClass().getMethod("addAssetPath", String.class);
     addAssetMethod.invoke(manager, apkPath);

    2.获取插件包中的resource id

    获取resource id就需要获取插件中的R类,如何获取插件中的R类呢?可以使用DexClassLoader这个类加载器,使用这个类就可以直接加载插件中的R类,并且都是static变量,可以非常方便的获取到resource id

     DexClassLoader loader = new DexClassLoader(apkPath, codePath, null, this.getClass().getClassLoader());

    3.实例

    1.将插件apk放置到sdcard中

    首先将一个apk作为插件放置到sdcard目录中作为插件供应用调用,apk中只放置了一张图片在drawable目录中。

    2.应用中获取资源替换图片

    package com.motiongear.simplecc.dynamicapk;
    
    import android.Manifest;
    import android.content.res.AssetManager;
    import android.content.res.Resources;
    import android.os.Bundle;
    import android.os.Environment;
    import android.support.v4.app.ActivityCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ImageView;
    
    import java.io.File;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    import dalvik.system.DexClassLoader;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        private static final String APK_NAME = "app-debug.apk";
        private ImageView mImageView;
        private Button mButton;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mImageView = (ImageView) this.findViewById(R.id.imageview);
            mButton = (Button) this.findViewById(R.id.btn);
            mButton.setOnClickListener(this);
            //获取动态权利,简单处理下
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0x001);
        }
    
        @Override
        public void onClick(View v) {
    
            String apkPath = Environment.getExternalStorageDirectory() + File.separator + APK_NAME;
            String codePath = getCodeCacheDir().getAbsolutePath();
            DexClassLoader loader = new DexClassLoader(apkPath, codePath, null, this.getClass().getClassLoader());
            try {
                //1. 获取resource id
    
                //加载插件中的R.drawable类
                Class clz = loader.loadClass("com.motiongear.simplecc.pluginsapk.R$drawable");
                //获取图片id
                Field field = clz.getDeclaredField("dog");
                int resId = (int) field.get(clz);
    
                //2. 获取resource
    
                //实例化AssetManager
                AssetManager manager = AssetManager.class.newInstance();
                Method addAssetMethod = manager.getClass().getMethod("addAssetPath", String.class);
                addAssetMethod.invoke(manager, apkPath);
                Resources superResource = getResources();
                //获取插件的resource
                Resources pluginRes = new Resources(manager, superResource.getDisplayMetrics(), superResource.getConfiguration());
    
                //替换图片
                mImageView.setImageDrawable(pluginRes.getDrawable(resId));
    
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    }
    

    显示结果如下:
    这里写图片描述

  • 相关阅读:
    通用应用程序设计
    咫尺与天涯
    SQL SERVER 自定义函数 split
    asp.net 页面实践执行顺序
    asp.net UpdatePanel 不能局部刷新问题汇总
    DataGrid GridView 单页javascript 表头排序
    存储过程分页方案
    数据库名、数据表名、字段名、主键、标识列相关查询
    c# web 缓存管理
    js笔记---拖动元素
  • 原文地址:https://www.cnblogs.com/summerpxy/p/13648314.html
Copyright © 2011-2022 走看看