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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM