您好,登錄后才能下訂單哦!
一、前言
開始模塊化開發項目之后,一個很重要的問題就是頁面見的跳轉問題。
關于模塊化發開,可詳見我的另一片文章 Android模塊化開發探索 。
正是由于將項目模塊化拆分,各模塊之間沒有任何依賴關系,也互相不可見,那么從A模塊的a界面跳轉到B模塊的b界面該怎么辦呢?
二、跨模塊跳轉的方法
這里我們會先介紹這幾種常見的跳轉方法:
2.1 顯示跳轉
顯示跳轉即我們最最常用的跳轉方法:使用Intent,傳入當前Activity上下文,和目標Activity的class對象即可,如下:
Intent intent = new Intent(); intent.setClass(mContext, GuideActivity.class); startActivity(intent);
顯然,這種方法只能是目標Activity可見(Activity在同一個Module下)的時候才可以這樣調用。不適合跨模塊間的跳轉。
2.2 隱示跳轉
我們這里說的隱示跳轉,intent不設置class,而是設置Action或者Category。
例如:
在清單文件中
<!--網頁展示界面--> <activity android:name="com.whaty.base.BaseWebViewActivity" android:hardwareAccelerated="true"> <intent-filter> <category android:name="android.intent.category.DEFAULT" /> <action android:name="com.whaty.base.BaseWebViewActivity" /> </intent-filter> </activity>
跳轉時:
//創建一個隱式的 Intent 對象:Action 動作 Intent intent = new Intent(); //設置 Intent 的動作為清單中指定的action intent.setAction("com.whaty.base.BaseWebViewActivity"); startActivity(intent);
2.3 scheme跳轉
如果我們為 B 頁面定義一個 URI - wsc://home/bbb,然后把共享的 messageModel 拍平序列化成 Json 串,那么 A 只需要拼裝一個符合 B 頁面 scheme 的跳轉協議就可以了。 wsc://home/bbb?message={ “name”:”John”, “age”:31, “city”:”New York” }
在清單文件中,配置data屬性,設置其host、path、scheme等
<activity android:name=".ui.BbbActivity" <intent-filter> <category android:name="android.intent.category.DEFAULT" /> <action android:name="android.intent.action.VIEW" /> <data android:host="bbb" android:path="/home" android:scheme="wsc" /> </intent-filter> </activity>
跳轉時:
final Uri uri = new Uri.Builder().authority("wsc").path("home/bbb").appendQueryParameter("message", new Gson().toJson(messageModel)).build(); final Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(uri); startActivity(intent);
以上的方法,都不是我們想要的,接下來開始介紹我們的Router方案。
三、為什么要用Router
Google提供了顯式和隱式兩種原生路由方案。但在模塊化開發中,顯式Intent存在類直接依賴的問題,造成模塊間嚴重耦合。隱式Intent則需要在Manifest中配置大量路徑,導致難以拓展(如進行跳轉攔截)。為了解決以上問題,我們需要采用一套更為靈活的Router方案。
四、實現思路
思路是這樣的:
使用注解,為每個目標Activity標注別名。在應用啟動時,對所有類進行掃名,將注解過的Activity存于路由表中。
跳轉時,在路由表中通過別名獲取目標Activity的class對象,使用Intent實現跳轉。
五、代碼實現
5.1 自定義注解
/** * Description: 路由跳轉界面 注解 * Created by jia on 2018/1/10. * 人之所以能,是相信能 */ @Target(ElementType.TYPE) //注解作用于類型(類,接口,注解,枚舉) @Retention(RetentionPolicy.RUNTIME) //運行時保留,運行中可以處理 @Documented // 生成javadoc文件 public @interface Action { String DEFAULT = "js"; String value() default DEFAULT; }
關于自定義注解的詳細介紹,請閱讀我的文章java進階之自定義注解。這里不再多說。
5.2 注解Activity
@Action("MainActivity") public class MainActivity extends BaseActivity implements TabLayout.OnTabSelectedListener { ... }
在創建Activity時,用剛剛自定義的注解進行注解,為其注釋別名。
5.3 啟動時掃描
private void getAllActivities(Context ctx){ try { //通過資源路徑獲得DexFile DexFile e = new DexFile(ctx.getPackageResourcePath()); Enumeration entries = e.entries(); //遍歷所有元素 while(entries.hasMoreElements()) { String entryName = (String)entries.nextElement(); //匹配Activity包名與類名 if(entryName.contains("activity") && entryName.contains("Activity")) { //通過反射獲得Activity類 Class entryClass = Class.forName(entryName); if(entryClass.isAnnotationPresent(Action.class)) { Action action = (Action)entryClass.getAnnotation(Action.class); this.map.put(action.value(), entryClass); } } } } catch (Exception e) { e.printStackTrace(); } }
在應用啟動時,Application中對包下的所有類進行掃描,先找到名字中到activity的(定義到activity包下),并將帶有注解標注的Activity,存入map中。
5.4 跳轉
/** * 頁面跳轉 * @param activity * @param alias */ public void jumpActivity(Activity activity, String alias) throws ClassNotFoundException{ if(map.containsKey(alias)) { Intent intent = new Intent(activity, map.get(alias)); activity.startActivity(intent); } else { throw new ClassNotFoundException(); } }
跳轉的時候傳入目標Activity的別名即可(這里的別名就是注解的別名)。
總結
通過這種方式,解決了跳轉Activity所產生的的模塊依賴問題,相較于原生方案,拓展性更強。但這種方案只是階段性的,還存在一些問題。首先,加載過程中,頻繁使用到反射,會產生性能問題。其次,對于每個Activity的別名,需要進行統一維護,增加了協作成本。還有待優化。
當然,市面上有很多流行的Router方案(如阿里的ARouter),這里只是介紹了一個思路,有好的建議歡迎交流,一起進步。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。