After the previous article with you a route (1)- interface jump, this article describes how to implement a jump with parameters

In order to make this series of articles more simple, the code in the demo is very simple and straightforward. So there will be a lot of unreasonable judgment. Anyone with reasonable suggestions for the demo can point them out in the comments section.

With reference to jump

In normal cases, jumps between activities are as follows

Intent intent = new Intent(this, TestActivity1.class); Intent. PutExtra ("name", "intent "); startActivity(intent); // IntEnts maintain a Bundle object inside. The Bundle implements the Parcelable interface, which is a relatively efficient way to pass parameters.Copy the code

Since Android native already has efficient parameter passing, it’s natural to take advantage of it. Add an intentWrapper. class to encapsulate the intent parameter

public class IntentWrapper {

    private Bundle mBundle;
    private String originalUrl;
    private RouteDemo routeDemo;

    private volatile static IntentWrapper instance = null;

    public static IntentWrapper getInstance() {
        if (instance == null) {
            synchronized (IntentWrapper.class) {
                if (instance == null) {
                    instance = new IntentWrapper();
                }
            }
        }
        return instance;
    }

    public IntentWrapper build(RouteDemo routeDemo, String url) {
        this.routeDemo = routeDemo;
        this.originalUrl = url;
        mBundle = new Bundle();
        return this;
    }

    public IntentWrapper withString(String key, String value) {
        mBundle.putString(key, value);
        return this;
    }

    public IntentWrapper withInt(String key, int value) {
        mBundle.putInt(key, value);
        return this;
    }

    public void open() {
        routeDemo.open(originalUrl, mBundle);
    }

}
Copy the code

Declare a Bundle object and provide two simple methods withString and withInt.

Next, we need to modify RouteDemo

In the previous article, since route jumps carry no parameters, they are

RouteDemo.open("test");
Copy the code

That’s the simple form.

How to call after transformation

Routedemo.getinstance ().build("route://test").withString("name").withint ("age", 15).open(); routeDemo.getInstance ().build("route://test").withInt("age", 15).open();Copy the code

Get the IntentWrapper object mentioned earlier through the build function and pass the parameters through it. Finally, the jump logic in RouteDemo is called back through the open() function.

The complete RouteDemo. Class

public class RouteDemo { private static HashMap<String, Class> activityMap = new HashMap<>(); private static Application mApplication; private volatile static RouteDemo instance = null; public static RouteDemo getInstance() { if (instance == null) { synchronized (RouteDemo.class) { if (instance == null) {  instance = new RouteDemo(); } } } return instance; } public void init(Application application) { mApplication = application; Try {/ / call AutoCreateModuleActivityMap_app Class method through reflection, and to give activityMap assignment Class clazz = Class.forName("com.dly.routeDemo.AutoCreateModuleActivityMap_app"); Method method = clazz.getMethod("initActivityMap", HashMap.class); method.invoke(null, activityMap); for (String key : activityMap.keySet()) { System.out.println("activityMap = " + activityMap.get(key)); } } catch (Exception e) { e.printStackTrace(); } } public IntentWrapper build(String url) { return IntentWrapper.getInstance().build(this,url); } public void open(String url, Bundle bundle) { for (String key : activityMap.keySet()) { if(url.equals(key)){ Intent intent = new Intent(mApplication, activityMap.get(key)); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtras(bundle); mApplication.startActivity(intent); } } } public void open(String url) { for (String key : activityMap.keySet()) { if (url.equals(key)) { Intent intent = new Intent(mApplication, activityMap.get(key)); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mApplication.startActivity(intent); }}}}Copy the code

If you just show jumps like above, the route is meaningless. More often than not, we want the server to return a URL and the client to match the url.

For example, a banner page on the home page requested to redirect to testActivity1 yesterday, and then suddenly changed its requirement to redirect to testActivity2 today. This is where the dynamic configuration of routes comes in handy.

The more common invocation method is as follows

RouteDemo.getInstance().open("route://test? name=555");Copy the code

Before talking about URL jump, we must first explain the Android URL and URI, as well as their relationship and format, to pave the way for URI parsing later.

The relationship between URL,URN, and URI (skip this paragraph if you’re familiar with URIs)###

A URI is a unified resource Identifier (I) that uniquely identifies a resource. URL L(Location) is the unified resource locator, which provides the path to find the resource. URN Specifies the name of the unified resource. It identifies the resource by name.

In general, URLS and UrNs are subsets of URIs that together make up URIs.

Such as www.zhihu.com/question/21. , this string of addresses can uniquely identify a resource, so it is a URI, and it can also be used to find the resource, so it is also a URL.

