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() + "必须是一个接口!");}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/50276.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Golang | Leetcode Golang题解之第290题单词规律

题目&#xff1a; 题解&#xff1a; func wordPattern(pattern string, s string) bool {word2ch : map[string]byte{}ch2word : map[byte]string{}words : strings.Split(s, " ")if len(pattern) ! len(words) {return false}for i, word : range words {ch : patt…

【知识分享】MIPI C-PHY 互连技术参数定义

目录 0 概述 1 Interconnect Specifications 1.1 Differential Insertion Loss 1.2 Differential Reflection Loss 1.3 Common-Mode Reflection Loss 1.4 Intra-Lane Cross Coupling 1.5 Mode-Conversion Loss 1.6 Inter-Lane Static Skew 2 Driver and Receiver Char…

好的STEM编程语言有哪些?

STEM是科学&#xff08;Science&#xff09;&#xff0c;技术&#xff08;Technology&#xff09;&#xff0c;工程&#xff08;Engineering&#xff09;&#xff0c;数学&#xff08;Mathematics&#xff09;四门学科英文首字母的缩写&#xff0c;STEM教育简单来说就是在通过在…

【管控业财一体化】

1. 引言 大型集团在现代企业管理中扮演着举足轻重的角色&#xff0c;其管控业财一体化解决方案是实现企业高效运营的关键。随着数字化转型的加速&#xff0c;业财一体化不再局限于财务与业务流程的简单融合&#xff0c;而是向着更深层次的数据驱动、智能化决策和价值创造方向发…

SpringMVC中的常用注解

目录 SpringMVC的定义 SpringMVC的常用注解 获取Cookie和Session SpringMVC的定义 Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架&#xff0c;从⼀开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来⾃其源模块的名称(Spring-webmvc)&#xff0c;但它…

百某应JS逆向

https://ying.baichuan-ai.com/ 目录 一、发起提问 二、观察发现有两个加密参数&#xff1a;X-Bc-Sig和X-Bc-Ts ​三、观察JS调用栈 四、从JS中搜索 X-Bc-Sig和X-Bc-Ts 五、断点并分析参数的生成方式 六、分析入参 七、发现关键的o方法调用了一个i()方法 八、验证结果 …

windows下配置Elasticsearch和kibana

一、下载Elasticsearch 8.12.2 Download Elasticsearch | Elastic 二、下载kibana 8.12.2 Download Kibana Free | Get Started Now | Elastic 三、下载ik&#xff1a;https://github.com/infinilabs/analysis-ik/releases?page1 选择与下载的es版本一致的下载 解压改名&…

Python 消费Kafka手动提交 批量存入Elasticsearch

一、第三方包选择 pip install kafka&#xff0c;对比了kafka和pykafka&#xff0c;还是选择kafka&#xff0c;消费速度更快pip install elasticsearch7.12.0(ES版本) 二、创建es连接对象 from elasticsearch import Elasticsearch from elasticsearch.helpers import bulkc…

@RequestParam和@PathVariable 处理 HTTP 请求参数的注解

RequestParam 请求参数 可解析前端get请求路径后以问号拼接的参数,查询参数是 URL 后面的问号 (?) 后跟的一系列键值对,RequestParam 可以设置参数是否是必需的&#xff08;使用 required 属性&#xff09; GetMapping("/users") public String getUsers(RequestPar…

前后端项目打包对比——关于Spring Boot Maven Plugin配置的问题

Spring Boot Maven Plugin 配置详解 Spring Boot Maven Plugin 配置详解1. 添加插件到 pom.xml2. 插件配置2.1 基本配置2.2 配置参数详解默认行为说明简单配置示例为什么这样的配置能工作&#xff1f;进一步说明 2.3 高级配置 3. 使用插件打包应用程序3.1 打包成 JAR 文件3.2 打…

ElasticSearch(六)— 全文检索

