From b7e5fb7193df2bac46d7dae95295fe7dfa75cf5f Mon Sep 17 00:00:00 2001 From: haoge <470368500@qq.com> Date: Thu, 10 May 2018 10:38:55 +0800 Subject: [PATCH] add setExecutor to ActionRoute --- README.md | 421 +++++++++++++++++- .../java/com/lzh/nonview/router/Router.java | 7 + .../router/launcher/ActionLauncher.java | 7 +- .../lzh/nonview/router/route/ActionRoute.java | 8 + .../nonview/router/route/IActionRoute.java | 7 + .../lzh/nonview/router/tools/Constants.java | 1 + sample/build.gradle | 2 +- .../java/com/lzh/nonview/router/demo/App.kt | 3 + .../lzh/nonview/router/demo/MainActivity.kt | 31 +- .../router/demo/action/ExecutorAction.kt | 20 + .../{SimpleAction.kt => SayHelloAction.kt} | 11 +- .../router/demo/executor/TestExecutor.kt | 21 + .../nonview/router/demo/tools/EasyToast.kt | 79 ++++ .../nonview/router/demo/tools/SingleCache.kt | 28 ++ sample/src/main/res/layout/activity_main.xml | 20 +- 15 files changed, 629 insertions(+), 37 deletions(-) create mode 100644 sample/src/main/java/com/lzh/nonview/router/demo/action/ExecutorAction.kt rename sample/src/main/java/com/lzh/nonview/router/demo/action/{SimpleAction.kt => SayHelloAction.kt} (56%) create mode 100644 sample/src/main/java/com/lzh/nonview/router/demo/executor/TestExecutor.kt create mode 100644 sample/src/main/java/com/lzh/nonview/router/demo/tools/EasyToast.kt create mode 100644 sample/src/main/java/com/lzh/nonview/router/demo/tools/SingleCache.kt diff --git a/README.md b/README.md index 8cbaca3..98c887d 100644 --- a/README.md +++ b/README.md @@ -7,26 +7,18 @@ ### 我希望的router框架所能支持的功能 - -- 可自动解析标准url参数。 -- 可传递bundle所支持的所有数据类型,能与原生做到无缝对接。 -- 支持拦截器.方便对于部分页面跳转时需要检查是否登录.并跳转登录界面做统一配置 -- 支持当路由被拦截后。操作之后恢复路由事件。如拦截后进行登录。登录后自动恢复之前被拦截的路由。 -- 如果使用http/https地址时.可以直接跳转至使用浏览器 -- 能支持原生跳转的各种方式,如请求码.转场动画的设置. -- 能灵活配置route规则.方便对各种开发环境灵活做兼容适配.如插件化.组件化 -- 启动动作路由时。支持切换运行线程。 - - -### 效果图 - -![route](./pics/route.gif) +- **自动化** 可自动解析标准url参数 +- **安全**: 路由启动过程中。全程catch住异常并通知用户。完全不用担心crash问题。 +- **强大的拦截器**:与大部分的路由不同。提供三种路由拦截器机制,对应不同业务下使用。 +- **方便**: 使用apt注解生成路由表,配置方便,易维护。 +- **灵活**: 配置路由表方式多样,满足你在任意条件下进行使用。 +- **支持两种路由**:页面路由与动作路由。 +- **支持重启路由**:路由被拦截后。可通过一行代码无缝恢复重启路由。在登录检查中会很有用。 +- **高度可定制**:单品、组件化完美支持,对于插件化环境。也可以针对性的定制使用。 ### 版本依赖 -- 添加gradle依赖: - -添加JitPack仓库到root project下的build.gradle中: +1. 添加JitPack仓库 ``` allprojects { @@ -37,7 +29,7 @@ allprojects { } ``` -- 基本配置: +2. 添加依赖 LatestVersion=[![](https://jitpack.io/v/yjfnypeu/Router.svg)](https://jitpack.io/#yjfnypeu/Router) @@ -46,9 +38,398 @@ compile "com.github.yjfnypeu.Router:router-api:$LatestVersion" annotationProcessor "com.github.yjfnypeu.Router:router-compiler:$LatestVersion" ``` -**针对插件化环境。需要有不同的配置方式。请参考:[插件化配置说明](https://github.com/JumeiRdGroup/Router/wiki/%E6%8F%92%E4%BB%B6%E5%8C%96%E9%85%8D%E7%BD%AE)** +## 用法 + +### 为Activity添加路由规则 + +- 指定路由前缀与路由表生成包名 + +``` +@RouteConfig( + baseUrl = "haoge://page/", // 路由前缀:用于结合RouterRule合成完整的路由链接 + pack = "com.haoge.studio") // 路由表生成包名:配置后。路由表生成类将会放置于此包下 +class App extends Application {...} +``` + +- 为目标页指定路由规则链接 + +``` +// 在目标Activity上添加RouterRule注解,添加对应的路由规则 +// 同一目标页可以添加多个不同的路由链接。 +@RouterRule({ + // 可只指定path, 此种数据会与RouteConfig中的baseUrl进行结合: + // 最终完整链接为:haoge://page/example + "example", + // 也可直接指定完整链接 + "total://example" + }) +class ExampleActivity extends BaseActivity { ... } +``` + +### 注册路由表 + +经过上面的配置后,编译后即可生成对应的路由表类,生成的路由表类名统一为**RouterRuleCreator**: + +然后即可通过以下代码进行路由表注册使用: + +```java +RouterConfiguration.get().addRouteCreator(new RouterRuleCreator()) +``` + +### 启动路由 + +还是以上面的example为例。要使用Router启动ExampleActivity, 使用以下链接进行跳转 + +```java +Router.create("haoge://page/example").open(context) +``` + +### 启动浏览器打开网页 + +当路由链接为http/https时,且此时本地的也没有页面配置过此链接地址时,将触发使用跳转浏览器打开 + +比如浏览器打开百度页面 + +``` +Router.create("https://www.baidu.com").open(context) +``` + +### 启用内部日志打印 + +```java +Router.DEBUG = true +``` + +### 添加额外数据启动 + +```java +Bundle extra = getExtras(); +Router.create(url) + .addFlags(flag) // 添加启动标记位,与Intent.addFlags(flag)相同 + .addExtras(extra) // 添加额外数据:Intent.addExtras(bundle) + .requestCode(code) // 使用startActivityForResult进行启动 + .setAnim(in, out) // 设置转场动画。Activity.overridePendingTransition(inAnim, outAnim) + .open(context) +``` + +### 使用路由回调 + +路由回调为**RouteCallback**接口,用于在进行路由启动后,对该次路由事件的状态做回调通知: + +```java +public interface RouteCallback { + // 当用于启动的路由链接未匹配到对应的目标页时。回调到此 + void notFound(Uri uri, NotFoundException e); + // 当启动路由成功后,回调到此。可在此通过rule.getRuleClz()获取对应的目标页类名。 + void onOpenSuccess(Uri uri, RouteRule rule); + // 当启动路由失败后,回调到此。 + void onOpenFailed(Uri uri, Throwable e); +} +``` + +路由回调的配置分为两种: + +1. 全局路由回调:所有的路由启动事件均会回调到此 + +```java +RouterConfiguration.get().setCallback(callback) +``` + +2. 临时路由回调:只对当次路由事件生效 + +```java +Router.create(url).setCallback(callback).open(context) +``` + +路由回调机制在进行界面路由跳转埋点时,是个很好的特性。 + +有时候我们会需要在回调中使用启动时添加的额外数据,而回调的api中并没有提供此数据,所以此时我们需要使用以下方法进行额外数据获取: + +```java +此方法只能在回调方法内调用,运行完回调方法后会自动清空。 +RouteBundleExtras extras = RouterConfiguration.get().restoreExtras(uri); +``` + +### 使用ActivityResultCallback + +**ActivityResultCallback**接口用于自动处理onActivityResult逻辑,可有效避免在onActivityResult中写一堆的判断switch逻辑。是个很棒的特性。 + +```java +public interface ActivityResultCallback { + void onResult(int resultCode, Intent data); +} +``` + +使用此特性前,需要在BaseActivity中的onActivityResult方法处,添加上派发方法: + +```java +RouterConfiguration.get() + .dispatchActivityResult(this, requestCode, resultCode, data) +``` + +然后即可直接使用 + +```java +// 添加了resultCallback属性后,即可不指定requestCode了。免去了取值的烦恼 +Router.create(url).resultCallback(resultCallback).open(context) +``` + +### 使用路由拦截器拦截器 + +拦截器,顾名思义,就是在路由启动过程中,进行中间状态判断,是否需要拦截掉此次路由事件。使其失败。 + +拦截器的接口名为**RouteInterceptor** + +```java +public interface RouteInterceptor{ + // 在此进行状态判断。判断是否需要拦截此次路由事件 + boolean intercept (Uri uri, RouteBundleExtras extras, Context context); + // 当intercept方法返回true时,此方法被调用。 + void onIntercepted(Uri uri, RouteBundleExtras extras, Context context); +} +``` + +Router经过长期的迭代,对拦截器进行了详细的分类,提供了三种拦截器提供使用: + +**1. 全局拦截器**:对所有的路由事件生效。 + +``` +RouterConfiguration.get().setInterceptor(interceptor); +``` + +**2. 单次拦截器**:对当次路由事件生效。 + +```java +Router.create(url) + // 是的你没有看错,可以配置多个不同的拦截器实例 + .addInterceptor(interceptor1) + .addInterceptor(interceptor2) + .open(context); +``` + +**3. 指定目标的拦截器**:对指定的目标页面生效 + +```java +// 在配置的RouterRule的目标页,添加此RouteInterceptors注解即可。 +// 在此配置的拦截器,当使用路由启动此页面时,即可被触发。 +@RouteInterceptors({CustomRouteInterceptor.class}) +@RouterRule("user") +public class UserActivity extends BaseActivity {...} +``` + +### 恢复路由的方式 + +既然路由可以被拦截,那么也可以直接被恢复。 + +```java +Router.resume(uri, extras).open(context); +``` + +光这样看有点不太直观。我们举个最经典的**登录检查拦截**案例作为说明: + +![](https://user-gold-cdn.xitu.io/2018/2/1/16150ba1206c981a?w=1130&h=274&f=png&s=47475) + +当不使用路由进行跳转时,这种情况就会导致你本地写上了大量的登录判断逻辑代码。这在维护起来是很费劲的。而且也非常不灵活,而使用拦截器的方式来做登录检查,就会很方便了: + +![](https://user-gold-cdn.xitu.io/2018/2/1/16150c2dc3758e35?w=902&h=654&f=png&s=86527) + +下面是一个简单的登录拦截实现: + +```java +// 实现RouteInterceptor接口 +public class LoginInterceptor implements RouteInterceptor{ + @Override + public boolean intercept(Uri uri, RouteBundleExtras extras, Context context){ + // 未登录时进行拦截 + return !LoginChecker.isLogin(); + } + + @Override + public void onIntercepted(Uri uri, RouteBundleExtras extras, Context context) { + // 拦截后跳转登录页并路由信息传递过去,便于登录后进行恢复 + Intent loginIntent = new Intent(context,LoginActivity.class); + // uri为路由链接 + loginIntent.putExtra("uri",uri); + // extras中装载了所有的额外配置数据 + loginIntent.putExtra("extras",extras); + context.startActivity(loginIntent); + } +} +``` + +```java +public class LoginActivity extends BaseActivity { + + @Arg + Uri uri; + @Arg + RouteBundleExtras extras; + + void onLoginSuccess() { + if(uri != null) { + // 登录成功。使用此方法直接无缝恢复路由启动 + Router.resume(uri, extras).open(context); + } + finish(); + } +} +``` + +### 自动解析传递url参数 + +Router支持自动从url中解析参数进行传递: + +```java +Router.create("haoge://page/user?username=haoge&uid=123456") + .open(context); +``` + +上面的链接即代表:跳转到**haoge://page/user**页面,并传递username和uid数据过去。 + +### 结合Parceler框架使用 + +[Parceler框架](https://github.com/JumeiRdGroup/Parceler)是我另一款超轻量型的Bundle数据处理框架,具备良好的兼容性。 + +将Router与Parceler结合进行使用。可做到 **自动匹配目标页的数据类型进行传递**的效果。 + +以上方的带参数链接为例:解析后传递到目标页的数据全部是String类型的 + +| key | value | type | +|--- |--- |--- | +| username | haoge |String | +| uid | 123456 |String | + +这样在数据传递的时候就比较麻烦,因为你如果要传递其他类型的数据,还得需要到目标页自己去手动转换一下。 + +#### 使用Arg注解 + +解决方法就是使用Arg注解, 比如如下页面: + +```kotlin +@RouterRule("parceler-args") +class ArgsActivity:BaseActivity() { + + // 为对应参数的成员变量添加Arg注解 + // 基本数据类型 + @Arg + var mBoolean:Boolean? = null + @Arg + var mInt:Int? = null + @Arg + var mByte:Byte? = null + @Arg + var mShort:Short? = null + @Arg + var mChar:Char? = null + @Arg + var mFloat:Float? = null + @Arg + var mLong:Long? = null + @Arg + var mDouble:Double? = null + // 默认类型String + @Arg + var mString:String? = null + // 普通实体bean + @Arg + var mUser: User? = null + // 子链接 + @Arg + var mUrl:String? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // 从intent中读取数据,注入到Arg注解的成员变量中去。 + Parceler.toEntity(this, intent) + } +} +``` + +然后此时使用Router往此页面跳转,传值。将会自动进行转换,比如我们使用如下方式进行传递: + +```kotlin +val url = Uri.parse("haoge://page/parceler-args") + .buildUpon() + // 添加基本数据类型 + .appendQueryParameter("mBoolean", "true") + .appendQueryParameter("mByte", "0") + .appendQueryParameter("mShort", "1") + .appendQueryParameter("mChar", "c") + .appendQueryParameter("mInt", "3") + .appendQueryParameter("mFloat", "3.14") + .appendQueryParameter("mDouble", "3.14") + .appendQueryParameter("mLong", "5") + .appendQueryParameter("mString", "HaogeStudio") + // 非可序列化对象可通过json格式传递 + .appendQueryParameter("mUser", JSON.toJSONString(User("HaogeStudio"))) + // 转义字符串。比如参数中需要传递网址时 + // appendQueryParameter本身会将数据先进行转义后再拼接上。所以此处是转义的链接 + .appendQueryParameter("mUrl", "https://www.baidu.com") + .build() + +Router.create(url).open(this) +``` + +这样就很简单的达到了**自动匹配目标页的数据类型进行传递**目的。 + +### 使用动作路由 + +上面主要介绍的页面跳转的路由,也叫页面路由,但实际上。有的时候我们使用路由启动的,并不是需要启动某个页面。而是需要执行一些特殊的操作:比如**添加购物车**、**强制登出**等。此时就需要使用动作路由了。 + +#### 创建动作路由 + +动作路由通过继承**ActionSupport**类进行创建: + +```java +// 与页面路由一样。添加RouterRule注解配置路由链接即可。 +@RouterRule("action/hello") +public class SayHelloAction extends ActionSupport { + @Override + public void onRouteTrigger(Context context, Bundle data) { + // 启动动作路由成功会触发调用此方法。 + Toast.makeText(context, "Hello! this is an action route!", Toast.LENGTH_SHORT).show(); + } +} +``` + +动作路由的启动方式与页面路由一致: + +```java +Router.create("haoge://page/action/hello").open(context) +``` + +#### 指定动作路由的执行线程 + +动作路由是用于执行一些特殊的操作的路由,而有时候部分操作是需要在指定线程进行处理的: + +动作路由提供两种指定线程的操作: + +1. 启动前进行配置(优先级高): + +```java +Router.create(url).setExecutor(executor).open(context); +``` + +2. 在定制动作路由时,直接指定线程: + +```java +@RouteExecutor(CustomExecutor.class) +@RouterRule("action/hello") +public class SayHelloAction extends ActionSupport {...} +``` + +**在没有配置过线程切换器时。默认使用MainThreadExecutor。指定线程为主线程** + +### 在目标页获取启动链接 + +```java +// 先从目标页读取bundle数据 +Bundle bundle = getBundle(); +// 然后从bundle中读取即可 +Uri lauchUri = bundle.getParcelable(Router.RAW_URI); +``` -### 用法 +## 更多介绍 基本使用方式说明,请参考[Router:一款单品、组件化、插件化全支持的路由框架](https://juejin.im/post/5a37771f6fb9a0450e7636e0) diff --git a/routerlib/src/main/java/com/lzh/nonview/router/Router.java b/routerlib/src/main/java/com/lzh/nonview/router/Router.java index 94064f9..c1180d9 100644 --- a/routerlib/src/main/java/com/lzh/nonview/router/Router.java +++ b/routerlib/src/main/java/com/lzh/nonview/router/Router.java @@ -39,6 +39,8 @@ import com.lzh.nonview.router.tools.Constants; import com.lzh.nonview.router.tools.Utils; +import java.util.concurrent.Executor; + /** * Entry of Router。 @@ -123,6 +125,11 @@ public Router addExtras(Bundle extras) { return this; } + public Router setExecutor(Executor executor) { + this.internalCallback.getExtras().putValue(Constants.KEY_ACTION_EXECUTOR, executor); + return this; + } + /** * Restore a Routing event from last uri and extras. * @param uri last uri diff --git a/routerlib/src/main/java/com/lzh/nonview/router/launcher/ActionLauncher.java b/routerlib/src/main/java/com/lzh/nonview/router/launcher/ActionLauncher.java index c044505..97681ee 100644 --- a/routerlib/src/main/java/com/lzh/nonview/router/launcher/ActionLauncher.java +++ b/routerlib/src/main/java/com/lzh/nonview/router/launcher/ActionLauncher.java @@ -17,6 +17,7 @@ import com.lzh.nonview.router.module.ActionRouteRule; import com.lzh.nonview.router.tools.Cache; +import com.lzh.nonview.router.tools.Constants; import java.util.concurrent.Executor; @@ -33,6 +34,10 @@ public abstract class ActionLauncher extends Launcher { * @return returns a executor instance to switching thread. */ protected Executor getExecutor() { - return Cache.findOrCreateExecutor(rule.getExecutor()); + Executor executor = extras.getValue(Constants.KEY_ACTION_EXECUTOR); + if (executor == null) { + executor = Cache.findOrCreateExecutor(rule.getExecutor()); + } + return executor; } } diff --git a/routerlib/src/main/java/com/lzh/nonview/router/route/ActionRoute.java b/routerlib/src/main/java/com/lzh/nonview/router/route/ActionRoute.java index 92a3ab3..d2bd982 100644 --- a/routerlib/src/main/java/com/lzh/nonview/router/route/ActionRoute.java +++ b/routerlib/src/main/java/com/lzh/nonview/router/route/ActionRoute.java @@ -19,6 +19,9 @@ import com.lzh.nonview.router.launcher.ActionLauncher; import com.lzh.nonview.router.launcher.Launcher; import com.lzh.nonview.router.module.ActionRouteRule; +import com.lzh.nonview.router.tools.Constants; + +import java.util.concurrent.Executor; public class ActionRoute extends BaseRoute implements IActionRoute { @@ -31,4 +34,9 @@ protected Launcher obtainLauncher() throws Exception{ } return launcher.newInstance(); } + + @Override + public void setExecutor(Executor executor) { + callback.getExtras().putValue(Constants.KEY_ACTION_EXECUTOR, executor); + } } diff --git a/routerlib/src/main/java/com/lzh/nonview/router/route/IActionRoute.java b/routerlib/src/main/java/com/lzh/nonview/router/route/IActionRoute.java index 106076e..11893b9 100644 --- a/routerlib/src/main/java/com/lzh/nonview/router/route/IActionRoute.java +++ b/routerlib/src/main/java/com/lzh/nonview/router/route/IActionRoute.java @@ -15,6 +15,8 @@ */ package com.lzh.nonview.router.route; +import java.util.concurrent.Executor; + /** *

