PS: One should never harbor illusions at any time; one must have their own plans, maintain a beautiful mood, and be responsible for oneself and those who love you.
The previous two articles introduced the basic knowledge of Android componentization and the related knowledge of the Android componentization process Application. It is recommended to read the following two articles before reading this one:
The interface transitions between different modules involved in the Android componentization process are also very important. If you want to refactor the projects you handle into components, ARouter is a very easy-to-use routing framework maintained by a large development team, ensuring quality is not an issue.
ARouter is an open-source framework for Android App componentization developed by the Alibaba team. It supports routing, communication, and interception functions between modules, making it more adaptable to componentized development compared to native transitions. This article mainly summarizes the commonly used functions of Arouter through examples, as follows:
- ARouter Configuration
- In-app Navigation
- In-app Navigation with Parameters
- Activity Result Handling
- Navigation via Uri and Parameter Parsing
- Navigation Between Modules
- Service Invocation
- Display Effects
ARouter Configuration#
Configure the relevant dependencies for ARouter in the corresponding build.gradle file as follows:
android {
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
}
dependencies {
// Use api and compiler in matching versions; using the latest version ensures compatibility
compile 'com.alibaba:arouter-api:1.4.0'
annotationProcessor 'com.alibaba:arouter-compiler:1.2.1'
...
}
You can choose to configure the automatic loading of the routing table in the build.gradle file under the project, as follows:
// Routing table automatic loading plugin
apply plugin: 'com.alibaba.arouter'
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
//ARouter
classpath "com.alibaba:arouter-register:1.0.2"
}
}
Additionally, ARouter needs to be initialized in the Application as follows:
@Override
public void onCreate() {
super.onCreate();
// Must configure before initializing ARouter
if (BuildConfig.DEBUG){
// Enable logging
ARouter.openLog();
// Enable debug mode; if running in install run mode, debug mode must be enabled
ARouter.openDebug();
}
ARouter.init(this);
}
In-app Navigation#
Using ARouter for in-app navigation is very simple; just add the @Route annotation to the Activity you want to navigate to, as follows:
// The configured path must have at least two levels, such as /xx/xxx
@Route(path = FirstActivity.PATH)
public class FirstActivity extends AppCompatActivity {
public static final String PATH = "/test/firstActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
}
}
Then use the navigation method provided by ARouter to navigate within the app, as follows:
// In-app navigation
ARouter.getInstance()
.build(FirstActivity.PATH)
.navigation();
In-app Navigation with Parameters#
ARouter uses a series of methods starting with withString to set corresponding parameters for parameter passing, as follows:
// In-app navigation with parameters
ARouter.getInstance()
.build(SecondActivity.PATH)
.withString(SecondActivity.PARAM, "This is the parameter carried during navigation")
.navigation();
Then use Intent in the Activity you navigate to in order to retrieve the passed parameters, as follows:
@Route(path = SecondActivity.PATH)
public class SecondActivity extends AppCompatActivity {
public static final String PATH = "/test/secondActivity";
public static final String PARAM = "param";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Intent intent = getIntent();
if (intent!=null){
String param = intent.getStringExtra(PARAM);
Toast.makeText(this, param, Toast.LENGTH_SHORT).show();
}
}
}
Activity Result Handling#
Activity result handling is almost identical to native handling, that is, carry a requestCode during navigation, as follows:
// Activity result handling
ARouter.getInstance()
.build(ThreeActivity.PATH)
.navigation(this, 100);
Then, when returning from the Activity, use Intent to carry parameters with setResult, as follows:
@Route(path = ThreeActivity.PATH)
public class ThreeActivity extends AppCompatActivity {
public static final String PATH = "/test/threeActivity";
public static final String PARAM_RESULT = "param_result";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_three);
Intent intent = getIntent();
//setResult
intent.putExtra(PARAM_RESULT,"This is the parameter carried back");
setResult(RESULT_OK,intent);
}
}
Navigation via Uri and Parameter Parsing#
ARouter also supports navigation via Uri. First, create a non-UI Activity to listen for Scheme events, which will uniformly forward the Uri. All Uris should go through here for dispatching navigation, which can effectively control the Uri and improve the security of using Uri for navigation to some extent. Implement a non-UI Activity as follows:
public class SchemeFilterActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Uri uri = getIntent().getData();
// Uniformly handle external navigation Uris, implementing a unified dispatch by the router to reduce security risks caused by relying solely on Intent property matching
ARouter.getInstance().build(uri).navigation(this, new NavCallback() {
@Override
public void onArrival(Postcard postcard) {
finish();
}
});
}
}
Configure host, scheme, and Action in the AndroidManifest file as follows:
<activity android:name=".SchemeFilterActivity">
<intent-filter>
<data
android:host="test.manu.com"
android:scheme="arouter" />
<action android:name="com.manu.route" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Then, create an HTML file in the assets folder, and complete the Uri navigation by clicking the link. The HTML content is as follows:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title></title>
</head>
<body>
<h2>Navigation Test</h2>
<h2>Custom Scheme</h2>
<p>
<!--Without parameters-->
<a href="arouter://test.manu.com/test/fiveActivity">arouter://test111.manu.com/test/fiveActivity</a>
</p>
<p>
<!--With parameters-->
<a href="arouter://test.manu.com/test/sixActivity?name=alex&age=18&score=%7B%22score%22:%2290%22,%22rank%22:%222%22%7D">arouter://test111.manu.com/test/sixActivity?name=alex&age=18&score={"score":"90","rank":"2"}</a>
</p>
</body>
</html>
For specific effects, refer to the running effect image.
Then, use WebView to load this HTML, and you can navigate to the corresponding Activities, which are FiveActivity and SixActivity, as follows:
// FiveActivity
@Route(path = FiveActivity.PATH)
public class FiveActivity extends AppCompatActivity {
public static final String PATH = "/test/fiveActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_five);
}
}
// SixActivity
@Route(path = SixActivity.PATH)
public class SixActivity extends AppCompatActivity {
public static final String PATH = "/test/sixActivity";
@Autowired
public String name;
@Autowired
public int age;
@Autowired
// If you want to pass a custom object in the Uri, you need to use a JSON string (encoded URI) to pass it, creating a class that implements the SerializationService interface to complete the JSON parsing
public ScoreBean score;
@BindView(R.id.tvData)
TextView tvData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_six);
ButterKnife.bind(this);
// Automatic dependency injection for parameters
ARouter.getInstance().inject(this);
String info = "name=" + name + ",age=" + age + ",score=" + score;
tvData.setText(info);
Log.i("SixActivity", info);
}
}
Navigation Between Modules#
Navigation between the main module and sub-modules is also very easy. For example, when the main module navigates to a sub-module, both the main module and sub-module must configure ARouter to enable navigation. You can create an interface in the main module to manage the paths of the sub-modules you want to navigate to, as follows:
// Manage navigation paths
public interface Module {
String MODULE_ONE = "/module1/module-one";
String MODULE_TWO = "/module2/module-two";
}
Then, navigate directly, as follows:
// Navigate to Module-one
ARouter.getInstance()
.build(Module.MODULE_ONE)
.navigation();
Service Invocation#
Service invocation in ARouter should not be confused with Android's Service. The service invocation in ARouter is actually a wrapper for a certain business. Through the unified encapsulation of ARouter, it becomes more convenient to call; you only need to know the path and name to call it freely. Implement a Service by creating IProvider as follows:
@Route(path = "/service/singleService")
public class SingleService implements IProvider {
public static final String PATH = "/service/singleService";
private Context mContext;
// Specific service
public void showMessage() {
Toast.makeText(mContext, "This is the service provided externally", Toast.LENGTH_SHORT).show();
}
@Override
public void init(Context context) {
this.mContext = context;
Log.i("SingleService", "SingleService has init");
}
}
Then you can call it, as follows:
// Call through service class
ARouter.getInstance().navigation(SingleService.class).showMessage();
// Call through service class Path
((SingleService) ARouter.getInstance()
.build(SingleService.PATH)
.navigation())
.showMessage();
Additionally, you can also use dependency injection to complete service invocation, which is convenient for managing multiple services. Create a service management class as follows:
// Service management class
public class ServiceManage {
@Autowired
SingleService singleService;
public ServiceManage(){
// Obtain the service through dependency injection
ARouter.getInstance().inject(this);
}
public void getService(){
singleService.showMessage();
}
}
Then call the specific service through the service management class as follows:
// Service management, obtaining the service through dependency injection
ServiceManage manage = new ServiceManage();
manage.getService();
Display Effects#
The test effects of the implementations above are shown in the image below:
ARouter has comprehensive functionality and is very simple to use. The above content is also the most commonly used. For other features such as interceptors, downgrade strategies, transition animations, mapping relationship grouping, etc., you can directly refer to the official documentation for practice.