緣起
隨着app項目的逐步迭代開發,單獨運行調試比較耗時,實行項目組件化拆分迫在眉睫,而跨組件通信是必須要解決的問題,而ARouter算是一個比較成熟的路由解決方案,所以寫下此篇文章,藉此來記錄。
一 、添加gradle基礎配置
apply plugin: 'kotlin-kapt'
android {
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.getName())
}
}
}
dependencies {
implementation 'com.alibaba:arouter-api:1.5.0'
kapt 'com.alibaba:arouter-compiler:1.2.2'
}
二、在application中初始化
if (BuildConfig.DEBUG) {
// 這兩行必須寫在init之前,否則這些配置在init過程中將無效
ARouter.openLog(); // 打印日誌
ARouter.openDebug();
// 開啓調試模式(如果在InstantRun模式下運行,必須開啓調試模式!線上版本需要關閉,否則有安全風險)
}
ARouter.init(this);
三、ARouter跳轉
- 抽取path常量
object PathConstant{
const val SERVICE_PATH="/app/service_path"
const val SECOND_ACTIVITY_PATH="/app/RouterSecondActivity"
const val INNER_FRAGMENT_PATH="/app/InnerFragment"
// secondModule
const val SECOND_MODULE_ACTIVITY_PATH="/secondmodule/MainActivity"
}
- 抽取Extra常量
object ExtraKeyConstant {
const val KEY_STRING_EXTRA="key_string_extra"
const val KEY_INT_EXTRA="key_int_extra"
const val KEY_BOOLEAN_EXTRA="key_boolean_extra"
const val KEY_LONG_EXTRA="key_long_extra"
const val KEY_OBJECT_EXTRA="key_object_extra"
}
- 跳轉
// 帶基本類型參數
btn_skip_two.setOnClickListener {
ARouter.getInstance().build(PathConstant.APP_MODULE_ROUTER_SECOND_ACTIVITY)
.withString(ExtraKeyConstant.KEY_STRING_EXTRA, "ARouter")
.withInt(ExtraKeyConstant.KEY_INT_EXTRA, 10)
.withLong(ExtraKeyConstant.KEY_LONG_EXTRA, 1)
.withBoolean(ExtraKeyConstant.KEY_BOOLEAN_EXTRA, true)
.navigation()
}
// 傳遞序列化對象
btn_skip_with_obj.setOnClickListener {
ARouter.getInstance().build(PathConstant.APP_MODULE_ROUTER_SECOND_ACTIVITY)
.withSerializable(ExtraKeyConstant.KEY_OBJECT_EXTRA, PersonEntity("peter", 18))
.navigation()
}
// 傳遞object
btn_skip_with_list.setOnClickListener {
val list = ArrayList<PersonEntity>()
list.add(PersonEntity("peter", 18))
list.add(PersonEntity("tommy", 20))
ARouter.getInstance().build(PathConstant.APP_MODULE_ROUTER_SECOND_ACTIVITY)
.withObject(ExtraKeyConstant.KEY_OBJECT_EXTRA, list)
.navigation()
}
// 跨module跳轉
btn_jump_second_module.setOnClickListener {
ARouter.getInstance().build(PathConstant.SECOND_MODULE_ACTIVITY_PATH)
.withTransition(R.anim.slide_in_bottom, R.anim.slide_out_bottom)
.withString(ExtraKeyConstant.KEY_STRING_EXTRA, "helloWorld").navigation()
}
注意跨module跳轉一定要在主module中添加其他module的引用,否則會找不到path
implementation project(':baselibrary')
implementation project(':secondmodule')
通過withObject()傳遞object,一定要新建一個類),然後實現 SerializationService,並使用@Route註解標註(方便用戶自行選擇序列化方式),否則會報空指針異常
- 添加Gson依賴
implementation 'com.google.code.gson:gson:2.8.6'
- JsonServiceImpl類
@Route(path = "/service/json")
class JsonServiceImpl : SerializationService {
private var mGson: Gson? = null
override fun init(context: Context?) {
mGson = Gson()
}
override fun <T> json2Object(text: String?, clazz: Class<T>?): T {
checkJson()
return mGson!!.fromJson(text, clazz)
}
override fun object2Json(instance: Any?): String {
checkJson()
return mGson!!.toJson(instance)
}
override fun <T> parseObject(input: String?, clazz: Type?): T {
checkJson()
return mGson!!.fromJson(input, clazz)
}
fun checkJson() {
if (mGson == null) {
mGson = Gson()
}
}
}
- 接收參數
- 注意要在接收跳轉的activity中添加Route註解,並添加 ARouter.getInstance().inject(this) 進行注入參數接收
@Route(path = PathConstant.APP_MODULE_ROUTER_SECOND_ACTIVITY)
class RouterSecondActivity : AppCompatActivity() {
@Autowired(name = ExtraKeyConstant.KEY_STRING_EXTRA)
@JvmField
var text = ""
@Autowired(name = ExtraKeyConstant.KEY_INT_EXTRA)
@JvmField
var intParam =0
@Autowired(name = ExtraKeyConstant.KEY_BOOLEAN_EXTRA)
@JvmField
var booleanParam =false
@Autowired(name = ExtraKeyConstant.KEY_LONG_EXTRA)
@JvmField
var longParam =0
@Autowired(name = ExtraKeyConstant.KEY_SERIALIZABLE_EXTRA)
@JvmField
var mPerson: PersonEntity? = null
@Autowired(name = ExtraKeyConstant.KEY_OBJECT_EXTRA)
@JvmField
var mList: List<PersonEntity>? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 注意一定要注入才能接收到參數
ARouter.getInstance().inject(this)
setContentView(R.layout.activity_router_second)
initData()
}
private fun initData() {
btn_second_text.text = "String data is $text int data is $intParam long data is $longParam boolean data is $booleanParam "
// 接收object參數
btn_second_obj_text.text = mPerson?.name + mPerson?.age
// 接收list
btn_second_list_text.text=if (mList.isNullOrEmpty()) "emptyList" else "list size is ${mList?.size}"
}
}
- 實現startActivityForResult效果獲取回傳數據
起始頁
// 類似startActivityForResult
btn_skip_with_response.setOnClickListener {
ARouter.getInstance().build(PathConstant.APP_MODULE_ROUTER_SECOND_ACTIVITY).navigation(this,
REQUEST_CODE)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode== REQUEST_CODE&&resultCode== RESULT_CODE){
Log.d(TAG,data?.getStringExtra(ExtraKeyConstant.KEY_SECOND_ACTIVITY_EXTRA))
}
}
companion object{
const val REQUEST_CODE=0X01
const val RESULT_CODE=0X02
}
結果頁
/**
* 設置返回數據
*/
private fun setResultData() {
val intent = Intent()
intent.putExtra(ExtraKeyConstant.KEY_SECOND_ACTIVITY_EXTRA, "secondActivityData")
setResult(RouterMainActivity.RESULT_CODE, intent)
}
四、跳轉過程監聽
// 獲取跳轉過程監聽
btn_skip_with_result.setOnClickListener {
val list = ArrayList<PersonEntity>()
list.add(PersonEntity("peter", 18))
list.add(PersonEntity("tommy", 20))
ARouter.getInstance().build(PathConstant.APP_MODULE_ROUTER_SECOND_ACTIVITY)
.withObject(ExtraKeyConstant.KEY_OBJECT_EXTRA, list)
.navigation(this, object : NavigationCallback {
override fun onLost(postcard: Postcard?) {
Log.d(TAG,"onLost")
}
override fun onFound(postcard: Postcard?) {
Log.d(TAG,"onFound")
}
override fun onInterrupt(postcard: Postcard?) {
Log.d(TAG,"onInterrupt")
}
override fun onArrival(postcard: Postcard?) {
Log.d(TAG,"onArrival")
}
})
}
五、添加攔截器,攔截路由跳轉參數,
AOP面向切面編程,做自己想做的事情
@Interceptor(priority = 8, name = "測試用攔截器")
class RouterInterceptor : IInterceptor {
override fun process(postcard: Postcard?, callback: InterceptorCallback?) {
Log.d("peter","埋點")
callback?.onContinue(postcard)
Log.d("peter","process")
}
override fun init(context: Context?) {
Log.d("peter","init")
}
}
六、獲取Fragment實例
- 創建Fragment並添加註解@Route
@Route(path = PathConstant.INNER_FRAGMENT_PATH)
class InnerFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return LayoutInflater.from(context).inflate(R.layout.fragment_inner, container,false)
}
}
- 獲取fragment實例
// 獲取fragment實例
val fragment = ARouter.getInstance().build(PathConstant.INNER_FRAGMENT_PATH).navigation() as Fragment
Log.d("peter", fragment.javaClass.canonicalName)
七、暴露服務
類似接口回調實現
- 定義接口實現IProvider
interface IService : IProvider {
override fun init(context: Context?) {
}
fun transferWords(words: String):String
}
- 創建接口實現類
@Route(path = PathConstant.SERVICE_PATH)
class ServiceImpl :IService{
override fun transferWords(words: String): String {
Log.d("peter",words)
return "words is helloWorld"
}
}
- 使用ARouter發現服務,並傳遞數據
btn_jump_service.setOnClickListener {
val serviceImpl= ARouter.getInstance().build(PathConstant.SERVICE_PATH).navigation() as IService
serviceImpl.transferWords("你好")
}
八、添加轉場動畫
- 使用
btn_jump_with_anim.setOnClickListener {
ARouter.getInstance().build(PathConstant.SECOND_ACTIVITY_PATH)
.withTransition(R.anim.slide_in_bottom, R.anim.slide_out_bottom)
.withString(ExtraKeyConstant.KEY_STRING_EXTRA, "helloWorld").navigation()
}
- anim文件
slide_in_bottom
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:fromYDelta="0%"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:toYDelta="100%"/>
slide_out_bottom
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:fromYDelta="100%"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:toYDelta="0%"/>
九、代碼混淆規則
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep public class com.alibaba.android.arouter.facade.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}
# 如果使用了 byType 的方式獲取 Service,需添加下面規則,保護接口
-keep interface * implements com.alibaba.android.arouter.facade.template.IProvider
# 如果使用了 單類注入,即不定義接口實現 IProvider,需添加下面規則,保護實現
# -keep class * implements com.alibaba.android.arouter.facade.template.IProvider