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 relevant 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 project you are handling into a componentized structure, ARouter is a very easy-to-use routing framework maintained by a large development team, and its quality is reliable.
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 {
// Match api and compiler 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 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 be configured 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 "with" such as 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 being passed")
.navigation();
Then, in the Activity being navigated to, use Intent 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, which involves carrying 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 the parameter 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 being returned");
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 forward the Uri uniformly. All Uris should go through this Activity for dispatching, which can effectively control the Uris and enhance the security of Uri navigation. 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 Uris for routing, reducing security risks from relying solely on Intent property matching
ARouter.getInstance().build(uri).navigation(this, new NavCallback() {
@Override
public void onArrival(Postcard postcard) {
finish();
}
});
}
}
In the AndroidManifest file, configure the host, scheme, and Action 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 to complete the Uri navigation through clickable links. 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>
<!-- No 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 images.
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 custom objects in the Uri, use a JSON string (encoded URI) for passing, and create a class that implements the SerializationService interface to complete 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, to navigate from the main module to a sub-module, both the main module and sub-module must be configured with ARouter to enable navigation. You can create an interface in the main module to manage the paths to the sub-modules, 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 Services. The service invocation in ARouter is actually a wrapper for a certain business, making it more convenient to call through the unified encapsulation of ARouter. You only need to know the path and name to call it. Implement IProvider to create a Service 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 been initialized");
}
}
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 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 mentioned above are shown in the following image:
ARouter has comprehensive functionality and is very simple to use. The above content covers the most commonly used features. For other functionalities such as interceptors, downgrade strategies, transition animations, and mapping relationship grouping, please refer to the official documentation for practical implementation.