Urn: ISBN :0-486-27557-4 This is the ISBN of a book, which uniquely identifies a book, but we can’t find the book by the isBN, so this is the URI, not the URL, but the ISBN is exactly a URN.

The structure of the URI

Several partitioning forms of URIs

The basic classification

[scheme:]scheme-specific-part[#fragment] 
Copy the code

Further division

[scheme:][//authority][path][?query][#fragment]
Copy the code

Divide it further

[scheme:][//host:port][path][?query][#fragment] 
Copy the code

There are some simple rules

  • There can be multiple paths, each with a/connection, for examplescheme://authority/path1/path2/path3? query#fragment
  • The query parameter may or may not have the corresponding value, if the corresponding value is represented by =, for example:scheme://authority/path1/path2/path3? id = 1#fragment, there is a parameter id, which has a value of 1
  • There can be multiple query arguments, each concatenated with an ampersandscheme://authority/path1/path2/path3? id = 1&name = mingming&old#fragmentThere are three parameters:

    Parameter 1: id, whose value is 1

    Parameter 2: name, whose value is mingming

    Parameter 3: old is not assigned, so its value is null
  • In Android, except scheme and authority, there are several paths, query and fragments, which can be selected or rejected in the same order. For example, “Path” is not allowed: Scheme ://authority? Scheme :// query#fragment “path” and “query” authority#fragment” Scheme ://authority/path “path”,”query”,”fragment” do not: Scheme ://authority

There are some simple rules

  • There can be multiple paths, each with a/connection, for examplescheme://authority/path1/path2/path3? query#fragment
  • The query parameter may or may not have the corresponding value, if the corresponding value is represented by =, for example:scheme://authority/path1/path2/path3? id = 1#fragment, there is a parameter id, which has a value of 1
  • There can be multiple query arguments, each concatenated with an ampersandscheme://authority/path1/path2/path3?id=1&name =张三&old#fragmentThere are three parameters:

    Parameter 1: id, whose value is 1

    Parameter 2: name, whose value is: 3: old, is not assigned, so its value is null
  • In Android, except scheme and authority, there are several paths, query and fragments, which can be selected or rejected in the same order. For example, “Path” is not allowed: Scheme ://authority? Scheme :// query#fragment “path” and “query” authority#fragment” Scheme ://authority/path “path”,”query”,”fragment” do not: Scheme ://authority

Do a simple example match

Zhang SAN & id = 4 # niknowzcd at http://www.java2s.com:8080/yourpath/fileName.htm?name=Copy the code
  • scheme:http
  • host:www.java2s.com
  • port:8080
  • path:/yourpath/fileName.htm
  • Query: name = zhang SAN & id = 4
  • fragment:niknowzcd

The commonly used API

Same example

Zhang SAN & id = 4 # niknowzcd at http://www.java2s.com:8080/yourpath/fileName.htm?name=Copy the code
  • getScheme() :Gets the Scheme string part of the Uri, in this casehttp
  • getSchemeSpecificPart():Get the scheme-specific-part: part of the Uri, where://www.java2s.com:8080/yourpath/fileName.htm?
  • GetFragment (): Gets the Fragment part of the Uri, niknowzcd
  • getAuthority():Gets the Authority part of the Uri, i.ewww.java2s.com:8080
  • getPath():Gets the path part of the Uri, i.e/yourpath/fileName.htm
  • getQuery():Gets the Query part of the Uri, i.eName = zhang SAN & id = 4
  • getHost():Gets the Host string in Authority, that iswww.java2s.com
  • getPost():Gets the Port string in Authority, that is8080

There are two other commonly used attributes :getPathSegments() and getQueryParameter(String key).

List getPathSegments() saves the entire path, delimited by a /

String mUriStr = "http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4#harvic"; Uri mUri = Uri.parse(mUriStr); List<String> pathSegList = mUri.getPathSegments(); for (String pathItem:pathSegList){ Log.d("debug",pathItem); } // print yourpath filename.htmCopy the code

GetQueryParameter (String Key): Obtains the corresponding Query value based on the key

String mUriStr = "HTTP: / / http://www.java2s.com:8080/yourpath/fileName.htm?name= zhang SAN & id = 4 # niknowzcd"; mUri = Uri.parse(mUriStr); Log.d(debug,"getQueryParameter(\"name\"):"+mUri.getQueryParameter("name")); Log.d(debug,"getQueryParameter(\"id\"):"+mUri.getQueryParameter("id")); GetQueryParameter ("name"): getQueryParameter("id"):Copy the code

In path, even if it is allowed not to assign a value to a KEY, null is obtained when getQueryParameter() is used to obtain the value of that KEY.

Matching URI redirect

Let’s go back and look at the matching of the paths we wrote earlier

public void open(String url) { for (String key : activityMap.keySet()) { if(url.equals(key)){ Intent intent = new Intent(mApplication, activityMap.get(key)); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mApplication.startActivity(intent); }}}Copy the code

Using the string Url full match form, this way is very limited, take

route://test? name=555Copy the code

For this string, I want to jump to the Activity of test and take the parameter name=555.

With full URL matching, we might need to add a similar annotation to the target Activity

@Route("route://test? name=555")Copy the code

This jump is possible, but how to carry parameters becomes a problem.

Then go back to the structure division of URI, take one of the more widely applicable as follows

[scheme:][//host:port][path][?query][#fragment] 
Copy the code

Among them

[scheme:][//host:port][path]
Copy the code

This section is sufficient to represent a unique interface resource; the following parameters only distinguish which data the current interface needs to display.

Like a UserInfoActivity and whatever userId you pass in, the view you’re in is a UserInfoActivity.

Therefore, when matching an external URL, it is the URL path part that needs to be matched, i.e

[scheme:][//host:port][path]
Copy the code

This part of

Along the way, to rewrite the code in RouteDemo.

Add a checkUrlPath function

Private static Boolean checkUrlPath(String targetUrl, String matchUrl) { Uri targetUri = Uri.parse(targetUrl); Uri matchUri = Uri.parse(matchUrl); Assert.assertNotNull(targetUri.getScheme()); Assert.assertNotNull(targetUri.getHost()); if (targetUri.getScheme().equals(matchUri.getScheme()) && targetUri.getHost().equals(matchUri.getHost())) { return TextUtils.equals(targetUri.getPath(), matchUri.getPath()); } else { return false; }}Copy the code

Here we use a simple and rude approach: when scheme,host, and path are all equal, we consider it a match. Port is not mentioned here because it is not normally used in routing, so you can get it from getAuthority() if you want.

Once the path is matched, one more step is to pass in the parameters we need. Use getQueryParameterNames() and getQueryParameter(queryParameterName)

The concrete implementation is as follows

private Intent parseParams(Intent intent, String targetUrl) {
    Uri uri = Uri.parse(targetUrl);
    Set<String> queryParameterNames = uri.getQueryParameterNames();
    for (String queryParameterName : queryParameterNames) {
        intent.putExtra(queryParameterName, uri.getQueryParameter(queryParameterName));
    }
    return intent;
}
Copy the code

Finally, post the modified RouteDemo function

public class RouteDemo { private static HashMap<String, Class> activityMap = new HashMap<>(); private static Application mApplication; private volatile static RouteDemo instance = null; public static RouteDemo getInstance() { if (instance == null) { synchronized (RouteDemo.class) { if (instance == null) {  instance = new RouteDemo(); } } } return instance; } public void init(Application application) { mApplication = application; Try {/ / call AutoCreateModuleActivityMap_app Class method through reflection, and to give activityMap assignment Class clazz = Class.forName("com.dly.routeDemo.AutoCreateModuleActivityMap_app"); Method method = clazz.getMethod("initActivityMap", HashMap.class); method.invoke(null, activityMap); for (String key : activityMap.keySet()) { System.out.println("activityMap = " + activityMap.get(key)); } } catch (Exception e) { e.printStackTrace(); } } public IntentWrapper build(String url) { return IntentWrapper.getInstance().build(this,url); } public void open(String url, Bundle bundle) { for (String key : activityMap.keySet()) { if (checkUrlPath(url, key)) { Intent intent = new Intent(mApplication, activityMap.get(key)); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtras(bundle); mApplication.startActivity(intent); } } } public void open(String url) { for (String key : activityMap.keySet()) { if (checkUrlPath(url, key)) { Intent intent = new Intent(mApplication, activityMap.get(key)); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent = parseParams(intent, url); mApplication.startActivity(intent); } } } private Intent parseParams(Intent intent, String targetUrl) { Uri uri = Uri.parse(targetUrl); Set<String> queryParameterNames = uri.getQueryParameterNames(); for (String queryParameterName : queryParameterNames) { intent.putExtra(queryParameterName, uri.getQueryParameter(queryParameterName)); } return intent; } scheme and authority are mandatory. Private static Boolean checkUrlPath(String targetUrl, String matchUrl) { Uri targetUri = Uri.parse(targetUrl); Uri matchUri = Uri.parse(matchUrl); Assert.assertNotNull(targetUri.getScheme()); Assert.assertNotNull(targetUri.getHost()); if (targetUri.getScheme().equals(matchUri.getScheme()) && targetUri.getHost().equals(matchUri.getHost())) { return TextUtils.equals(targetUri.getPath(), matchUri.getPath()); } else { return false; }}}Copy the code

Making the address

RouteDemo