当前位置: 首页 > news >正文

Android小技巧:利用动态代理自动切换线程(续)

本文是针对上文Android小技巧:利用动态代理自动切换线程的一个补充,补充一种简单的实现方式。

上文中我们提到利用动态代理将对某个对象的方法调用自动切换到对应线程中去,只是探讨了可行性和局限,但如果每个功能都手动创建代理就显得有些繁琐。本文提供一个简单的工具来简化这个创建流程。

使用效果演示

方式一:注解控制
@RunInThread(ThreadType.IO)
public interface TestActor {void test();
}class TestActorImpl implements TestActor {@Overridepublic void test() {Log.d("SPECTRE", "TestActorImpl.test => " + Thread.currentThread().getName());}@Overridepublic int hashCode() {Log.d("SPECTRE", "TestActorImpl.hashCode => " + Thread.currentThread().getName());return super.hashCode();}
}//下面是获取代理对象并调用的代码
TestActor actor = ThreadProxyUtils.createThreadProxy(TestActor.class, new TestActorImpl());
actor.test();
actor.hashCode();
方式二:参数控制
// 这里没有注解
public interface TestActor {void test();
}class TestActorImpl implements TestActor {@Overridepublic void test() {Log.d("SPECTRE", "TestActorImpl.test => " + Thread.currentThread().getName());}@Overridepublic int hashCode() {Log.d("SPECTRE", "TestActorImpl.hashCode => " + Thread.currentThread().getName());return super.hashCode();}
}//下面是获取代理对象并调用的代码
TestActor actor = ThreadProxyUtils.createThreadProxy(ThreadType.IO, TestActor.class, new TestActorImpl()); // 多了ThreadType参数
actor.test();
actor.hashCode();

具体实现

  1. ThreadType定义(不想用enum可以改用静态int常量)
public enum ThreadType {IO, CPU, MAIN, HANDLER, SINGLE
}
  1. RunInThread注解
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
public @interface RunInThread {ThreadType value();
}
  1. ThreadProxyUtils实现(这里用了com.blankj.utilcode的ThreadUtils线程池,如果自己项目中已经有线程池管理,可以改用自己项目中的线程池)
public class ThreadProxyUtils {private static final AtomicInteger HANDLER_THREAD_INDEX = new AtomicInteger(1);private ThreadProxyUtils() {}public static <T> T createThreadProxy(Class<T> clazz, T impl) {ThreadType threadType = Optional.ofNullable(clazz.getAnnotation(RunInThread.class)).map(RunInThread::value).orElseThrow(() -> new IllegalStateException("类的注解中找不到ThreadType!"));return createThreadProxy(threadType, clazz, impl);}public static <T> T createThreadProxy(ThreadType threadType, Class<T> clazz, T impl) {if (clazz.isInterface()) {final Consumer<Runnable> taskConsumer;switch (threadType) {case IO:taskConsumer = action -> ThreadUtils.getIoPool().submit(action);break;case CPU:taskConsumer = action -> ThreadUtils.getCpuPool().submit(action);break;case SINGLE:taskConsumer = action -> ThreadUtils.getSinglePool().submit(action);break;case MAIN:Handler mainHandler = new Handler(Looper.getMainLooper());taskConsumer = mainHandler::post;break;case HANDLER:HandlerThread handlerThread = new HandlerThread("HandlerThread-" + HANDLER_THREAD_INDEX.getAndIncrement());handlerThread.start();Handler handler = new Handler(handlerThread.getLooper());taskConsumer = handler::post;break;default:throw new RuntimeException("非法的ThreadType: " + threadType);}Set<Method> methodSet = Arrays.stream(clazz.getMethods()).collect(Collectors.toSet());return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, (proxy, method, args) -> {if (methodSet.contains(method)) {taskConsumer.accept(() -> {try {method.invoke(impl, args);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);}});return null;} else {return method.invoke(impl, args);}});} else {throw new IllegalArgumentException(clazz.getCanonicalName() + "必须是一个接口!");}}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • wodpress设置固定链接的方式和好处【SEO优化】
  • Qt遇到qt自身组件找不到
  • Firefox扩展程序和Java通信
  • C# Task.WaitAll 的用法
  • BGP选路之Local Preference
  • table car vs. table cars:数据库命名用单数还是复数?
  • OpenCV图像滤波(1)双边滤波函数bilateralFilter的使用
  • 小规模的LLMS
  • C# 使用pythonnet 迁入 python 初始化错误解决办法
  • GO版本更新
  • [Meachines] Lame smbd3.0-RCE
  • 一文解决 | Linux(Ubuntn)系统安装 | 硬盘挂载 | 用户创建 | 生信分析配置
  • 可能是目前最全面的前端提测/自测标准
  • AI有关的学习和python
  • 数据结构-C语言-排序(4)
  • 收藏网友的 源程序下载网
  • egg(89)--egg之redis的发布和订阅
  • js ES6 求数组的交集,并集,还有差集
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • node-glob通配符
  • oschina
  • Web标准制定过程
  • 动态魔术使用DBMS_SQL
  • 关于 Linux 进程的 UID、EUID、GID 和 EGID
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 检测对象或数组
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 理解在java “”i=i++;”所发生的事情
  • 漂亮刷新控件-iOS
  • 如何编写一个可升级的智能合约
  • 如何打造100亿SDK累计覆盖量的大数据系统
  • 如何合理的规划jvm性能调优
  • 三栏布局总结
  • 实现菜单下拉伸展折叠效果demo
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • 使用权重正则化较少模型过拟合
  • 小程序button引导用户授权
  • 学习ES6 变量的解构赋值
  • 应用生命周期终极 DevOps 工具包
  • 用Visual Studio开发以太坊智能合约
  • 云栖大讲堂Java基础入门(三)- 阿里巴巴Java开发手册介绍
  • PostgreSQL之连接数修改
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • ​ssh免密码登录设置及问题总结
  • ​中南建设2022年半年报“韧”字当头,经营性现金流持续为正​
  • #QT 笔记一
  • #微信小程序:微信小程序常见的配置传旨
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • (ZT)薛涌:谈贫说富
  • (不用互三)AI绘画工具应该如何选择
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (附源码)c#+winform实现远程开机(广域网可用)
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (剑指Offer)面试题34:丑数
  • (入门自用)--C++--抽象类--多态原理--虚表--1020