日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內(nèi)最全I(xiàn)T社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > 互聯(lián)網(wǎng) > Android插件化開發(fā)---運(yùn)行未安裝apk中的Service

Android插件化開發(fā)---運(yùn)行未安裝apk中的Service

來源:程序員人生   發(fā)布時(shí)間:2014-11-15 00:28:15 閱讀次數(shù):2838次
 如果你還不知道甚么叫插件化開發(fā),那末你應(yīng)當(dāng)先讀1讀之前寫的這篇博客:Android插件化開發(fā),初入殿堂

        上1篇博客主要從整體角度分析了1下Android插件化開發(fā)的幾個(gè)難點(diǎn)與動態(tài)加載沒有被安裝的apk中的Activity和資源的方法。其實(shí)1般的插件開發(fā)主要也就是加載個(gè)Activity,讀取1些資源圖片之類的。但是總有遇到特殊情況的時(shí)候,比如加載Service。

        要動態(tài)加載Service,有兩種思路:1是通過NDK的情勢,將Service通過C++運(yùn)行起來(這類方法我沒有嘗試,只聽群里的朋友說實(shí)現(xiàn)過);另外一種就是我使用的,具體思路和上1篇中提到加載Activity的方法1樣,使用托管所的情勢,由于上1篇博客沒有講清楚,這里就詳細(xì)講1下通過托管所實(shí)現(xiàn)加載插件中Service的方法。

        以下幾點(diǎn)是每個(gè)Android開發(fā)組肯定都知到的: 1個(gè)apk如果沒有被安裝的話是沒有辦法直接運(yùn)行的。1個(gè)JAVA類的class文件是可以通過classload類加載器讀取的。1個(gè)apk實(shí)際上就是1個(gè)緊縮包,其中包括了1個(gè).dex文件就是我們的代碼文件。那末,接下來基本思路我們就能夠明確了:apk沒辦法直接運(yùn)行,apk中有代碼文件,代碼文件可以被classload讀取。

        在Android中有兩種classload,分別是DexClassLoader、PathClassLoader。后者只能加載/data/app目錄下的apk也就是apk必須要安裝才能被加載,這不是我們想要的,所以我們使用前者:DexClassLoader。

