ARouter入门之从零开始——Kotlin版

缘起

随着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()
            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  json2Object(text: String?, clazz: Class?): T {
        checkJson()
        return mGson!!.fromJson(text, clazz)
    }

    override fun object2Json(instance: Any?): String {
        checkJson()
        return mGson!!.toJson(instance)
    }

    override fun  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? = 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()
            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




slide_out_bottom




九、代码混淆规则

-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

十、参考:

ARouter中文文档README_CN

你可能感兴趣的:(Kotlin)