android動態載入布局
1. android 怎麼動態的載入類
android 如何動態的載入類----app插件技術
轉自:http://blog.csdn.net/mingli198611/article/details/8858076
?
前言:
?
? ? ? 在目前的軟硬體環境下,Native App與Web App在用戶體驗上有著明顯的優勢,但在實際項目中有些會因為業務的頻繁變更而頻繁的升級客戶端,造成較差的用戶體驗,而這也恰恰是Web App的優勢。現如今很多項目要求需要採用類似於微信或Q游這樣的插件化開發模式越來越多,本文就是闡述android的動態載入技術來滿足插件化開發模式的文章。
?
1.基本概念
1.1??在Android中可以動態載入,但無法像java中那樣方便動態載入jar。
Android的虛擬機(DalvikVM)是不認識Java打出jar的byte code,需要通過dx工具來優化轉換成Dalvikbyte code才行。這一點在咱們Android項目打包的apk中可以看出:引入其他Jar的內容都被打包進了classes.dex。即android要載入的java類必須dex格式的代碼文件.
1.2??在Android中可以載入基於NDK的so庫。
NDK的執行效率很高,加密性很好,但同時開發入門難度大,一般用於加解密、數學運算等場合。so的載入很簡單,如果APK發布時已經攜帶了so文件,只需要在載入時調用System.loadLibrary(libName)方法即可。由於軟體的安裝目錄中存放so的目錄是沒有寫許可權的,開發者不能更改該目錄的內容,所以如果要動態載入存放在其他地方的so文件,用System.load(pathName)方法即可。
1.3??在Android中支持動態載入dex文件的兩種方式:
DexClassLoader:這個可以載入jar/apk/dex,也可以從SD卡中載入,也是本文的重點
PathClassLoader:只能載入已經安裝到Android系統中的apk文件。也就是 /data/app 目錄下的 apk 文件。其它位置的文件載入的時候都會出現 ClassNotFoundException.因為 PathClassLoader 會去讀取 /data/dalvik-cache 目錄下的經過 Dalvik 優化過的 dex 文件,這個目錄的 dex 文件是在安裝 apk 包的時候由 Dalvik 生成的。
?
2.注意
2.1 採用不用安裝的插件開發模式,只能夠使用?DexClassLoader進行載入.不過動態載入是有一些限制的,比如插件(子apk)包中的Activity、Service類是不能動態載入的,因為缺少聲明;即使你在Manifest文件中進行了聲明,系統默認也是到安裝apk所在的路徑中去尋找類,所以你會遇到一個ClassNotFound的異常。插件里你可以用主apk中先前放入的layout、strings等資源。但是插件中自帶的界面只能用純代碼進行編寫,插件中是不能載入插件(子apk)中的xml作為layout等資源使用的。所以在開發上一些特效會比較困難些,建議預先植入主apk中。
2.2?大家可以看看DexClassLoader的API文檔,裡面不提倡從SD卡載入,不安全
3.如何製作插件
3.1 把工程導出為jar包
3.2 執行SDK安裝目錄android-sdk-windows\platform-tools下的dx命令,把jar包轉換為dex格式
dx?--dex?--output=dex名 jar包名
4.如何做到啟動未安裝的apk中的activity?
採用反射機制,把主apk中的activity的context傳遞到插件的activity中,然後採用反射進行回調插件activity的方法。不足之出就是,插件中的activity並不是真正的activity,它只是運行在主activity中。比如:點擊返回直接退出當前activity而不是回到主activity。實例如下:
?
這是調用的Activity:
?
[java]?view plain ? ?
package?com.beyondsoft.activity;??
??
import?java.lang.reflect.Constructor;??
import?java.lang.reflect.InvocationTargetException;??
import?java.lang.reflect.Method;??
??
import?dalvik.system.DexClassLoader;??
import?android.app.Activity;??
import?android.content.pm.PackageInfo;??
import?android.os.Bundle;??
import?android.util.Log;??
??
public?class?PlugActivity?extends?Activity?{??
??
????private?Class?mActivityClass;??
????private?Object?mActivityInstance;??
????Class?localClass;??
????private?Object?instance;??
??
????@Override??
????protected?void?onCreate(Bundle?savedInstanceState)?{??
????????super.onCreate(savedInstanceState);??
??
????????Bundle?paramBundle?=?new?Bundle();??
????????paramBundle.putBoolean("KEY_START_FROM_OTHER_ACTIVITY",?true);??
????????paramBundle.putString("str",?"PlugActivity");??
????????String?dexpath?=?"/sdcard/FragmentProject.apk";??
????????String?dexoutputpath?=?"/mnt/sdcard/";??
????????LoadAPK(paramBundle,?dexpath,?dexoutputpath);??
????}??
??
????@Override??
????protected?void?onStart()?{??
????????super.onStart();??
????????Method?start;??
????????try?{??
????????????start?=?localClass.getMethod("onStart");??
????????????????start.invoke(instance);??
????????}?catch?(Exception?e)?{??
????????????//?TODO?Auto-generated?catch?block??
????????????e.printStackTrace();??
????????}??
????}??
??
????@Override??
????protected?void?onResume()?{??
????????//?TODO?Auto-generated?method?stub??
????????super.onResume();??
????????Method?resume;??
????????try?{??
????????????resume?=?localClass.getMethod("onResume");??
????????????resume.invoke(instance);??
????????}?catch?(Exception?e)?{??
????????????//?TODO?Auto-generated?catch?block??
????????????e.printStackTrace();??
????????}??
????}??
??
????@Override??
????protected?void?onPause()?{??
????????super.onPause();??
????????Method?pause;??
????????try?{??
????????????pause?=?localClass.getMethod("onPause");??
????????????pause.invoke(instance);??
????????}?catch?(Exception?e)?{??
????????????e.printStackTrace();??
????????}??
????}??
??
????@Override??
????protected?void?onStop()?{??
????????super.onStop();??
????????try?{??
????????????Method?stop?=?localClass.getMethod("onStop");??
????????????stop.invoke(instance);??
????????}?catch?(Exception?e)?{??
????????????e.printStackTrace();??
????????}??
????}??
??
????@Override??
????protected?void?onDestroy()?{??
????????//?TODO?Auto-generated?method?stub??
????????super.onDestroy();??
????????try?{??
????????????Method?des?=?localClass.getMethod("onDestroy");??
????????????des.invoke(instance);??
????????}?catch?(Exception?e)?{??
????????????//?TODO?Auto-generated?catch?block??
????????????e.printStackTrace();??
????????}??
????}??
2. 很簡單的送分題又來了,高手還不進來android如何動態include布局文件,答得好的追加100分
inflate函數可以見xml布局文件刷成view,然後java中獲得activity的view的父節點,然後通過addview就可以動態加入你要的view了
3. 如何在Android開發中動態載入的list列表數據
動態獲取的話,一般都是結合服務端通知客戶端數據更新,然後組成成一個list,通知你的界面進行重繪更新。
4. Android Native庫的載入及動態鏈接
我們從一個簡單的NDK Demo開始分析。
下面從 System.loadLibrary() 開始分析。
下面看 loadLibrary0()
參數 loader 為Android的應用類載入器,它是 PathClassLoader 類型的對象,繼承自 BaseDexClassLoader 對象,下面看 BaseDexClassLoader 的 findLibrary() 方法。
下面看 DexPathList 的 findLibrary() 方法
回到 loadLibrary0() ,有了動態庫的全路徑名就可以裝載庫了,下面看 doLoad() 。
nativeLoad() 最終調用 LoadNativeLibrary() ,下面直接分析 LoadNativeLibrary() 。
對於JNI注冊,這里暫不討論,下面看 OpenNativeLibrary() 的實現。
下面看 android_dlopen_ext() 的實現
接下來就Android鏈接器linker的工作了。
下面從 do_dlopen() 開始分析。
find_library() 當參數translated_name不為空時,直接調用 find_libraries() ,這是裝載鏈接的關鍵函數,下面看它的實現。
find_libraries() 中動態庫的裝載可以分為兩部分
下面從 find_library_internal() 開始分析。
下面分析 load_library()
下面看另一個 load_library() 的實現
下面分析ELF文件頭以及段信息的讀取過程,也就是LoadTask的 read() ,它直接調用ElfReader的 Read() 方法。
動態庫的裝載在LoadTask的 load() 中實現。
下面看ElfReader的 Load() 方法
動態庫的裝載已經完成,下面看鏈接過程。
下面看 prelink_image()
鏈接主要完成符號重定位工作,下面從 link_image() 開始分析
下面以函數引用重定位為例分析 relocate() 方法