android動態載入布局-ag真人国际官网
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() 方法