public class CJClassLoader extends DexClassLoader { //創(chuàng)建1個(gè)插件加載器集合,對固定的dex使用固定的加載器可以避免多個(gè)加載器同時(shí)加載1個(gè)dex釀成的毛病。 private static final HashMap<String, CJClassLoader> pluginLoader = new HashMap<String, CJClassLoader>(); protected CJClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) { super(dexPath, optimizedDirectory, libraryPath, parent); } /** * 返回dexPath對應(yīng)的加載器 */ public static CJClassLoader getClassLoader(String dexPath, Context cxt, ClassLoader parent) { CJClassLoader cjLoader = pluginLoader.get(dexPath); if (cjLoader == null) { // 獲得到app的啟動路徑 final String dexOutputPath = cxt .getDir("dex", Context.MODE_PRIVATE).getAbsolutePath(); cjLoader = new CJClassLoader(dexPath, dexOutputPath, null, parent); pluginLoader.put(dexPath, cjLoader); } return cjLoader; } }

以上只是1個(gè)開始,接著我們需要斟酌1個(gè)問題,1個(gè)Service是有oncreate->onstart->ondestroy生命周期和1些回調(diào)方法的,這些回調(diào)方法在我們正常使用的時(shí)候是由父類們(包括has...a...關(guān)系)或說是SDK管理的,那末當(dāng)我們通過類加載器加載的時(shí)候,它是沒有能夠管理的父類的,也就是說我們需要自己摹擬SDK去管理插件Service的回調(diào)函數(shù)。那末這個(gè)去管理插件Service的類,就是之條件到的托管所。

這里是我將Service中的回調(diào)方法抽出來寫成的1個(gè)接口

public interface I_CJService { IBinder onBind(Intent intent); void onCreate(); int onStartCommand(Intent intent, int flags, int startId); void onDestroy(); void onConfigurationChanged(Configuration newConfig); void onLowMemory(); void onTrimMemory(int level); boolean onUnbind(Intent intent); void onRebind(Intent intent); void onTaskRemoved(Intent rootIntent); }

//1個(gè)托管所類 class CJProxyService extends Service{ //采取包括關(guān)系 protected I_CJService mPluginService; // 插件Service對象 }

這里采取包括關(guān)系而不是采取繼承(或說實(shí)現(xiàn)1個(gè)接口)的方式,

是由于我們需要重寫Service中的方法,而這些被重寫的方法都需要用到接口對象相應(yīng)的接口方法。

public class CJProxyService extends Service{ @Override public void onConfigurationChanged(Configuration newConfig) { mPluginService.onConfigurationChanged(newConfig); super.onConfigurationChanged(newConfig); } @Override public void onLowMemory() { mPluginService.onLowMemory(); super.onLowMemory(); } @Override @SuppressLint("NewApi") public void onTrimMemory(int level) { mPluginService.onTrimMemory(level); super.onTrimMemory(level); } @Override public boolean onUnbind(Intent intent) { mPluginService.onUnbind(intent); return super.onUnbind(intent); } @Override public void onRebind(Intent intent) { mPluginService.onRebind(intent); super.onRebind(intent); } }

看到這里大家應(yīng)當(dāng)也就明白了,托管所實(shí)際上就是1個(gè)普通的Service類,但是這個(gè)托管所是正常運(yùn)行的,是由SDK管理回調(diào)函數(shù)的,我們通過這個(gè)Service的回調(diào)函數(shù)去調(diào)用插件Service中相應(yīng)的回調(diào)方法,就間接的管理了插件Service的生命周期(此處可以類比Activity與Fragment的關(guān)系)

到這里為止,我們已可以成功調(diào)起1個(gè)插件Service了,接下來的問題就是這個(gè)I_CJSrvice對象從哪里來?很簡單,通過類加載器加載1個(gè)

private void init(Intent itFromApp) { Object instance = null; try { Class<?> serviceClass; if (CJConfig.DEF_STR.equals(mDexPath)) { serviceClass = super.getClassLoader().loadClass(mClass); } else { serviceClass = this.getClassLoader().loadClass(mClass); } Constructor<?> serviceConstructor = serviceClass .getConstructor(new Class[] {}); instance = serviceConstructor.newInstance(new Object[] {}); } catch (Exception e) { } setRemoteService(instance); mPluginService.setProxy(this, mDexPath); } /** * 保存1份插件Service對象 */ protected void setRemoteService(Object service) { if (service instanceof I_CJService) { mPluginService = (I_CJService) service; } else { throw new ClassCastException( "plugin service must implements I_CJService"); } }

這樣就能夠拿到1個(gè)I_CJSrvice對象mPluginService了,如果到此為止,還是會有問題,由于此時(shí)mPluginService中例如onStart方法還對應(yīng)的是那個(gè)插件中的onStart也就是父類的onStart(這里比較繞,我不知道該如何描寫),而之前我們又說過,通過反射加載的類是沒有父類的,那末如果此時(shí)強(qiáng)迫調(diào)用那個(gè)反射對象的@Override方法是會報(bào)空指針的,由于找不到父類。那末解決的辦法就是再去插件Service中重寫每一個(gè)@Override的方法。

//.......篇幅有限,部份截取 public abstract class CJService extends Service implements I_CJService { /** * that指針指向的是當(dāng)前插件的Context(由因而插件化開發(fā),this指針絕對不能使用) */ protected Service that; // 替換this指針 @Override public IBinder onBind(Intent intent) { if (mFrom == CJConfig.FROM_PLUGIN) { return null; } else { return that.onBind(intent); } } }

通過代可以看到:我們使用了1個(gè)that對象來替換本來的this對象,然后我們只需要通過在托管所中將這個(gè)that對象賦值為托管所的this對象,也就是插件中的所有that.xxx都相當(dāng)于調(diào)用的是托管所的this.xxx,那末動態(tài)替換的目的就到達(dá)了,這樣我們也就成功的加載了1個(gè)未被安裝的插件apk中的Service。

    有關(guān)本類中的代碼,和完全的Demo,你可以關(guān)注:Android插件式開發(fā)框架 CJFrameForAndroid
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 伊人网综合 | 久久国产精品免费视频 | 欧美成人网视频 | 亚洲欧洲精品在线 | 毛片免费观看视频 | 欧美在线视频二区 | 久久久久久久久久久久久久久久久久久久 | 午夜av网站 | 9久久精品| 成人性视频免费网站 | 国内久久| a级片在线 | 欧美少妇一区二区 | 国产精品欧美在线 | 日韩区欧美区 | 日韩欧美中文 | 国产精品99久久 | 成人免费视频在线看 | 欧美日韩在线视频免费观看 | 欧美一区二区大片 | 国产精品视频42页 | 国产精品高清在线 | 在线视频 中文字幕 | 国产精品日韩在线观看 | 91这里只有精品 | 91大神免费观看 | 99在线视频播放 | 中国大陆高清aⅴ毛片 | 黄色高清美女免费网站 | 国产精品亚洲一区二区三区在线观看 | 亚洲精品久久久久 | 国产精品久久久久久久久久久久 | 国产欧美精品一区 | 精品在线一区二区三区 | 夜夜福利| 国产一区二区三区视频播放 | 精品一级| 黄色毛片免费观看 | 国产日韩久久 | a亚洲天堂 | 成人精品影院 |