欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

動態(tài)加載Android,動態(tài)加載和動態(tài)鏈接的區(qū)別

android 怎么動態(tài)的加載類

android 如何動態(tài)的加載類----app插件技術(shù)

創(chuàng)新互聯(lián)專注于北侖網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗。 熱誠為您提供北侖營銷型網(wǎng)站建設(shè),北侖網(wǎng)站制作、北侖網(wǎng)頁設(shè)計、北侖網(wǎng)站官網(wǎng)定制、微信平臺小程序開發(fā)服務(wù),打造北侖網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供北侖網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。

轉(zhuǎn)自:

?

前言:

?

? ? ? 在目前的軟硬件環(huán)境下,Native App與Web App在用戶體驗上有著明顯的優(yōu)勢,但在實際項目中有些會因為業(yè)務(wù)的頻繁變更而頻繁的升級客戶端,造成較差的用戶體驗,而這也恰恰是Web App的優(yōu)勢。現(xiàn)如今很多項目要求需要采用類似于微信或Q游這樣的插件化開發(fā)模式越來越多,本文就是闡述android的動態(tài)加載技術(shù)來滿足插件化開發(fā)模式的文章。

?

1.基本概念

1.1??在Android中可以動態(tài)加載,但無法像Java中那樣方便動態(tài)加載jar。

Android的虛擬機(DalvikVM)是不認識Java打出jar的byte code,需要通過dx工具來優(yōu)化轉(zhuǎn)換成Dalvikbyte code才行。這一點在咱們Android項目打包的apk中可以看出:引入其他Jar的內(nèi)容都被打包進了classes.dex。即android要加載的java類必須dex格式的代碼文件.

1.2??在Android中可以加載基于NDK的so庫。

NDK的執(zhí)行效率很高,加密性很好,但同時開發(fā)入門難度大,一般用于加解密、數(shù)學(xué)運算等場合。so的加載很簡單,如果APK發(fā)布時已經(jīng)攜帶了so文件,只需要在加載時調(diào)用System.loadLibrary(libName)方法即可。由于軟件的安裝目錄中存放so的目錄是沒有寫權(quán)限的,開發(fā)者不能更改該目錄的內(nèi)容,所以如果要動態(tài)加載存放在其他地方的so文件,用System.load(pathName)方法即可。

1.3??在Android中支持動態(tài)加載dex文件的兩種方式:

DexClassLoader:這個可以加載jar/apk/dex,也可以從SD卡中加載,也是本文的重點

PathClassLoader:只能加載已經(jīng)安裝到Android系統(tǒng)中的apk文件。也就是 /data/app 目錄下的 apk 文件。其它位置的文件加載的時候都會出現(xiàn) ClassNotFoundException.因為 PathClassLoader 會去讀取 /data/dalvik-cache 目錄下的經(jīng)過 Dalvik 優(yōu)化過的 dex 文件,這個目錄的 dex 文件是在安裝 apk 包的時候由 Dalvik 生成的。

?

2.注意

2.1 采用不用安裝的插件開發(fā)模式,只能夠使用?DexClassLoader進行加載.不過動態(tài)加載是有一些限制的,比如插件(子apk)包中的Activity、Service類是不能動態(tài)加載的,因為缺少聲明;即使你在Manifest文件中進行了聲明,系統(tǒng)默認也是到安裝apk所在的路徑中去尋找類,所以你會遇到一個ClassNotFound的異常。插件里你可以用主apk中先前放入的layout、strings等資源。但是插件中自帶的界面只能用純代碼進行編寫,插件中是不能加載插件(子apk)中的xml作為layout等資源使用的。所以在開發(fā)上一些特效會比較困難些,建議預(yù)先植入主apk中。

2.2?大家可以看看DexClassLoader的API文檔,里面不提倡從SD卡加載,不安全

3.如何制作插件

3.1 把工程導(dǎo)出為jar包

3.2 執(zhí)行SDK安裝目錄android-sdk-windows\platform-tools下的dx命令,把jar包轉(zhuǎn)換為dex格式

dx?--dex?--output=dex名 jar包名

4.如何做到啟動未安裝的apk中的activity?

采用反射機制,把主apk中的activity的context傳遞到插件的activity中,然后采用反射進行回調(diào)插件activity的方法。不足之出就是,插件中的activity并不是真正的activity,它只是運行在主activity中。比如:點擊返回直接退出當前activity而不是回到主activity。實例如下:

?

這是調(diào)用的Activity:

?

[java]?view plaincopy ? ?

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();??

