多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > 互聯網 > Android插件化開發---運行未安裝apk中的Service

Android插件化開發---運行未安裝apk中的Service

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

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

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

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

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

public class CJClassLoader extends DexClassLoader { //創建1個插件加載器集合,對固定的dex使用固定的加載器可以避免多個加載器同時加載1個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對應的加載器 */ 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個開始,接著我們需要斟酌1個問題,1個Service是有oncreate->onstart->ondestroy生命周期和1些回調方法的,這些回調方法在我們正常使用的時候是由父類們(包括has...a...關系)或說是SDK管理的,那末當我們通過類加載器加載的時候,它是沒有能夠管理的父類的,也就是說我們需要自己摹擬SDK去管理插件Service的回調函數。那末這個去管理插件Service的類,就是之條件到的托管所。

這里是我將Service中的回調方法抽出來寫成的1個接口

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個托管所類 class CJProxyService extends Service{ //采取包括關系 protected I_CJService mPluginService; // 插件Service對象 }

這里采取包括關系而不是采取繼承(或說實現1個接口)的方式,

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

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); } }

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

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

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個I_CJSrvice對象mPluginService了,如果到此為止,還是會有問題,由于此時mPluginService中例如onStart方法還對應的是那個插件中的onStart也就是父類的onStart(這里比較繞,我不知道該如何描寫),而之前我們又說過,通過反射加載的類是沒有父類的,那末如果此時強迫調用那個反射對象的@Override方法是會報空指針的,由于找不到父類。那末解決的辦法就是再去插件Service中重寫每一個@Override的方法。

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

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

    有關本類中的代碼,和完全的Demo,你可以關注:Android插件式開發框架 CJFrameForAndroid
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 日韩欧美精品中文字幕 | 伊人蕉久 | 亚洲国产天堂久久九九九 | 国产免费久久精品久久久 | 欧美videosex| 国产三级理论片 | 日韩99精品| 免费在线看v片 | 国产福利一区二区三区视频在线 | 免费中日高清无专码有限公司 | 免费播放欧美毛片欧美a | 最新日韩欧美不卡一二三区 | 亚洲图片欧美视频 | 亚洲天堂影院 | 日本欧美在线 | 复仇之路在线观看免费版高清 | 五月视频 | 在线 | 一区二区三区四区 | 大杳焦伊人久久综合热 | 国产成人影院在线观看 | 中文字幕在线天堂 | 国产精品久久亚洲不卡4k岛国 | 久久天堂 | 日韩精品在线一区二区 | 亚洲欧美一区二区三区蜜芽 | 成人淫片免费视频95视频 | www精品久久| 亚洲五月婷婷 | 国产成人欧美一区二区三区的 | 日韩中文字幕视频在线 | 亚洲综合视频网 | 欧美精品福利视频 | 欧美毛片视频 | 日韩欧美精品综合一区二区三区 | 好大好湿好硬顶到了好爽在 | 最新国产大片高清视频 | 午夜视频在线看 | 欧美18videosex性欧 | 日韩天天摸天天澡天天爽视频 | 亚洲国产综合视频 | 国产成人黄网址在线视频 |