* Base on the {@link IBaseRoute} @@ -22,10 +24,15 @@ */ public interface IActionRoute extends IBaseRoute{ + void setExecutor(Executor executor); + class EmptyActionRoute extends EmptyBaseRoute implements IActionRoute { public EmptyActionRoute(InternalCallback internal) { super(internal); } + + @Override + public void setExecutor(Executor executor) { } } } diff --git a/routerlib/src/main/java/com/lzh/nonview/router/tools/Constants.java b/routerlib/src/main/java/com/lzh/nonview/router/tools/Constants.java index ef94342..1faec05 100644 --- a/routerlib/src/main/java/com/lzh/nonview/router/tools/Constants.java +++ b/routerlib/src/main/java/com/lzh/nonview/router/tools/Constants.java @@ -3,4 +3,5 @@ public interface Constants { String KEY_RESUME_CONTEXT = "ROUTER-KEY:RESUME_CONTEXT"; String KEY_RESULT_CALLBACK = "ROUTER-KEY:RESULT_CALLBACK"; + String KEY_ACTION_EXECUTOR = "ROUTER-KEY:ACTION_EXECUTOR"; } diff --git a/sample/build.gradle b/sample/build.gradle index 4db1967..be2e923 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -28,7 +28,7 @@ android { } def parceler_version="1.3.9" -def router_version="2.6.1" +def router_version="2.7.0" def butterknife_version='8.8.1' dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') diff --git a/sample/src/main/java/com/lzh/nonview/router/demo/App.kt b/sample/src/main/java/com/lzh/nonview/router/demo/App.kt index 73f9d31..dba4509 100644 --- a/sample/src/main/java/com/lzh/nonview/router/demo/App.kt +++ b/sample/src/main/java/com/lzh/nonview/router/demo/App.kt @@ -9,6 +9,7 @@ import com.lzh.nonview.router.Router import com.lzh.nonview.router.RouterConfiguration import com.lzh.nonview.router.anno.RouteConfig import com.lzh.nonview.router.demo.interceptors.DefaultInterceptor +import com.lzh.nonview.router.demo.tools.SingleCache @RouteConfig(baseUrl = "haoge://page/", pack = "com.haoge.studio") class App : Application() { @@ -25,5 +26,7 @@ class App : Application() { // 配置Parceler转换器 Parceler.setDefaultConverter(FastJsonConverter::class.java) + + SingleCache.init(this) } } diff --git a/sample/src/main/java/com/lzh/nonview/router/demo/MainActivity.kt b/sample/src/main/java/com/lzh/nonview/router/demo/MainActivity.kt index 51cb859..4ea6041 100644 --- a/sample/src/main/java/com/lzh/nonview/router/demo/MainActivity.kt +++ b/sample/src/main/java/com/lzh/nonview/router/demo/MainActivity.kt @@ -15,9 +15,18 @@ import com.lzh.nonview.router.exception.NotFoundException import com.lzh.nonview.router.launcher.Launcher import com.lzh.nonview.router.module.RouteRule import com.lzh.nonview.router.route.RouteCallback +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors @RouterRule("main") class MainActivity : BaseActivity() { + + val pool: ExecutorService = Executors.newSingleThreadExecutor { runnable -> + val thread:Thread = Thread(runnable) + thread.name = "action_executor" + return@newSingleThreadExecutor thread + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) @@ -82,11 +91,6 @@ class MainActivity : BaseActivity() { } - @OnClick(R.id.launchActionRoute) - fun launchActionRoute() { - Router.create("haoge://page/simple-action").open(this) - } - @OnClick(R.id.toResultActivity) fun toResultActivity() { Router.create("haoge://page/result") @@ -118,4 +122,21 @@ class MainActivity : BaseActivity() { Router.create(url).open(this) } + + @OnClick(R.id.launchActionRoute) + fun launchActionRoute() { + Router.create("haoge://page/say/hello").open(this) + } + + @OnClick(R.id.launchActionRouteWithExecutorAnnotation) + fun launchActionRouteWithExecutorAnnotation() { + Router.create("haoge://page/executor/switcher").open(this) + } + + @OnClick(R.id.launchActionRouteWithExecutorConfig) + fun launchActionRouteWithExecutorConfig() { + Router.create("haoge://page/executor/switcher") + .setExecutor(pool) + .open(this) + } } diff --git a/sample/src/main/java/com/lzh/nonview/router/demo/action/ExecutorAction.kt b/sample/src/main/java/com/lzh/nonview/router/demo/action/ExecutorAction.kt new file mode 100644 index 0000000..33a2672 --- /dev/null +++ b/sample/src/main/java/com/lzh/nonview/router/demo/action/ExecutorAction.kt @@ -0,0 +1,20 @@ +package com.lzh.nonview.router.demo.action + +import android.content.Context +import android.os.Bundle +import com.lzh.nonview.router.anno.RouteExecutor +import com.lzh.nonview.router.anno.RouterRule +import com.lzh.nonview.router.demo.executor.TestExecutor +import com.lzh.nonview.router.demo.tools.SingleCache +import com.lzh.nonview.router.route.ActionSupport + +/** + * @author haoge on 2018/5/10 + */ +@RouteExecutor(TestExecutor::class) +@RouterRule("executor/switcher") +class ExecutorAction : ActionSupport(){ + override fun onRouteTrigger(context: Context?, bundle: Bundle?) { + SingleCache.toast?.show("线程切换器测试动作路由被启动,启动线程为:${Thread.currentThread().name}" ) + } +} \ No newline at end of file diff --git a/sample/src/main/java/com/lzh/nonview/router/demo/action/SimpleAction.kt b/sample/src/main/java/com/lzh/nonview/router/demo/action/SayHelloAction.kt similarity index 56% rename from sample/src/main/java/com/lzh/nonview/router/demo/action/SimpleAction.kt rename to sample/src/main/java/com/lzh/nonview/router/demo/action/SayHelloAction.kt index b3401bd..1c1cfa8 100644 --- a/sample/src/main/java/com/lzh/nonview/router/demo/action/SimpleAction.kt +++ b/sample/src/main/java/com/lzh/nonview/router/demo/action/SayHelloAction.kt @@ -2,17 +2,16 @@ package com.lzh.nonview.router.demo.action import android.content.Context import android.os.Bundle -import android.widget.Toast import com.lzh.nonview.router.anno.RouterRule +import com.lzh.nonview.router.demo.tools.SingleCache import com.lzh.nonview.router.route.ActionSupport /** - * DATE: 2018/5/8 - * AUTHOR: haoge + * @author haoge on 2018/5/10 */ -@RouterRule("simple-action") -class SimpleAction : ActionSupport(){ +@RouterRule("say/hello") +class SayHelloAction:ActionSupport() { override fun onRouteTrigger(context: Context?, bundle: Bundle?) { - Toast.makeText(context, "simple-action被触发", Toast.LENGTH_SHORT).show() + SingleCache.toast?.show("Hello! this is an action route!") } } \ No newline at end of file diff --git a/sample/src/main/java/com/lzh/nonview/router/demo/executor/TestExecutor.kt b/sample/src/main/java/com/lzh/nonview/router/demo/executor/TestExecutor.kt new file mode 100644 index 0000000..f5dcc1f --- /dev/null +++ b/sample/src/main/java/com/lzh/nonview/router/demo/executor/TestExecutor.kt @@ -0,0 +1,21 @@ +package com.lzh.nonview.router.demo.executor + +import java.util.concurrent.Executor +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors + +/** + * @author haoge on 2018/5/10 + */ +class TestExecutor : Executor{ + + val pool:ExecutorService = Executors.newSingleThreadExecutor { runnable -> + val thread:Thread = Thread(runnable) + thread.name = "action_annotation_executor" + return@newSingleThreadExecutor thread + } + + override fun execute(command: Runnable?) { + pool.execute(command) + } +} \ No newline at end of file diff --git a/sample/src/main/java/com/lzh/nonview/router/demo/tools/EasyToast.kt b/sample/src/main/java/com/lzh/nonview/router/demo/tools/EasyToast.kt new file mode 100644 index 0000000..f74a340 --- /dev/null +++ b/sample/src/main/java/com/lzh/nonview/router/demo/tools/EasyToast.kt @@ -0,0 +1,79 @@ +package com.lzh.nonview.router.demo.tools + +import android.annotation.SuppressLint +import android.os.Looper +import android.text.TextUtils +import android.view.LayoutInflater +import android.widget.TextView +import android.widget.Toast + +/** + * 一个简单易用的Toast封装类。用于提供易用的、多样式的Toast组件进行使用 + * + * DATE: 2018/5/9 + * + * AUTHOR: haoge + */ +class EasyToast private constructor(private val toast: Toast, private val tv: TextView?, private val isDefault: Boolean) { + + fun show(resId:Int) { + show(SingleCache.context!!.getString(resId)) + } + + fun show(message:String) { + if (TextUtils.isEmpty(message)) { + return + } + + if (Looper.myLooper() == Looper.getMainLooper()) { + showInternal(message) + } else { + SingleCache.mainHandler.post { showInternal(message) } + } + } + + private fun showInternal(message: String) { + if (isDefault) { + toast.setText(message) + toast.show() + } else { + tv?.text = message + toast.show() + } + } + + companion object { + /** + * 默认提供的Toast实例,在首次使用时进行加载。 + */ + @JvmStatic + val DEFAULT: EasyToast by lazy { default() } + + @JvmStatic + private fun default(): EasyToast { + checkThread() + @SuppressLint("ShowToast") + val toast = Toast.makeText(SingleCache.context, "", Toast.LENGTH_SHORT) + return EasyToast(toast, null, true) + } + + @JvmStatic + fun create(layoutId: Int, tvId: Int, duration: Int): EasyToast { + checkThread() + val container = LayoutInflater.from(SingleCache.context).inflate(layoutId, null) + val tv:TextView = container.findViewById(tvId) as TextView + val toast = Toast(SingleCache.context) + toast.view = container + toast.duration = duration + return EasyToast(toast, tv, false) + } + + // Toast限制:在执行了Looper.prepare()的线程中才能创建Toast实例 + // 这里加强限制,仅限主线程创建 + private fun checkThread() { + if (Looper.myLooper() != Looper.getMainLooper()) { + throw RuntimeException("the toast-create method must called on main-thread") + } + } + } +} \ No newline at end of file diff --git a/sample/src/main/java/com/lzh/nonview/router/demo/tools/SingleCache.kt b/sample/src/main/java/com/lzh/nonview/router/demo/tools/SingleCache.kt new file mode 100644 index 0000000..acf02f4 --- /dev/null +++ b/sample/src/main/java/com/lzh/nonview/router/demo/tools/SingleCache.kt @@ -0,0 +1,28 @@ +package com.lzh.nonview.router.demo.tools + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Handler +import android.os.Looper + + +/** + * 提供一些全局的常用数据进行使用。 + * + * DATE: 2018/5/9 + * + * AUTHOR: haoge + */ +@SuppressLint("StaticFieldLeak") +object SingleCache { + internal var toast:EasyToast? = null + internal var context:Context? = null + var mainHandler: Handler = Handler(Looper.getMainLooper()) + + fun init(context: Context) { + if (this.context == null) { + this.context = context.applicationContext + toast = EasyToast.DEFAULT + } + } +} \ No newline at end of file diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index ccd5c20..60022d9 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -45,6 +45,17 @@ android:layout_width="match_parent" android:layout_height="wrap_content" /> +