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
&n