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

news/2024/9/25 11:19:01/

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

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

使用效果演示

方式一:注解控制
java">@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();
方式二:参数控制
java">// 这里没有注解
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常量)
java">public enum ThreadType {IO, CPU, MAIN, HANDLER, SINGLE
}
  1. RunInThread注解
java">@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
public @interface RunInThread {ThreadType value();
}
  1. ThreadProxyUtils实现(这里用了com.blankj.utilcode的ThreadUtils线程池,如果自己项目中已经有线程池管理,可以改用自己项目中的线程池)
java">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() + "必须是一个接口!");}}
}

http://www.ppmy.cn/news/1499853.html

相关文章

记录贴-VUE相关

VUE多环境配置 链接: vue-cli3实现分环境打包步骤&#xff08;给不同的环境配置相对应的打包命令&#xff09; 链接: vue不同环境打包命令配置 链接: 官网-模式和环境变量 链接: vuejs多环境配置 链接: vue-cli-service build --mode 区分多个环境

线性代数:向量组与向量组等价

向量组概述 向量组是由若干个同维数的行向量或列向量组成的集合。这些向量可以是二维的、三维的&#xff0c;甚至是更高维度的。在数学和物理学的许多领域中&#xff0c;向量组扮演着至关重要的角色&#xff0c;特别是在线性代数、矩阵论、以及工程学中。 例如&#xff0c;一…

爬虫基本库的使用之使用urllib

在Python的爬虫开发领域&#xff0c;urllib是一个非常重要的基础库。它提供了丰富的接口来发送HTTP请求并处理响应&#xff0c;非常适合初学者以及需要快速实现HTTP请求的开发者。本文将详细介绍如何使用urllib库进行基本的网络爬虫开发。 1、urllib库简介 urllib是Python标准…

2.6基本算法之动态规划6045:开餐馆

描述 北大信息学院的同学小明毕业之后打算创业开餐馆.现在共有n 个地点可供选择。小明打算从中选择合适的位置开设一些餐馆。这 n 个地点排列在同一条直线上。我们用一个整数序列m1, m2, ... mn 来表示他们的相对位置。由于地段关系,开餐馆的利润会有所不同。我们用pi 表示在m…

Vue Router高级用法:动态路由与导航守卫

Vue Router是Vue.js官方的路由管理器&#xff0c;它和Vue.js的核心深度集成&#xff0c;让构建单页应用变得轻而易举。 动态路由 动态路由允许你在路由路径中使用变量&#xff0c;这些变量可以从实际的URL中获取&#xff0c;并传递给对应的路由组件。 定义动态路由 在route…

el-menu根据多层树形结构递归遍历展示菜单栏

文章目录 前提条件假设菜单等级只有两个等级结果如下所示 但是如果菜单等级超过两个等级或者多个等级的话App.vueMenuItems.vue结果如下所示 关于遍历时图标前的展示后续完善关于点击路由跳转参考element plus的官网即可 前提条件 package.json如下所示&#xff0c;这是一个Vi…

redis高可用之主从复制、哨兵以及Cluster集群

目录 一、Redis主从复制 1&#xff09;主从复制的作用 2&#xff09;主从复制流程 3&#xff09;搭建Redis主从复制 1、部署redis服务器 2、修改Redis配置文件&#xff08;所有节点操作&#xff09; 3、验证主从复制结果 二、哨兵模式 1&#xff09;哨兵的作用 2&…

Rabbitmq从入门到精通

文章目录 1. RabbitMQ简介1.2 组件介绍1.1 消息队列的选择1.2 Docker 安装rabbitmq1.4 消息应答机制 2.1 交换机类型2.1 direct2.2 fanout2.3 topic&#xff1a;2.4header 3 RabbitMQ集群搭建3.1docker 搭建 rabbitmq集群 4 死信队列4.1 ttl消息过期&#xff1a;生产者添加延迟…