zoukankan      html  css  js  c++  java
  • Android之资源管理利器Resources和AssetManager

    前言  :

           Android工程在运行的时候往往需要引用资源。使用 Resources 来获取 res 目录下的各种与设备相关的资源。而使用 AssetManager 来获取 assets 目录下的资源。

           资源包括系统资源、工程资源、第三方资源、插件资源等,分为两类:

    •        res目录下存放的可编译的资源文件,编译时,系统会自动在R.java中生成资源文件的ID,所以访问这种资源比较简单,通过在程序中调用R.id.filenam  e即可。    
    •        assets目录下存放的原始资源文件,因为系统在编译的时候不会编译assets下的资源文件,所以我们不能通过R.id.filename的方式访问它们。那我么能不能通过该资源的绝对路径去访问它们呢?因为apk安装之后会放在/data/app/**.apk目录下,assets被绑定在apk里,以apk形式存在,并不会解压到/data/data/YourApp目录下去,所以我们无法直接获取到assets的绝对路径,因为它们根本就没有独立存在

     res/raw和assets的相同点:  
        1.两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制。

    res/raw和assets的不同点:   
       1.res/raw中的文件会被映射到R.java文件中,访问的时候直接使用资源ID即R.id.filename;                assets文件夹下的文件不会被映射到R.java中,访问的时候需要AssetManager类。    
       2.res/raw不可以有目录结构,而assets则可以有目录结构(在其目录下可以再建文件夹)   
       3.读取res/raw下的文件资源,通过以下方式获取输入流:

          InputStream is=getResources().openRawResource(R.id.filename);

          读取assets下的文件资源,通过以下方式获取输入流:

          InputStream is =getResources()..getAssets().open("filename");  

           不管是什么样的资源,最终都能通过一个入口来获取,而这个入口就是Resources对象。Resources对象描述了android资源文件,例如android工程下的res、asset目录等除了.class文件的资源,我们可以认为,所有涉及到获取资源的地方,都可以使用Resources来获取。事实上我们在代码中读取asset目录下的资源时常常直接使用Assetmanager来直接获取对象的流数据,而AssetManager也是属于Resources对象的一个属性,都同时指向相同的对象。

    Resources解析:

    1.Resources对象的几个重要成员属性:

    static Resources mSystem = null; // mSystem为一个静态的对象,代表了系统默认的资源管理。
    final Object mAccessLock = new Object();
    final Configuration mTmpConfig = new Configuration();
    TypedValue mTmpValue = new TypedValue();
    final AssetManager mAssets; // mAssets指向了系统默认的实例,mAsset的创建初始化过程是在C++层做的。
    private final Configuration mConfiguration = new Configuration();
    final DisplayMetrics mMetrics = new DisplayMetrics();
    private NativePluralRules mPluralRule;
     1 private Resources() {
     2         mAssets = AssetManager.getSystem();
     3         // NOTE: Intentionally leaving this uninitialized (all values set
     4         // to zero), so that anyone who tries to do something that requires
     5         // metrics will get a very wrong value.
     6         mConfiguration.setToDefaults();
     7         mMetrics.setToDefaults();
     8         updateConfiguration(null, null);
     9         mAssets.ensureStringBlocks();
    10     }

           我们在开发自己的应用时,是把自己需要的资源都放置到工程目录下的res文件夹下和asset文件夹下。当编译工程的时候,资源和源文件都将会打包到apk里面。运行应用的时候,Resources中AssetManager的路径默认指向了该apk的文件,如果是普通应用,一般apk文件被放置在data/app目录下,系统应用的apk包放在system/app下。

           所以在启动应用的时候,Resources通过Assetmanager,AssetManager再根据设定的路径查找apk中的资源,就可以正确的找到自己的资源了。

            既然AssetManager获取资源是根据指向的路径来完成,理论上我们改变AssetManager读取的路径,就可以指定加载自己的资源,事实上也是这样设计的。所以如果我们让AssetManager指向自己设定的Apk资源路径,就可以完成提取apk资源的目的了。   一些动态主题包的实现原理主要是通过AssetsManager.addAssetPath(String path) 这一接口来创建对应主题包的 Resources 对象来实现的。

     

    Demo:

    新建一个用于管理资源的类ResourcesManager,其中包含的重要属性与方法:

     1     AssetManager mAssetManager = null;
     2     Resources mResources = null;
     3     LayoutInflater mLayoutInflater = null;
     4     Theme mTheme = null;
     5     ClassLoader mClassLoader = null;
     6     //ResApk.apk  资源文件
     7     String packageName = "com.example.testapk";
     8     String libPath = Environment.getExternalStorageDirectory().toString()
     9             + File.separator + "ResApk.apk";
    10  
    11     protected void initAssetManager() {
    12         try {
    13             AssetManager assetManager = AssetManager.class.newInstance();
    14             Method addAssetPath = assetManager.getClass().getMethod(
    15                     "addAssetPath", String.class);
    16             addAssetPath.invoke(assetManager, libPath);
    17             mAssetManager = assetManager;
    18         } catch (Exception e) {
    19             e.printStackTrace();
    20         }
    21         Resources superRes = super.getResources();
    22         mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(),
    23                 superRes.getConfiguration());
    24     }

    mResources就指向了ResApk.apk里面的资源,通过名字就可以取得对应资源。

     1 public int getDrawableId(String imgName) {
     2         return mResources.getIdentifier(imgName, "drawable", apkPackageName);
     3     }
     4  
     5     /**
     6      * 获取图片资源
     7      * 
     8      * @param imgName
     9      * @return drawable
    10      */
    11     public Drawable getResApkDrawable(String imgName) {
    12         return mResources.getDrawable(getDrawableId(imgName));
    13     }

    特别需要注意的是,由于每个应用的上下文对象都是不一样的,要始终记住,如果使用的不是自己资源文件,要慎用与上下文有关的功能方法。

         原文参考博客链接:https://blog.csdn.net/MeteorLuoyidong/article/details/49530839

                                         https://www.cnblogs.com/jpfss/p/9876370.html

  • 相关阅读:
    从点子到产品
    基础设计模式
    SpringBoot单元测试
    结构化思维
    考试脑科学读书笔记
    爆发式成长的思维
    人人都是产品经理笔记
    文本处理工具awk
    CSP-S2019【绍兴一中集训】
    寒假集训【1.28】
  • 原文地址:https://www.cnblogs.com/jiani/p/11654487.html
Copyright © 2011-2022 走看看