使用阿里ARouter路由实现组件化(模块化)开发流程
Android平台中对页面、服务提供路由功能的中间件,我的目标是 —— 简单且够用。
这是阿里对Arouter的定位,那么我们一起来梳理一下Arouter使用流程,和使用中我所遇到的一些问题!
先来看看有哪些功能
模块化的要解决的问题
-
模块间页面跳转(路由);
-
模块间事件通信;
-
模块间服务调用;
-
模块的独立运行;
-
模块间页面跳转路由拦截(登录)
-
其他注意事项;
对项目模块进行划分
app模块:主模块,主要进行搭载各个模块的功能。
lib_base:对ARouter进行初始化,和放置一些各个模块公用的封装类。
lib_icon:放置图片、assets、xml等公用资源文件
module_home,module_caht,module_recom,module_me:分别对应“首页”、“微聊”、“推荐”、“我的”模块!
ARouter各个模块的gradle配置
- 因为路由跳转是子模块都需要用到的,所以我们在lib_base 模块中引入
compile 'com.alibaba:arouter-api:1.2.4' annotationProcessor "com.alibaba:arouter-compiler:1.1.4" 包括整个项目中都会用到的其他依赖,例如: compile 'com.android.support:design:26.0.0-alpha1' compile 'org.simple:androideventbus:1.0.5.1' compile 'com.alibaba:fastjson:1.2.9'
因为我把拦截器等公用类在base注册,在编译期间生成路径映射。同时也需要在build中加入
defaultConfig { javaCompileOptions { annotationProcessorOptions { arguments = [moduleName: project.getName()] } } }
- 然后在各子模块的build文件中导入(也就是module_home,module_caht,module_recom,module_me):
/** * 及时在base已经引入了com.alibaba:arouter-compiler:1.1.4 * 这里也需要引入,不然报错 */ annotationProcessor 'com.alibaba:arouter-compiler:1.1.4' compile project(':lib_base') compile project(':lib_icon')
在编译期间生成路径映射。同时也需要在各子模块的build中加入:
defaultConfig { javaCompileOptions { annotationProcessorOptions { arguments = [moduleName: project.getName()] } } }
- 在app模块对各个子模块进行依赖:
compile project(':module_home') compile project(':module_chat') compile project(':module_recom') compile project(':module_me')
模块可插拔单独编译运行
模块化的好处之一就是单一模块可以独立的开发编译运行安装到用户的手机上,这样就方便了对某一模块的单独开发调试,单一模块生成的apk体积也小,编译时间也快,开发效率会高很多。
- 项目根目录gradle.properties配置:
# 是否需要单独编译 true表示不需要,false表示需要 isNeedHomeModule=true #isNeedHomeModule=false isNeedChatModule=true #isNeedChatModule=false isNeedRecomModule=true #isNeedRecomModule=false isNeedMeModule=true #isNeedMeModule=false
- 在各个子模块中配置(例如module_me):
if (!isNeedMeModule.toBoolean()) { apply plugin: 'com.android.application' } else { apply plugin: 'com.android.library' }
defaultConfig { if (!isNeedMeModule.toBoolean()) { applicationId "tsou.cn.module_me" } }
- 在app主模块中:
if (isNeedHomeModule.toBoolean()) { compile project(':module_home') } if (isNeedChatModule.toBoolean()) { compile project(':module_chat') } if (isNeedRecomModule.toBoolean()) { compile project(':module_recom') } if (isNeedMeModule.toBoolean()) { compile project(':module_me') }
如果需要单独运行某个模块时,修改gradle.properties配置,
例如单独运行module_home模块时,开启isNeedHomeModule=false,
- 方式一:直接在AndroidManifest.xml的MainActivity添加
<intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter>
反之则关闭!当然比较lou
- 方式二:通过build自动配置
1、主目录下AndroidManifest.xml不变
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="tsou.cn.module_home"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> </activity> </application> </manifest>
2、在src目录下创建debug文件夹包含一个AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="tsou.cn.module_home"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
3、在子模块的build中配置
android { ... sourceSets { main { if (!isNeedHomeModule.toBoolean()) { manifest.srcFile 'src/debug/AndroidManifest.xml' } else { manifest.srcFile 'src/main/AndroidManifest.xml' java { //全部Module一起编译的时候剔除debug目录 exclude '**/debug/**' } } } } }
4、运行module_home即可
ARouter初始化
在lib_base中创建MyApplication
public class MyApplication extends Application { /** * 上下文 */ private static MyApplication instance; @Override public void onCreate() { super.onCreate(); instance = this; initRouter(this); } public static Context getInstance() { return instance; } private void initRouter(MyApplication mApplication) { // 这两行必须写在init之前,否则这些配置在init过程中将无效 if (UIUtils.isApkInDebug(instance)) { //打印日志 ARouter.openLog(); //开启调试模式(如果在InstantRun模式下运行,必须开启调试模式! //线上版本需要关闭,否则有安全风险) ARouter.openDebug(); } // 尽可能早,推荐在Application中初始化 ARouter.init(mApplication); } }
/** * 判断当前应用是否是debug状态 */ public static boolean isApkInDebug(Context context) { try { ApplicationInfo info = context.getApplicationInfo(); return (info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; } catch (Exception e) { return false; } }
这里要注意:如果你在debug模式下进行调试代码,ARouter.openDebug();一定要调用,否则ARouter会出现无效情况。
首页的搭建
使用ARouter来获取到各个模块的Fragment
package tsou.cn.lib_base.utils; /** * Created by Administrator on 2017/12/4 0004. */ public class RouteUtils { //获得home模块fragment public static final String Home_Fragment_Main = "/home/main"; //获得chat模块fragment public static final String Chat_Fragment_Main = "/chat/main"; //获得Recom模块fragment public static final String Recom_Fragment_Main = "/recom/main"; //获得Me模块fragment public static final String Me_Fragment_Main = "/me/main"; //跳转到登录页面 public static final String Me_Login = "/me/main/login"; //跳转到eventBus数据接收页面 public static final String Me_EventBus = "/me/main/EventBus"; //跳转到TextOne数据接收页面 public static final String Me_TextOne = "/me/main/TextOne"; //跳转到Test公用页面 public static final String Me_Test = "/me/main/Test"; //路由拦截 public static final String Me_Test2 = "/me/main/Test2"; //跳转到webview页面 public static final String Me_WebView = "/me/main/WebView"; //跳转到依赖注入页面 public static final String Me_Inject = "/me/main/Inject"; /** * 依赖注入使用,注意:必须实现SerializationService进行注册, */ public static final String Home_Json_Service = "/huangxiaoguo/json"; //跳转ForResult public static final String Chat_ForResult = "/chat/main/ForResult"; //模块间服务调用,调用chat模块的接口 public static final String Service_Chat = "/chat/service"; //路由拦截 public static final String Chat_Interceptor = "/chat/main/Interceptor"; /** * 专门的分组,这里就叫做needLogin组,凡是在这个组下的,都会进行登录操作 */ public static final String NeedLogin_Test3 = "/needLogin/main/Test3"; }
package tsou.cn.myaroutertest.utils; import android.support.v4.app.Fragment; import com.alibaba.android.arouter.launcher.ARouter; import tsou.cn.lib_base.utils.RouteUtils; /** * Created by Administrator on 2017/12/4 0004. */ public class FragmentUtils { public static Fragment getHomeFragment() { Fragment fragment = (Fragment) ARouter.getInstance().build(RouteUtils.Home_Fragment_Main).navigation(); return fragment; } public static Fragment getChatFragment() { Fragment fragment = (Fragment) ARouter.getInstance().build(RouteUtils.Chat_Fragment_Main).navigation(); return fragment; } public static Fragment getRecomFragment() { Fragment fragment = (Fragment) ARouter.getInstance().build(RouteUtils.Recom_Fragment_Main).navigation(); return fragment; } public static Fragment getMeFragment() { Fragment fragment = (Fragment) ARouter.getInstance().build(RouteUtils.Me_Fragment_Main).navigation(); return fragment; } }
package tsou.cn.myaroutertest; import android.os.Bundle; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import java.util.ArrayList; import tsou.cn.myaroutertest.utils.FragmentUtils; public class MainActivity extends AppCompatActivity { private ViewPager mMViewPager; private TabLayout mToolbarTab; /** * 图标 */ private int[] tabIcons = { R.drawable.tab_home, R.drawable.tab_weichat, R.drawable.tab_recommend, R.drawable.tab_user }; private String[] tab_array; private DemandAdapter mDemandAdapter; private ArrayList<Fragment> fragments = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); initView(); // 给viewpager设置适配器 setViewPagerAdapter(); setTabBindViewPager(); setItem(); } private void initData() { tab_array = getResources().getStringArray(R.array.tab_main); fragments.clear(); fragments.add(FragmentUtils.getHomeFragment()); fragments.add(FragmentUtils.getChatFragment()); fragments.add(FragmentUtils.getRecomFragment()); fragments.add(FragmentUtils.getMeFragment()); } private void initView() { mMViewPager = (ViewPager) findViewById(R.id.mViewPager); mToolbarTab = (TabLayout) findViewById(R.id.toolbar_tab); } private void setViewPagerAdapter() { mDemandAdapter = new DemandAdapter(getSupportFragmentManager()); mMViewPager.setAdapter(mDemandAdapter); } private void setTabBindViewPager() { mToolbarTab.setupWithViewPager(mMViewPager); } private void setItem() { /** * 一定要在设置适配器之后设置Icon */ for (int i = 0; i < mToolbarTab.getTabCount(); i++) { mToolbarTab.getTabAt(i).setCustomView(getTabView(i)); } } public View getTabView(int position) { View view = LayoutInflater.from(this).inflate(R.layout.item_tab, null); ImageView tab_image = view.findViewById(R.id.tab_image); TextView tab_text = view.findViewById(R.id.tab_text); tab_image.setImageResource(tabIcons[position]); tab_text.setText(tab_array[position]); return view; } /** * 适配器 */ public class DemandAdapter extends FragmentStatePagerAdapter { public DemandAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return fragments.get(position); } @Override public int getCount() { return fragments.size(); } } }
代码中有注释,切很简单,不会出现什么毛病!如果有小毛病,就clean一下解决
使用ARouter路由实现各种功能
- 跨模块跳转Activity
-
实现这个Activity跳转的路径。
//跳转到我的模块登录页面 public static final String Me_Login = "/me/main/login";
ARouter跳转Activity,在这个Activity上加入注解。
@Route(path = RouteUtils.Me_Login) public class LoginActivity extends AppCompatActivity implements View.OnClickListener {
跳转逻辑是
//登录(跨模块跳转Activity) ARouter.getInstance().build(RouteUtils.Me_Login).navigation();
跨模块实现ForResult返回数据(activity中使用)
实现这个Activity跳转的路径。
//跳转ForResult public static final String Chat_ForResult = "/chat/main/ForResult";
ARouter跳转Activity,在这个Activity上加入注解。
@Route(path = RouteUtils.Chat_ForResult) public class ForResultActivity extends AppCompatActivity implements View.OnClickListener {
跳转逻辑是
//跳转ForResult,在fragment中使用不起作用 ARouter.getInstance().build(RouteUtils.Chat_ForResult).navigation(this, 666);
接收数据数据
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case 666: String name = data.getStringExtra("name"); UIUtils.showToast(name + ",resultCode===>" + resultCode); break; default: break; } }
返回数据
Intent intent = new Intent(); intent.putExtra("name", "ForResult返回的数据"); setResult(999, intent); finish();
- 跳转并携带参数和Eventbus夸模块通信
EventBus.getDefault().register(this); EventBus.getDefault().unregister(this); @Subscriber(tag = EvenBusTag.GOTO_EVENTBUS) public void onEvent(String s) { UIUtils.showToast(s); }
//跳转到eventBus数据接收页面 public static final String Me_EventBus = "/me/main/EventBus";
@Route(path = RouteUtils.Me_EventBus) public class EventBusActivity extends AppCompatActivity implements View.OnClickListener {
// 跳转并携带参数,基本涵盖所以类型传递,具体可以查看Postcard类 //传递过去的值使用getIntent()接收 //在fragment中无法使用ForResult进行夸模块传递数据 //在activity中可以(详细请看LoginActivity)这里的EventBusBean 已经实现了Parcelable接口 EventBusBean eventBusBean = new EventBusBean(); eventBusBean.setProject("android"); eventBusBean.setNum(3); ARouter.getInstance().build(RouteUtils.Me_EventBus) .withString("name", "haungxiaoguo") .withLong("age", 25) .withParcelable("eventbus", eventBusBean) .navigation();
@Route(path = RouteUtils.Me_EventBus) public class EventBusActivity extends AppCompatActivity implements View.OnClickListener { /** * eventBus数据接收页面 */ private TextView mTextView; /** * eventBus返回数据 */ private Button mBtnBackData; private String name; private long age; private EventBusBean eventbus; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_event_bus); ARouter.getInstance().inject(this); initData(); initView(); } private void initData() { name = getIntent().getStringExtra("name"); age = getIntent().getLongExtra("age", 0); eventbus = getIntent().getParcelableExtra("eventbus"); } private void initView() { mTextView = (TextView) findViewById(R.id.textView); mBtnBackData = (Button) findViewById(R.id.btn_back_data); mBtnBackData.setOnClickListener(this); mTextView.setText("name=" + name + ",\tage=" + age + ",\tproject=" + eventbus.getProject() + ",\tnum=" + eventbus.getNum()); } @Override public void onClick(View v) { int i = v.getId(); if (i == R.id.btn_back_data) { EventBus.getDefault().post(name, EvenBusTag.GOTO_EVENTBUS); finish(); } else { } } }
路径配置都是一样,以下只介绍跳转方式
- 使用Uri应用内跳转
EventBusBean eventBusBean = new EventBusBean(); eventBusBean.setProject("android"); eventBusBean.setNum(3); Uri testUriMix = Uri.parse("arouter://tsou.cn.huangxiaoguo/me/main/EventBus"); ARouter.getInstance().build(testUriMix) .withString("name", "haungxiaoguo") .withLong("age", 25) .withParcelable("eventbus", eventBusBean) .navigation();
- 旧版本转场动画
//旧版本转场动画 ARouter.getInstance() .build(RouteUtils.Me_Test) .withTransition(R.anim.slide_in_bottom, R.anim.slide_out_bottom) .navigation(getContext());//context上下文不传无效果
- 新版本转场动画
//新版本转场动画 if (Build.VERSION.SDK_INT >= 16) { ActivityOptionsCompat compat = ActivityOptionsCompat. makeScaleUpAnimation(v, v.getWidth() / 2, v.getHeight() / 2, 0, 0); ARouter.getInstance() .build(RouteUtils.Me_Test) .withOptionsCompat(compat) .navigation(); } else { UIUtils.showToast("API < 16,不支持新版本动画"); }
- 通过URL跳转(webview)
//通过URL跳转(webview) ARouter.getInstance() .build(RouteUtils.Me_WebView) .withString("url", "file:///android_asset/schame-test.html") .navigation();
拦截器操作
首先实现IInterceptor:
package tsou.cn.lib_base.interceptor; import android.content.Context; import android.util.Log; import com.alibaba.android.arouter.facade.Postcard; import com.alibaba.android.arouter.facade.annotation.Interceptor; import com.alibaba.android.arouter.facade.callback.InterceptorCallback; import com.alibaba.android.arouter.facade.template.IInterceptor; import com.alibaba.android.arouter.launcher.ARouter; import tsou.cn.lib_base.utils.RouteUtils; /** * Created by Administrator on 2017/12/6 0006. * 添加拦截器的时候,建议clean再打包运行,不然会出现,无效的情况 * <p> * 切记一个项目里面priority的值保证唯一,不然会出毛病 */ @Interceptor(priority = 1, name = "重新分组进行拦截") public class MyDataInterceptor implements IInterceptor { @Override public void process(Postcard postcard, InterceptorCallback callback) { if (postcard.getGroup().equals("needLogin")) { Log.e("huangxiaoguo", "需要去登陆"); //直接执行 // callback.onContinue(postcard); //直接拦截,走onLost方法 // callback.onInterrupt(null); //添加数据 // postcard.withString("extra", "我是在拦截器中附加的参数"); // callback.onContinue(postcard); callback.onInterrupt(null); ARouter.getInstance().build(RouteUtils.Me_Login) .withString("path", postcard.getPath()).navigation(); } else { postcard.withString("extra", "我是在拦截器中附加的参数"); callback.onContinue(postcard); } } @Override public void init(Context context) { } }
接收未拦截时拦截器添加的数据(postcard.withString(“extra”, “我是在拦截器中附加的参数”);)
private void initData() { extra = getIntent().getStringExtra("extra"); }
对目标Activity指定新的分组(组名为“needLogin”,注意同时也是“me”组下的成员)
@Route(path = RouteUtils.Me_Test2, group = "needLogin") public class Test2Activity extends AppCompatActivity {
- 拦截器操作(利用重新分组拦截)
/** * 如果利用重新分组,就需要在build中进行指定的分组不然没有效果 */ ARouter.getInstance() .build(RouteUtils.Me_Test2, "needLogin") .navigation(getContext(), new NavCallback() { @Override public void onFound(Postcard postcard) { super.onFound(postcard); //路由目标被发现时调用 Log.e("huangxiaoguo", "发现了"); } @Override public void onLost(Postcard postcard) { super.onLost(postcard); //路由被丢失时调用 Log.e("huangxiaoguo", "丢失了"); } @Override public void onArrival(Postcard postcard) { //路由到达之后调用 Log.e("huangxiaoguo", "到达了"); } @Override public void onInterrupt(Postcard postcard) { super.onInterrupt(postcard); //路由被拦截时调用 Log.e("huangxiaoguo", "拦截了"); } });
- 拦截器操作(利用原有分组)
/** * 专门的分组,这里就叫做needLogin组,凡是在这个组下的,都会进行登录操作 */ public static final String NeedLogin_Test3 = "/needLogin/main/Test3";
@Route(path = RouteUtils.NeedLogin_Test3) public class Test3Activity extends AppCompatActivity {
//拦截器操作(利用原有分组) ARouter.getInstance().build(RouteUtils.NeedLogin_Test3).navigation();
- 拦截器操作(绿色通道,跳过拦截器)
//拦截器操作(绿色通道,跳过拦截器) ARouter.getInstance().build(RouteUtils.NeedLogin_Test3) .withString("extra", "我是绿色通道直接过来的,不经过拦截器") .greenChannel() .navigation();
- 依赖注入
- 必须先初始化JsonServiceImpl实现SerializationService
-
package tsou.cn.lib_base.JsonService; import android.content.Context; import com.alibaba.android.arouter.facade.annotation.Route; import com.alibaba.android.arouter.facade.service.SerializationService; import com.alibaba.fastjson.JSON; import java.lang.reflect.Type; import tsou.cn.lib_base.utils.RouteUtils; /** * 依赖注入使用,注意:必须实现SerializationService进行注册, */ @Route(path = RouteUtils.Home_Json_Service,name = "序列化JavaBean使用") public class JsonServiceImpl implements SerializationService { @Override public void init(Context context) { } @Override public <T> T json2Object(String text, Class<T> clazz) { return JSON.parseObject(text, clazz); } @Override public String object2Json(Object instance) { return JSON.toJSONString(instance); } @Override public <T> T parseObject(String input, Type clazz) { return JSON.parseObject(input, clazz); } }
实现跳转
/** * 序列化过得 * 必须先初始化JsonServiceImpl实现SerializationService */ EventBusBean eventBusBean = new EventBusBean(); eventBusBean.setProject("android"); eventBusBean.setNum(3); /** * 普通的javaBean */ JavaBean javaBean = new JavaBean(); javaBean.setName("huangxiaoguo"); javaBean.setAge(25); List<JavaBean> objList = new ArrayList<>(); objList.add(javaBean); Map<String, List<JavaBean>> map = new HashMap<>(); map.put("testMap", objList); ARouter.getInstance().build(RouteUtils.Me_Inject) .withString("name", "老王") .withInt("age", 18) .withBoolean("boy", true) .withLong("high", 180) .withString("url", "https://www.baidu.com") .withParcelable("pac", eventBusBean) .withObject("obj", javaBean) .withObject("objList", objList) .withObject("map", map) .navigation();
接收数据
package tsou.cn.module_me.activity; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.widget.TextView; import com.alibaba.android.arouter.facade.annotation.Autowired; import com.alibaba.android.arouter.facade.annotation.Route; import com.alibaba.android.arouter.launcher.ARouter; import java.util.List; import java.util.Map; import tsou.cn.lib_base.bean.EventBusBean; import tsou.cn.lib_base.bean.JavaBean; import tsou.cn.lib_base.utils.RouteUtils; import tsou.cn.module_me.R; /** * 依赖注入使用,注意:必须实现SerializationService进行注册, */ @Route(path = RouteUtils.Me_Inject) public class InjectActivity extends AppCompatActivity { @Autowired String name = "hahahha"; @Autowired int age = 13; @Autowired(name = "boy")//映射参数名 boolean sex; @Autowired long high = 160; @Autowired String url; @Autowired EventBusBean pac; @Autowired JavaBean obj; @Autowired List<JavaBean> objList; @Autowired Map<String, List<JavaBean>> map; @Autowired int height = 21;//上页面没有传递 private TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_inject); ARouter.getInstance().inject(this); initView(); } private void initView() { mTextView = (TextView) findViewById(R.id.textView); String params = String.format( "name=%s,\n age=%s, \n height=%s,\n girl=%s,\n high=%s,\n url=%s,\n pac=%s,\n obj=%s \n" + " objList=%s, \n map=%s", name, age, height, sex, high, url, pac.getProject(), obj.getName(), objList.get(0).getName(), map.get("testMap").get(0).getName() ); mTextView.setText(params); } }
模块间服务调用
首先,为了所有子类模块都能共享这个方法,我们在lib_base中定义一个服务接口:
package tsou.cn.lib_base.provider; import com.alibaba.android.arouter.facade.template.IProvider; /** * Created by Administrator on 2017/12/5 0005. * 如果是共有的module_base里的方法,不同模块都可以调用。 * 但如果属于两个模块的独有方法,其他模块是不能调用的, * 此时使用ARouter的IProvider来实现 */ public interface IChatModuleService extends IProvider { String getUserName(String userId); }
该接口有个未实现的方法叫getUserName,获取用户名称,接口写好了由谁来实现呢?获取用户所在的地址只有chat模块才有这个方法,所以就需要在chat模块中来实现这个接口了,我们把它叫做ChatModuleService
package tsou.cn.module_chat.module_service; import android.content.Context; import com.alibaba.android.arouter.facade.annotation.Route; import tsou.cn.lib_base.provider.IChatModuleService; import tsou.cn.lib_base.utils.RouteUtils; import tsou.cn.module_chat.net.ChatService; /** * Created by Administrator on 2017/12/5 0005. */ @Route(path = RouteUtils.Service_Chat) public class ChatModuleService implements IChatModuleService { @Override public String getUserName(String userId) { return ChatService.getUserName(); } @Override public void init(Context context) { } }
和Activity和Fragment一样,我们也需要在实现的Service上加上path路由注解,这样ARouter框架才能发现这个服务,而且不同模块的Service的path前的组“/chat/”一定要是不一样的,不然会出现找不到的情况:
//模块间服务调用,调用chat模块的接口 public static final String Service_Chat = "/chat/service";
ChatService类中简单的写了一个getUserName方法,返回用户的名称
package tsou.cn.module_chat.net; /** * Created by Administrator on 2017/12/5 0005. */ public class ChatService { public static String getUserName() { return "从服务器获取的数据“hangxiaoguo”"; } }
接下来就是服务的发现(我放在了base中方便各个模块的使用),调用方法:
package tsou.cn.lib_base.route_service; /** * Created by Administrator on 2017/12/5 0005. * <p> * 服务的发现 */ public class ModuleRouteService { public static String getUserName(String userId) { IChatModuleService chatModuleService = ARouter.getInstance().navigation(IChatModuleService.class); if (chatModuleService != null) { return chatModuleService.getUserName(userId); } return ""; } }
- 模块间服务调用(普通调用)
//模块间服务调用 //例如home模块调用chat模块的方法 String userName = ModuleRouteService.getUserName("userId"); UIUtils.showToast(userName);
- 模块间通过路径名称调用服务
//模块间通过路径名称调用服务 String userName = ((IChatModuleService) ARouter.getInstance() .build(RouteUtils.Service_Chat) .navigation()) .getUserName("userid"); UIUtils.showToast(userName);
- 模块间通过类名调用服务
//模块间通过类名调用服务 String userName = ARouter.getInstance() .navigation(IChatModuleService.class) .getUserName("userid"); UIUtils.showToast(userName);
跳转失败
//跳转失败 ARouter.getInstance().build("/xxx/xxx").navigation(getContext(), new NavCallback() { @Override public void onFound(Postcard postcard) { UIUtils.showToast("找到了"); } @Override public void onLost(Postcard postcard) { UIUtils.showToast("找不到了"); } @Override public void onArrival(Postcard postcard) { UIUtils.showToast("跳转完了"); } @Override public void onInterrupt(Postcard postcard) { UIUtils.showToast("被拦截了"); } });
因为/xxx/xxx这个路径没有对应的activity或fragment所以会跳转失败,走onLost方法。
-
- 拦截器操作(利用重新分组拦截)
- 使用Uri应用内跳转
-