????????}??

????}??

Android怎樣動態(tài)加載代碼技術(shù)

在開發(fā)Android App的過程當中,可能希望實現(xiàn)插件式軟件架構(gòu),將一部分代碼以另外一個APK的形式單獨發(fā)布,而在主程序中加載并執(zhí)行這個APK中的代碼。

實現(xiàn)這個任務(wù)的一般方法是:

復(fù)制代碼

// 加載類cls

Context pluginContext = mainContext.createPackageContext(PLUGIN_PKG, Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);

ClassLoader loader = pluginContext.getClassLoader();

Class? cls = loader.loadClass(CLASS_NAME);

// 通過反射技術(shù),調(diào)用cls中的方法,下面是一個示例,實際代碼因情況而定

Object obj = cls.newInstance();

Method method = cls.getDeclaredMethod("someMethod");

method.invoke(obj);

復(fù)制代碼

但是,這個方法在Android 4.1及之后的系統(tǒng)中存在一些問題:對于收費應(yīng)用,Google Play會將其安裝在一個加密目錄之下(具體就是/data/app-asec),而不是一個普通目錄之下(具體就是/data/app);安裝在加密目錄中的應(yīng)用,我們是無法使用上述方法來加載并執(zhí)行代碼的;而實際情況是,我們經(jīng)常就是依靠插件應(yīng)用來收費的。

解決上述問題的一個方案是:將插件的二進制代碼拷貝到SD卡中,主程序從SD卡中加載并執(zhí)行其代碼。

實現(xiàn)這個任務(wù)的具體方法是:

復(fù)制代碼

Class? cls = null;

try {

// 嘗試第一種方法

cls = loadClass1(mainContext, pkg, entryCls);

} catch (Exception e) {

// 嘗試第二種方法

cls = loadClass2(mainContext, pkg, entryCls);

}

// 示例代碼

Object obj = cls.newInstance();

Method method = cls.getDeclaredMethod("someMethod");

method.invoke(obj);

// 第一種加載方法

private Class? loadClass1(Context mainContext, String pkg, String entryCls) throws Exception {

Context pluginContext = mainContext.createPackageContext(pkg, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);

ClassLoader loader = pluginContext.getClassLoader();

return loader.loadClass(entryCls);

}

// 第二種加載方法

private Class? loadClass2(Context mainContext, String pkg, String entryCls) throws Exception {

Context pluginContext = mainContext.createPackageContext(pkg, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);

String path = generatePluginDexPath(mainContext, pkg);

ensureFileExist(pluginContext, pkg, path);

// cacheDir必須是主程序的私有目錄,否則DexClassLoader可能會拒絕加載

String cacheDir = mainContext.getApplicationInfo().dataDir;

ClassLoader parentLoader = pluginContext.getClassLoader();

DexClassLoader loader = new DexClassLoader(path, cacheDir, null, parentLoader);

return loader.loadClass(entryCls);

}

// 獲取程序版本號

private int getVersionCode(Context context, String pkg) {

PackageInfo info = null;

int versionCode = 0;

try {

info = context.getPackageManager().getPackageInfo(pkg, PackageManager.GET_ACTIVITIES);

versionCode = info.versionCode;

} catch (Exception e) {}

return versionCode;

}

// 獲取插件二進制代碼的存儲位置,注意做好版本控制;路徑必須是以.dex結(jié)束,否則加載會出問題

private String generatePluginDexPath(Context context, String pkg) {

int version = getVersionCode(context, pkg);

String path = getMyAppPath() + ".classes/" + pkg + version + ".dex";

return path;

}

// 主程序在SD卡上的數(shù)據(jù)目錄

private String getMyAppPath() {

return Environment.getExternalStorageDirectory().getAbsolutePath() + "/MyApp/";

}

// 拷貝插件的二進制代碼到SD卡

private void ensureFileExist(Context pluginContext, String pkg, String path) throws Exception {

File file = new File(path);

if(file.exists()) return;

file.getParentFile().mkdirs();

Resources res = pluginContext.getResources();

int id = res.getIdentifier("classes", "raw", pkg);

InputStream in = res.openRawResource(id);

FileOutputStream out = new FileOutputStream(file);

try {

byte[] buffer = new byte[1024 * 1024];

int n = 0;

while((n = in.read(buffer)) 0) {

out.write(buffer, 0, n);

} out.flush();

} catch (IOException e) {

in.close();

out.close();

}

}

復(fù)制代碼

插件工程這邊也需要做相應(yīng)的修改:

1.編譯插件工程;

2.將bin目錄之下的classes.dex拷貝到/res/raw目錄之下;

3.重新編譯插件工程;

4.發(fā)布插件APK。

Android動態(tài)加載資源

Fruit[] data = {"apple", "banana", "orange"};

int[] ?bitmaps= {R.drawable.apple, ?R.drawable.banana, R.drawable.orange};

for ( int i= 0; i data.size; i ++ ){

Fruit temp= new Fruit(fruit, bitmaps[i]);

fruitList.add(temp);

}

Android動態(tài)加載dex技術(shù)初步了解

此處需要注意DexClassLoader的四個參數(shù):

參數(shù)1 dexPath:待加載的dex文件路徑,如果是外存路徑,一定要加上讀外存文件的權(quán)限(uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/ ),否則會報與上面一樣的錯誤,這點參考文章2中說這個權(quán)限可有可無是錯誤的。(更正下:Android4.4 KitKat及以后的版本需要此權(quán)限,之前的版本不需要權(quán)限)

android的動態(tài)加載和靜態(tài)加載的區(qū)別

兩者區(qū)別:

一,靜態(tài)庫的使用需要:

1

包含一個對應(yīng)的頭文件告知編譯器lib文件里面的具體內(nèi)容

2

設(shè)置lib文件允許編譯器去查找已經(jīng)編譯好的二進制代碼

二,動態(tài)庫的使用:

程序運行時需要加載動態(tài)庫,對動態(tài)庫有依賴性,需要手動加入動態(tài)庫

三,依賴性:

靜態(tài)鏈接表示靜態(tài)性,在編譯鏈接之后,

lib庫中需要的資源已經(jīng)在可執(zhí)行程序中了,

也就是靜態(tài)存在,沒有依賴性了

動態(tài),就是實時性,在運行的時候載入需要的資源,那么必須在運行的時候提供

需要的

動態(tài)庫,有依賴性,

運行時候沒有找到庫就不能運行了

四,區(qū)別:

簡單講,靜態(tài)庫就是直接將需要的代碼連接進可執(zhí)行程序;動態(tài)庫就是在需要調(diào)用其中的函數(shù)時,根據(jù)函數(shù)映射表找到該函數(shù)然后調(diào)入堆棧執(zhí)行。

做成靜態(tài)庫可執(zhí)行文件本身比較大,但不必附帶動態(tài)庫

做成動態(tài)庫可執(zhí)行文件本身比較小,但需要附帶動態(tài)庫

五:

首先糾正所謂“靜態(tài)連接就是把需要的庫函數(shù)放進你的exe之中”的說法。在真實世界中,有三個概念:Use

static

libary,

static

linked

DLL,

dynamic

linked

DLL.

多數(shù)人混淆了static

libary

static

linked

DLL的概念,當然他們有似是而非的“相似之處”,比如都用到.lib,下面具體說明。

使用靜態(tài)庫(Use

static

libary)是把.lib和其他.obj一起build在目標文件中,目標文件可以是.exe,也可以是.dll或.oxc等。一般情況下,可以根本就沒有“對應(yīng)的”.dll

文件,如C

Run

Time(CRT)庫。一個例子就是,寫一個main(){},build出來并不是只有幾個字節(jié),當然有人會說那還有exe文件頭呢?是,即使加上文件頭的尺寸,build出的執(zhí)行文件仍然“莫名的大”。實際上那多出來的部分就是CRT靜態(tài)庫。姑且可以把靜態(tài)庫.lib理解成外部程序的obj文件比較合理,它包含了函數(shù)的實現(xiàn)。

android中怎么動態(tài)的加載一個布局

由于前段時間項目需要,需要在一個頁面上加載根據(jù)不同的按鈕加載不同的布局頁面,當時想到用 tabhot 。不過美工提供的界面圖完全用不上tabhot ,所以想到了動態(tài)加載的方法來解決這一需求。在這里我整理了一下,寫了一個 DEMO 希望大家以后少走點彎路。

首先,我們先把界面的框架圖畫出來,示意圖如下:

中間白色部門是一個線性布局文件,我喜歡在畫圖的時候用不同的顏色將一塊布局標示出來,方便查看。布局文件代碼如下:

分享標題:動態(tài)加載Android,動態(tài)加載和動態(tài)鏈接的區(qū)別
瀏覽路徑:http://chinadenli.net/article2/dsdsjic.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作搜索引擎優(yōu)化網(wǎng)站改版網(wǎng)站營銷建站公司移動網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站