用Kotlin打造一個Router的示例代碼
0.
最近接收了從前的項目,之前的代碼比較凌亂,準備重構。整個項目其實功能比較明顯,而且產品還想給他打造成比較成熟牛逼的app,那么組件化開發(fā)勢在必行。眾所周知,模塊開發(fā),路由先行,就有了這篇文章。自從用了Kotlin后,感覺Java那些繁瑣的語法和喋喋不休的空指針判斷讓人惡心,于是決定用Kotlin來寫一個Router
1.
項目地址Router
代碼,想好再寫,首先分析一下為什么需要模塊化開發(fā),為什么路由并且這個路由需要什么功能。
1.1
為什么使用模塊化開發(fā):隨著項目的越來越大,如果把所有功能都放到一個module里,對開發(fā)和測試來說都有一個效率問題,對開發(fā)來講,由于各種業(yè)務代碼混合在一起,出現問題不好定位,對測試來講,每次修改都要重新編譯整個項目測試。采用組件化開發(fā),講業(yè)務模塊分到一個一個module里,彼此間相互獨立,這樣既容易定位問題,也方便測試人員進行測試,因為只需要測試相應的module即可。所以我們的項目結構應該是這樣的

1.2
為什么使用路由:上面說了,每個module是彼此獨立的,而要實現activity的跳轉就需要彼此引用,這是我們不想看到的,模塊間應該是沒有依賴的,那么如何實現不同模塊的跳轉呢?就需要路由了。
1.3
這個路由需要什么功能:目前所需要的就是根據url實現不同模塊之間的Activity跳轉,包括傳遞參數,類似startActivity和startActivityForResult,得到不同模塊的fragment。
2.
需求想好了,該想怎么實現了。activity跳轉有兩種,隱式調用和顯示調用,如果采取隱式調用就要為每個activity注冊intent-filter,麻煩,那就只能顯示調用了,但是顯示調用是需要class對象的,不同module是不能得到class對象的,這怎么搞?編譯前得不到,運行時總行吧,所以我們需要一個容器來存儲不同moudle里的class對象,并且能通過一個值來進行區(qū)分,所以我們需要一個map,而值就是用來區(qū)分各個activity和fragment的url。
第二個問題來了,url如何確定,class對象怎么得到,又怎么放進map里。這里我們采用注解來做,我們用在注解里聲明了url,同時自定義Processor,在編譯時生成java文件,里面只有一個方法
public void putRouteClass(ArrayMap<String, Class<?>> routableMap) {
routableMap.put("test", MainActivity.class);
}
根據講每個module里添加注解的Activity和fragment的class對象放入傳入的map里。之后再Application的onCreate方法里,調用Router的register方法
fun register(vararg moduleNames: String)
{
for (moduleName in moduleNames)
{
try
{
val cla = Class.forName(Constants.PACKAGE_NAME + Constants.DOT + moduleName + "_" + Constants.ROUTER_TABLE_IMP)
val routerTable = cla.newInstance() as RouterTable
routerTable.putRouteClass(classMap)
} catch (e: ClassNotFoundException)
{
e.printStackTrace()
} catch (e: Exception)
{
e.printStackTrace()
}
}
}
這個方法很簡單,調用每個module里利用Processor生成的對象的putRouteClass方法,將Router里的一個全局map傳入,這樣,這個map就持有了所有添加注解的Activity和fragment的url以及對應的class對象。有了class對象,那想怎么搞就怎么搞了
//類似startActivity
fun go(context: Context, url: String, extras: Bundle? = null)
{
val intent = Intent(context, classMap[url])
if (extras != null)
{
intent.putExtras(extras)
}
context.startActivity(intent)
}
fun go(fragment: Fragment,url: String, extras: Bundle? = null)
{
val context=fragment.context
if(context!=null)
{
go(context, url, extras)
}
}
//類似startActivityForResult
fun goForResult(context: Context, url: String, requestCode: Int, extras: Bundle? = null)
{
val intent = Intent(context, classMap[url])
if (extras != null)
{
intent.putExtras(extras)
}
if (context is Activity)
{
context.startActivityForResult(intent, requestCode)
} else if (context is Fragment)
{
context.startActivityForResult(intent, requestCode)
}
}
//得到fragment
fun getFragment(url: String): Fragment?
{
try
{
val cla = classMap[url]
if (cla != null)
{
return cla.newInstance() as Fragment
} else
{
}
} catch (e: ClassNotFoundException)
{
e.printStackTrace()
} catch (e: Exception)
{
e.printStackTrace()
}
return null
}
3.有些坑:
3.1
注冊注解解釋器的時候,不要使用google的autoservice庫了,采用resoureces,META-INF,不然沒效果。別問為什么,我也不知道
3.2
在gradle文件里使用注解解釋器使用kapt代替annoationProcessor
apply plugin: 'kotlin-kapt'
dependencies {
kapt project(':processor')
api project(':router')
}
3.3
生成的java文件在每個module的build/generated/source/kapt里
4.
其實在上家公司的時候就打算寫一個路由,只是由于種種原因最近沒能成型,這里只是給大家提供一種思路,作為思路文,就不在普及注解和編譯時注解解釋器了,請自行查詢資料。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
基于android startActivityForResult的學習心得總結
本篇文章是對android中的startActivityForResult進行了詳細的分析介紹,需要的朋友參考下2013-05-05
淺析AndroidStudio3.0最新 Android Profiler分析器(cpu memory network
Android Profiler分為三大模塊: cpu、內存 、網絡。本文給大家介紹AndroidStudio3.0最新 Android Profiler分析器(cpu memory network 分析器)的相關知識,他們的基本使用方法,在文中都給大家提到,具體內容詳情大家通過本文一起學習吧2017-12-12
flutter FadeTransition實現透明度漸變動畫
這篇文章主要為大家詳細介紹了flutter FadeTransition實現透明度漸變動畫,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-07-07

