使用阿里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) != ;
} 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 = ; 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, );
接收数据数据
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case :
String name = data.getStringExtra("name");
UIUtils.showToast(name + ",resultCode===>" + resultCode);
break;
default:
break;
}
}返回数据
Intent intent = new Intent();
intent.putExtra("name", "ForResult返回的数据");
setResult(, 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(); ARouter.getInstance().build(RouteUtils.Me_EventBus)
.withString("name", "haungxiaoguo")
.withLong("age", )
.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", );
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(); Uri testUriMix = Uri.parse("arouter://tsou.cn.huangxiaoguo/me/main/EventBus");
ARouter.getInstance().build(testUriMix)
.withString("name", "haungxiaoguo")
.withLong("age", )
.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 >= ) {
ActivityOptionsCompat compat = ActivityOptionsCompat.
makeScaleUpAnimation(v, v.getWidth() / , v.getHeight() / , , );
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 = , 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();
/**
* 普通的javaBean
*/
JavaBean javaBean = new JavaBean();
javaBean.setName("huangxiaoguo");
javaBean.setAge(); 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", )
.withBoolean("boy", true)
.withLong("high", )
.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 = ; @Autowired(name = "boy")//映射参数名
boolean sex; @Autowired
long high = ; @Autowired
String url; @Autowired
EventBusBean pac; @Autowired
JavaBean obj; @Autowired
List<JavaBean> objList; @Autowired
Map<String, List<JavaBean>> map; @Autowired
int height = ;//上页面没有传递 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().getName(),
map.get("testMap").get().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应用内跳转
使用阿里ARouter路由实现组件化(模块化)开发流程的更多相关文章
- App 组件化/模块化之路——构建开发架构思路
App 组件化/模块化开发架构思路 随着业务的发展 App 开发技术也越来越成熟,对开发者来说 App 代码量也迅速地增长到一个数量级.对于如何架构 App 已经每个开发者面临的实际问题.好的架构可以 ...
- App 组件化/模块化之路——如何封装网络请求框架
App 组件化/模块化之路——如何封装网络请求框架 在 App 开发中网络请求是每个开发者必备的开发库,也出现了许多优秀开源的网络请求库.例如 okhttp retrofit android-asyn ...
- App 组件化/模块化之路——Repository 模式
什么是 Repository 模式 Repository 这个词直译过来仓库.仓储的意思.这个意思其实也能反应出 Repository 模式作用.App 开发中少不了对数据的操作,数据的来源可能有很多 ...
- App 组件化/模块化之路——Android 框架组件(Android Architecture Components)使用指南
面对越来越复杂的 App 需求,Google 官方发布了Android 框架组件库(Android Architecture Components ).为开发者更好的开发 App 提供了非常好的样本. ...
- Android 组件化/模块化之路——在展示层搭建MVP结构
Android 组件化/模块化之路——在展示层搭建MVP结构 什么是MVP Model–View–Presenter (MVP) 源于 Model–View–Controller (MVC) 的结构设 ...
- App 组件化/模块化之路——使用SDK的思路进行模块化设计接口
在不久之前分享一篇<App 组件化/模块化之路——如何封装网络请求框架>文章介绍了我在项目中封装网络请求框架的思路.开发一个 App 会涉及到很多网络请求 API ,例如登录注册接口.用户 ...
- 组件化网页开发 / 步骤一 · 4-4 匹配HTML标签
组件化网页开发 / 步骤一 · 4-4 匹配HTML标签
- 企业 SOA 设计(2)–组件化产品开发平台
上一篇<企业 SOA 设计(1)–ESB 设计>中,写到我们的 SOA 设计分为两个层面来进行:一个是系统间的 SOA 设计,主要通过 ESB 来完成:另一方面则是单个应用系统内部的 SO ...
- Vue-Router路由 Vue-CLI脚手架和模块化开发 之 使用路由对象获取参数
使用路由对象$route获取参数: 1.params: 参数获取:使用$route.params获取参数: 参数传递: URL传参:例 <route-linke to : "/food ...
随机推荐
- Vue CLI4.0版本正式发布了!一起来看看有哪些新的变化吧
Vue CLI4.0版本正式发布 这个主要的版本更新主要关注底层工具的必要版本更新.更好的默认设置和其他长期维护所需的微调. 我们希望为大多数用户提供平稳的迁移体验. Vue CLI v4提供了对Ni ...
- 满减 HRBUST - 2455
https://vjudge.net/problem/HRBUST-2455 有两种优惠方式,一是满400减100,另外一种是商品自带折扣,二者不可叠加 dp[i][j]表示前i种商品,(参与满400 ...
- sqli-labs(36)
0X01发现又是‘’被过滤了 ?id=%df%%20and%=%23 错误 ?id=1%df%27%20and%201=1%23 正确 存在注入 0X01爆数据库 ?id=-%df%%20unio ...
- JavaScript 事件不触发
在class上绑定的事件,点击图片的时候无法触发 <div id="files" class="files"> <div> <p& ...
- maven之阿里云Maven镜像的使用
Maven中央仓库在国外,速度比较慢,所以我们采用国内的镜像,速度回有质的提升. 配置下setting.xml <mirrors> <mirror> <id>ali ...
- C:\WINDOWS\system32\drivers\etc\hosts文件的作用
在网络上访问网站,要首先通过DNS服务器把网络域名(www.XXXX.com)解析成XXX.XXX.XXX.XXX的IP地址后,我们的计算机才能访问.要是对于每个域名请求我们都要等待域名服务器解析后返 ...
- Visual Studio Code - 插件
Intellisense(代码提示.智能感应) Path Intellisense:路径别名(alias)代码提示 例如:在模块打包配置中配置@代替了src,可以使用下面的配置让@智能感应 " ...
- xshell6,xftp下载
https://www.netsarang.com/zh/free-for-home-school/
- Octavia 的实现与分析(OpenStack Rocky)
目录 文章目录 目录 Octavia 基本对象概念 基本使用流程 软件架构 服务进程清单 代码结构 loadbalancer 创建流程分析 network_tasks.AllocateVIP netw ...
- Python学习之==>内置函数、列表生成式、三元表达式
一.内置函数 所谓内置函数就是Python自带的函数 print(all([0,2,3,4])) #判断可迭代的对象里面的值是否都为真 print(any([0,1,2,3,4])) #判断可迭代的对 ...