一、match系列查询 前面讲到的query中的查询&#xff0c;都是精准查询。可以理解成跟在关系型数据库中的查询类似。match系列的查询&#xff0c;是全文检索的查询。会通过分词进行评分&#xff0c;匹配&#xff0c;再返回搜索结果。 1.1 match 查询 "query": {&qu…

Linux 大页修改

随笔记录 目录 1. 背景介绍 2. 麒麟SP1 系统修改大页 2.1 查询大页信息 2.2 通过kernel cmdline配置大页 2.3 生成配置 2.4 查看配置是否生效 2.5 查询大页是否配置成功 3. CenOS 系统修改大页 1. 背景介绍 若操作系统当前Hugepagesize不是2048kB&#xff0c;则只能…

SSM框架整合——常用方式整合SSM框架(三)Spring和MyBatis整合

一、Spring和MyBatis的整合步骤 Spring和MyBatis的整合可以分为2步来完成&#xff0c;首先搭建Spring环境&#xff0c;然后整合MyBatis到Spring环境中。框架环境包含框架对应的依赖和配置文件&#xff0c;其中Spring的依赖、MyBatis的依赖、Spring和MyBatis整合的依赖&#xf…

c++笔记4

目录 深度优先搜索DFS DFS的复杂度 DFS与递归 递归与暴力枚举 递归树 DFS与栈 DFS的搜索剪枝 搜索剪枝与优化 可行性剪枝 最优化剪枝 减少等效的分支 优化搜索顺序 搜索的记忆化 搜索的复杂度 大多时候&#xff0c;搜索的复杂度都是指数级的。各种剪枝方案&#…

Flink 技术与应用(一)

Flink技术与应用&#xff08;初级篇&#xff09; 起源 Apache Flink 是一个开源的大数据处理框架&#xff0c;其起源可以追溯到一个名为 Stratosphere 的研究项目&#xff0c;旨在建立下一代大数据分析引擎&#xff0c;2010 年&#xff0c;从 Stratosphere 项目中分化出了 Fl…

「Unity3D」场景中的距离单位Unit与相关设置PixelsToUnits、PixelsPerUnit

GameObject在场景的位置Position&#xff0c;并没有明确是什么具体单位——如&#xff1a;Transform的x、y、z&#xff0c;或RectTransform的PosX、PosY、PosZ。而RectTransform在面板上显示的Width和Height&#xff0c;也没有具体单位&#xff0c;其实并不是像素。 事实上&am…

Java 中对象List 转map实践

class MyObject {Long id;String name;// Constructorpublic MyObject(Long id, String name) {this.id id;this.name name;}// Getterspublic Long getId() {return id;}public String getName() {return name;} }第一种 List 转 Map<Long, String> List<MyObject…

百易云资产管理运营系统 comfileup.php 文件上传致RCE漏洞复现(XVE-2024-18154)

0x01 产品简介 百易云资产管理运营系统,是专门针对企业不动产资产管理和运营需求而设计的一套综合解决方案。该系统能够覆盖资产的全生命周期管理,包括资产的登记、盘点、评估、处置等多个环节,同时提供强大的运营分析功能,帮助企业优化资产配置,提升运营效率。 0x02 漏…

用Python移除Word文档中的宏

Word文档作为最常用的电子文档格式之一&#xff0c;经常被用来作为内容分享工具&#xff0c;在网络中或设备之间进行传输&#xff0c;其安全性也需要受到关注。宏是可嵌入Word文档中的一种VBA迷你程序&#xff0c;用来执行一些自动化操作。虽然宏可以提高工作效率&#xff0c;但…

C++内存管理(候捷)第五讲 笔记

GNU C对allocators的描述 new_allocator 和malloc_allocator&#xff0c;它们都没有特别的动作&#xff0c;无非底部调用operator new和malloc。它们没有用内存池 区别&#xff1a;::operator new是可重载的 智能型的allocator&#xff0c;使用内存池&#xff0c;分一大块然后…