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 example
scheme://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 ampersand
scheme://authority/path1/path2/path3? id = 1&name = mingming&old#fragment
There 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 example
scheme://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 ampersand
scheme://authority/path1/path2/path3?id=1&name =张三&old#fragment
There 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