ARouter 是阿里开源的一个优秀的路由框架,用在Android平台中对页面,服务提供路由功能的中间件。中间件这个概念之前是用在Web端,它是一种独立的服务程序,能够实现不同技术间的资源共享,管理计算资源和网络通信。
为什么Android中要用到其他(第三方)路由,默认系统已经提供路由如StartActivity?因为在一些复杂的,灵活性比较强的业务下(比如金融,电商),很多功能都是动态配置的,比如下发一个新的会员策略,活动页面等,事先时不知道具体的目标页面,但如果事先做了约定,提前做好页面映射,就可以动态配置。 其次,随着业务的增长,客户端的代码业务越来越大,会引起协作开发问题,资源共用问题,这时App大多会向组件化,插件化发展,而它们的前提就是解耦,解除页面之间的依赖关系。 简单来看一下ARouter的使用,代码如下:
1 添加依赖:
android {}
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.getName())
}
}
dependencies {
implementation 'com.alibaba:arouter-api:1.4.0'
kapt 'com.alibaba:arouter-compiler:1.2.1'
}
2 Application初始化
xxxApplication
override fun onCreate() {
super.onCreate()
// 打印日志
ARouter.openLog()
ARouter.openDebug()
ARouter.init(this)
}
3 添加注解
方式一 启动Activity
findViewById<Button>(R.id.main_btn).setOnClickListener{
ARouter.getInstance().build("/com/activity/ResultActivity").navigation()
}
目标Activity:
@Route(path = "/com/activity/ResultActivity")
class ResultActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_result)
}
}
方式二 通过Fragment启动Activity,并且回传参数
MainActivity
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val fragment = ARouter.getInstance().build("/com/fragment/kotlin").navigation() as Fragment
supportFragmentManager.beginTransaction().replace(R.id.root, fragment).commit()
}
}
@Route(path = "/com/fragment/result")
class ResultFragment : Fragment() {
var textView: TextView? = null ;
companion object {
const val REQUEST_CODE = 101
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val root = inflater.inflate(R.layout.fragment_result, container, false)
textView = root.findViewById<TextView>(R.id.fragment_text)
root.findViewById<Button>(R.id.btn).setOnClickListener {
FragmentResultRouter
.build(this@ResultFragment, "/com/activity/ResultActivity")
.navigation(REQUEST_CODE)
}
return root
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == Constants.REQUEST_CODE) {
val result = data!!.getStringExtra("data")
println("receive====ResultFragment 结果 : $result")
textView?.setText(result)
}
}
}
@Route(path = "/com/activity/ResultActivity")
class ResultActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_result)
}
override fun finish() {
val intent = Intent()
intent.putExtra("data", "world")
setResult(Activity.RESULT_OK, intent)
super.finish()
}
}
class FragmentResultRouter private constructor(fragment: Fragment) {
companion object {
private val router = ARouter.getInstance()
private var mHandler: Handler = Handler(Looper.getMainLooper())
fun build(fragment: Fragment, path: String): FragmentResultRouter {
val fragmentRouter = FragmentResultRouter(fragment)
fragmentRouter.postcard = router.build(path)
return fragmentRouter
}
fun build(fragment: Fragment, uri: Uri): FragmentResultRouter {
val fragmentRouter = FragmentResultRouter(fragment)
fragmentRouter.postcard = router.build(uri)
return fragmentRouter
}
}
private var fragment: Fragment = fragment
private lateinit var postcard: Postcard
fun setTag(tag: Any): FragmentResultRouter {
postcard.tag = tag
return this
}
fun navigation(requestCode: Int) {
navigation(requestCode, null)
}
fun navigation(requestCode: Int, callback: NavigationCallback?) {
try {
LogisticsCenter.completion(postcard)
} catch (e: NoRouteFoundException) {
if (null != callback) {
callback.onLost(postcard)
} else {
val degradeService = ARouter.getInstance().navigation(DegradeService::class.java)
degradeService?.onLost(fragment.context, postcard)
}
return
}
callback?.onFound(postcard)
if (!postcard.isGreenChannel) {
val interceptorService = ARouter.getInstance()
.build("/arouter/service/interceptor")
.navigation() as InterceptorService
interceptorService.doInterceptions(postcard, object : InterceptorCallback {
override fun onContinue(postcard: Postcard) {
internalNavigation(requestCode, callback)
}
override fun onInterrupt(exception: Throwable) {
callback?.onInterrupt(postcard)
}
})
} else {
internalNavigation(requestCode, callback)
}
}
private fun internalNavigation(requestCode: Int, callback: NavigationCallback?) {
val intent = Intent(fragment.activity, postcard.destination)
intent.putExtras(postcard.extras)
val flags = postcard.flags
if (-1 != flags) {
intent.flags = flags
}
// Set Actions
val action = postcard.action
if (!TextUtils.isEmpty(action)) {
intent.action = action
}
// Navigation in main looper.
if (Looper.getMainLooper().thread != Thread.currentThread()) {
mHandler.post {
fragment.startActivityForResult(intent, requestCode, postcard.optionsBundle)
if (-1 != postcard.enterAnim && -1 != postcard.exitAnim) { // Old version.
fragment.activity!!.overridePendingTransition(postcard.enterAnim, postcard.exitAnim)
}
}
} else {
fragment.startActivityForResult(intent, requestCode, postcard.optionsBundle)
if (-1 != postcard.enterAnim && -1 != postcard.exitAnim) { // Old version.
fragment.activity!!.overridePendingTransition(postcard.enterAnim, postcard.exitAnim)
}
}
callback?.onArrival(postcard)
}
fun with(bundle: Bundle?): FragmentResultRouter {
postcard.with(bundle)
return this
}
}
简单总结一下ARouter特点:
1 直接解析URL路由,解析参数并赋值到对应目标字段的页面中。
2 支持多模块项目,实现跨团队开发。
3 支持InstantRun,类似于代码的日更新,面向的是开发过程,这样可以减少开发和编译的次数,可以将代码修改即时地同步APK中,从而可以大规模降低开发复杂度。
4 允许自定义拦截器,ARouter是支持拦截器,而拦截器是AOP实现,可以自定义多个拦截器解决一些面向行为编程上出现的问题。
5 可以提供loC容器,控制反转。
6 映射关系自动注册,在页面不是很多的小型APP上面,自动注册并不会体现出太大优势,但是对于大型APP而言,可能页面数量已经达到的几十个或者数百个,在这样的情况下,自动注册就显得非常重要了,因为不可能将每一个页面都通过代码的方式进行注册。
7 灵活的降级策略,ARouter可以提供多种降级策略给用户,原生的路由方案如StartActivity,处理无法灵活降级问题,一旦失败就会抛出运营级异常;
官方地址:ARouter