首页 文章 精选 留言 我的

精选列表

搜索[UI设计],共10000篇文章
优秀的个人博客,低调大师

Android UI开发第二篇——多级列表(ExpandableListView)

开发中很多地方使用到了多级列表,android可以使用ExpandableListView很好的实现,下面模仿了手机qq的实现,见下图。 多级列表使用了ExpandableListView,自定义了Adapter; 代码可以到 http://www.devdiv.com/viewthread.php?tid=39473&extra= 下载 本文转自xyz_lmn51CTO博客,原文链接:http://blog.51cto.com/xyzlmn/817392,如需转载请自行联系原作者

优秀的个人博客,低调大师

如何去掉Android 6.0 UI界面上的搜索框

网上参考了许多博文,更改了不少都没有结果,搜索框就是去不了,后来在以下的这个java文件中找到这个按钮监听事件 packages/apps/Launcher3/src/com/android/launcher3/Launcher.java 找到这个方法: public View getOrCreateQsbBar() { ..... .... //将这段代码改成这样,屏蔽掉上方的搜索栏 if (widgetId != -1 && false) { //if (widgetId != -1) { //这里是原来的 mQsb = mAppWidgetHost.createView(this, widgetId, searchProvider); mQsb.setId(R.id.qsb_widget); ///M: ALPS02314317.//TODO : Need fix this workaround. mSearchDropTargetBar.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { onSearchRequested(); } }); mQsb.updateAppWidgetOptions(opts); mQsb.setPadding(0, 0, 0, 0); mSearchDropTargetBar.addView(mQsb); mSearchDropTargetBar.setQsbSearchBar(mQsb); } }

优秀的个人博客,低调大师

幂等设计详解

导读 本文主要从研发人员的角度,结合研发人员日常常见的各类业务场景,从经典系统框架的每一层入手分析幂等处理的时机。希望通过这篇文章的分析,让开发者在日常开发中对幂等的处理不再陌生。抓住导致请求、接口不幂等的本质,在工作中避免再陷入这个陷阱中。 幂等、幂等性这词,作为一个研发人员是再熟悉不过的,那是否有深入思考过幂等产生的背景、为什么需要幂等,如何做才是幂等的?今天将结合业务场景及请求的过程来分析解决幂等(性)的方法。 1 概念 幂等这个概念,是一个数学上的概念,即:f……(f(f(x))) = f(x)。用在计算机领域,指的是系统里的接口或方法对外的一种承诺,使用相同参数对同一资源重复调用某个接口或方法的结果与调用一次的结果相同。 2 业务场景 从业务场景上来说,如:现在互联网电商的下单服务,同一个用户在短时间内调用某一个下单服务,只能下单成功一次;银行账户之间的转账,A账户给B账户转账,无论系统出现什么问题或故障,也只能转账成功一次;前端页面对相同表单的内容多次向后端发起提交请求,后端只能给出一个相同的结果等都属于幂等的范畴。 试想一下,如果提供的这些服务不是幂等的,客户在下单时由于网络不稳定或是连续点了几次下单按钮,实际客户只下了一单,结果系统里给客户生成了多单,那平台/商家将是无法承受的,如果被“羊毛党”盯上,损失是无可估量的;银行之间的转账,A账户本来实际给B账户只转了一百万,结果B账户收到了几百万,这在业务上是不可接受的。分析这些业务场景,开发者发现,无论是下单服务、转账服务还是表单提交都是一个个业务请求,提供这些业务服务的接口或方法都应该保证无论服务是超时、重试或有故障等异常情况,都要满足业务上的处理结果是正确的。业务上的一次或多次请求,最终的处理结果是一致的,即:在一定时间内,服务的幂等其实就是请求的幂等。 3 架构分析 从系统架构上进行分析,幂等该在哪一层去做,怎么做? 图1 经典系统框架图 上图为一个最常见的经典系统框架图,Web端发起一个请求到后端,幂等该在哪一层来处理呢?不妨一层一层地分析。 Nginx是否需要做幂等,Nginx的主要功能是做Web服务器、反向代理、负载均衡等,把请求转发到后端的服务器上,本身不参与具体的业务,所以Nginx是不需要做幂等处理的;Gateway是负责权限校验、安全防御、认证鉴权、流量控制、协议转换、日志审计、监控等,本身也不含对任何业务的处理,所以其也不需要做幂等处理;Service层通常是对业务逻辑进行处理、编排,可能会改变数据,但对于数据的改变结果,最终也还是需要通过数据访问层,写入到数据库,所以Service层也不需要做数据幂等;DAO层主要是和数据库交互,把Service层的结果写入数据库,对Service层提供读取、写入数据库的功能。 在写入数据库的时候,针对每一次的写入,可能返回不同的结果,此时就需要按场景进行具体的分析对待;DataBase层,主要提供数据的存储,并不参与具体的业务逻辑计算。所以,通过对该架构的每一层的功能分析,得出对于请求的幂等处理,需要在DAO层做处理,以便保证多次请求和一次请求的结果是一致的。 4 数据库操作分析 通过上面的分析,得出幂等需要在DAO层来处理,再进一步分析,得出DAO层的操作主要就是CRUD。下面逐一对每一种操作分析是否需要做幂等,以及怎么做。 R(read):对应的操作SQL语句为select。只要查询条件不变,在一定的时间内,执行一次和执行多次返回的结果肯定是相同的,所以其本身是幂等的,不需要再做处理。 select * from user where id = 1; 查询一次或多次结果是一致的,所以是幂等的。 C(create):对应的操作SQL语句为insert。此时,需要分情况,如果用到的数据库主键为数据库自增,不考虑业务主键防重的情况下,每一次写入数据库就不是幂等的,所以为了保证幂等,需要在数据insert前做业务防重或是在数据库表上对业务主键加唯一索引。如果数据库主键不是自增,是由业务系统写入的,需要在业务系统里把数据库主键和业务主键做一对一映射,或是由独立服务提供数据库主键和业务主键的映射关系,保证多次请求获取到的数据库主键和业务主键是一致的,确保写入数据库操作是幂等的。综合来说,就是相同的数据多次写入数据库后,能否保证只有一条数据。 insert into user (id,age,sex,ts) values(1,10,‘male’,2021-07-20 10:22:23); U(update):对应的操作SQL语句为update。更新操作时,一定是要用绝对值进行更新操作,而不要用相对值进行更新,相对值更新可能导致更新操作不幂等。 幂等: update user set age = 10 where id = 1; 非幂等: update user set age++ where id = 1; D(delete):对应的操作SQL语句为delete。删除操作时,如果删除的是一个范围,生产上最好是禁止该类操作;比较推荐的做法是把按范围操作删除转换为先按范围查询,再按查询的主键进行删除。而且按范围删除的操作不是幂等的。 幂等: delete from user where id = 1; 非幂等:该类操作要禁止。 delete from user where id in (select id from user order by id desc limit 10); 5 常见业务场景 保证幂等的实现方式有多种,此处例举几类常见的业务场景,在实际应用中,根据业务场景进行选用。 图2 页面token机制处理流程 前端页面提交时,页面token机制。进入页面时,从服务器获取token,在服务器端把token进行存储,提交时把token带到服务器端进行验证;常见的处理流程如下: 乐观锁机制,使用数据库的版本号实现乐观锁,数据库更新时,判断版本号是否与查询时保持一致,一致更新成功,否则更新失败; select+insert,数据写入前,先查询数据是否存在,存在直接返回,不存在则写入数据,保证写入数据库的数据正确性;常用于并发不高的一些后台系统或是防止任务的重复执行; 悲观锁机制,一般id为主键或唯一索引,仅锁定当前记录; select*fromtablewhereid='1234'forupdate; 去重表,每一次写入或更新业务表时,先查询去重表是否已经存在记录,再操作业务表。 数据库唯一索引,为业务表建立唯一索引,避免业务数据多次写入; 状态机,业务状态在变更之前是有条件的,必须按设定的状态条件进行更新; 在实际开发中,保证提供的接口或服务的幂等(性),是一个最基本的技术要求,希望通过该分析,能对还未理解幂等(性)的研发人员有所帮助。

优秀的个人博客,低调大师

MASA Framework - EventBus设计

概述 利用发布订阅模式来解耦不同架构层级,亦可用于解决隔离业务之间的交互 优点: 松耦合 横切关注点 可测试性 事件驱动 <!-- more --> 发布订阅模式 发布者通过调度中心将消息发送给订阅者。调度中心解决发布与订阅者之间的关系,保证消息可以送达订阅者手中。 发布者与订阅者互不相识,发布者只管向调度中心发布消息,而订阅者只关心自己订阅的消息类型 多订阅者保序执行 在常见的发布订阅模式中,的确很少见到类似的说法。但在实际业务中我们会有类似的需求,一个消息由调度中心协调多个订阅者按照顺序执行消息,同时还可以将上一个订阅者处理过的消息传递给下一个订阅者。这样既可以保留发布订阅模式的特性,又有了顺序执行逻辑的特性。 一个小思考:如果 EventBus 的配置支持动态调整的话,是否业务的执行顺序也可以被动态排列组合? 换句话说它或许可以为进程内工作流提供了一个可能性 Event Sourcing(事件溯源) 一种事件驱动的架构模式,可以用于审计和溯源 基于事件驱动架构 以事件为事实 业务数据由事件计算产生的视图,可以持久化也可以不持久化 CQRS(命令查询的责任分离) CQRS 是一种架构模式,能够使改变模型与查询模型的实现分离 Event Sourcing & CQRS 事件溯源可以与 CQRS 很好的配合 在 Command Handler 中持久化事件到 Event Store 的同时实时计算一个最终视图给 View DB 用于查询展示 在 Query 中既可以通过 View DB 获取最新状态,也可以通过 Event Store 来重放事件来校验 View 或用于更严谨的业务 Saga Saga 是一个长活事务被分解成可以交错运行的子事务集合。其中每个子事务都是一个保持数据库一致性的真实事务 每个 Saga 由一系列 sub-transaction Ti 组成 每个 Ti 都有对应的补偿动作 Ci,补偿动作用于撤销 Ti 造成的结果 两种执行顺序 T1, T2, T3...[Tx retry]...,Tn T1, T2, ..., Tj, Cj,..., C2, C1 两种恢复策略 backward recovery,向后恢复,补偿所有已完成的事务,如果任一子事务失败。即上面提到的第二种执行顺序,其中 j 是发生错误的 sub-transaction,这种做法的效果是撤销掉之前所有成功的 sub-transation,使得整个 Saga 的执行结果撤销 forward recovery,向前恢复,重试失败的事务,假设每个子事务最终都会成功。适用于必须要成功的场景,执行顺序是类似于这样的:T1, T2, ..., Tj(失败), Tj(重试),..., Tn,其中 j 是发生错误的 sub-transaction。该情况下不需要 Ci BuildingBlocks 的类视图 作为接口标准,BuildingBlocks 中并没有过多的干涉实现方式,它只保留了最基础的功能流程限制,以达到最小 EventBus 的功能集合。至于最终是基于接口还是特性来实现订阅关系的,交还给 Contrib 自行决定。 事件 用于本地事件的发布/订阅 IEvent:事件接口,IEvent<TResult>为带返回值的基础事件接口 IEventHanldler<TEvent>:事件处理器接口,ISagaEventHandler<TEvent>为 Saga 的实现提供了基础接口要求 IMiddleware<TEvent>:中间件接口,允许在事件执行前挂载预处理动作和时间执行后的收尾动作 IEventBus:事件总线接口,用于发送事件,并提供订阅关系维护和附加功能执行 集成事件 用于跨进程事件的发布/订阅 IntegrationEventLog:集成事件日志,用于实现本地消息表的消息模型 IIntegrationEventLogService:集成事件日志服务接口 ITopic:发布/订阅的主题 IIntegrationEvent:集成事件接口 IIntegrationEventBus:集成事件总线,用于跨进程调用的事件总线 CQRS 用于使改变模型与查询模型的实现分离 IQuery<TResult>:查询的接口 IQueryHandler<TCommand,TResult>:查询处理器接口 ICommand:可用于增删改等指令的接口 ICommandHandler<TCommand>:指令处理器接口 Event Bus 要完成上述的这些功能,我们需要借助于 EventBus,它需要有以下基础功能 接收事件 维护订阅关系 转发事件 接收与转发事件 这两个功能其实可以合并为一个接口,由发布者调用 Publish,再由 Event Bus 根据订阅关系转发即可 维护订阅关系 在.Net 项目中,我们常见的用于扫描自动注册的方式是接口和特性 MediatR 支持接口的方式去扫描事件订阅关系,举个例子:IRequestHandler<,> public class PingHandler : IRequestHandler<Ping, string> { public Task<string> Handle(Ping request, CancellationToken cancellationToken) { return Task.FromResult("Pong"); } } 如果你的代码洁癖程度没有高的离谱,或许你希望是这样 public class NetHandler : IRequestHandler<Ping, string>, IRequestHandler<Telnet, string> { public Task<string> Handle(Ping request, CancellationToken cancellationToken) { return Task.FromResult("Pong"); } public Task<string> Handle(Telnet request, CancellationToken cancellationToken) { return Task.FromResult("Success"); } } 看着好像还行?如果很多呢? 那有没有办法解决这个问题? 特性!我们来看个例子 public class NetHandler { [EventHandler] public Task PingAsync(PingEvent @event) { //TODO } [EventHandler] public Task TelnetAsync(TelnetEvent @event) { //TODO } } 似乎我们找到了一个出路 多订阅者保序执行 通过事件层层推进确实可以满足顺序执行的场景,但如果你被大量无限套娃的事件包围的时候或许你需要另外一个出路,看下例子: public class NetHandler { [EventHandler(0)] public Task PingAsync(PingEvent @event) { //TODO } [EventHandler(1)] public Task LogAsync(PingEvent @event) { //TODO } } 只要参数是同一个 Event 就会按照 EventHandler 的 Order 顺序执行。 Saga 那执行失败了怎么办,如果两个方法因为其中一个需要调用远程服务而无法跟本地事务结合,能帮我回滚吗? 来吧,SAGA 走起,帮你再做个取消动作,同时还支持重试机制,以及是否忽略当前步骤的取消动作。 我们先来预设一下场景: 调用 CheckBalanceAsync 来检查余额 调用 WithdrawAsync, 抛出 exception 重试 WithdrawAsync 3 次 调用 CancelWithdrawAsync 代码如下: public class TransferHandler { [EventHandler(1)] public Task CheckBalanceAsync(TransferEvent @event) { //TODO } [EventHandler(2, FailureLevels.ThrowAndCancel, enableRetry: true, retryTimes: 3)] public Task WithdrawAsync(TransferEvent @event) { //TODO throw new Exception(); } [EventHandler(2, FailureLevels.Ignore, enableRetry: false, isCancel: true)] public Task CancelWithdrawAsync(TransferEvent @event) { //TODO } } AOP 举个业务场景,给所有 Command 在执行前增加一个参数验证 我们提供了 Middleware,允许像俄罗斯套娃一样(.Net Middleware)做横切关注点的相关的事情 public class LoggingMiddleware<TEvent> : IMiddleware<TEvent> where TEvent : notnull, IEvent { private readonly ILogger<LoggingMiddleware<TEvent>> _logger; public LoggingMiddleware(ILogger<LoggingMiddleware<TEvent>> logger) => _logger = logger; public async Task HandleAsync(TEvent @event, EventHandlerDelegate next) { _logger.LogInformation("----- Handling command {EventName} ({@Event})", typeof(TEvent).FullName, @event); await next(); } } 注册 DI builder.Services.AddTransient(typeof(IMiddleware<>), typeof(LoggingMiddleware<>)) MASA EventBus 完整功能列表 接收事件 维护订阅关系 - 接口 维护订阅关系 - 特性 多订阅者顺序执行 转发事件 Saga AOP UoW 自动开启和关闭事务 Integration Event Bus 用于跨服务的 Event Bus,支持最终一致性,本地消息表 Pub/Sub 提供了 Pub Sub 接口,并基于 Dapr Pub/Sub 提供默认实现 本地消息表 提供了本地消息保存和 UoW 联动接口,并基于 EF Core 提供默认实现 使用方法 启用 Dapr Event Bus builder.Services .AddDaprEventBus<IntegrationEventLogService>(options=> { options.UseUoW<CatalogDbContext>(dbOptions => dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=Password;database=test")) .UseEventLog<CatalogDbContext>(); ) }); 定义 Integration Event public class DemoIntegrationEvent : IntegrationEvent { public override string Topic { get; set; } = nameof(DemoIntegrationEvent);//dapr topic name //todo other properties } 定义 DbContext(非必须,定义 DbContext 可以将本地消息表与业务事务联动) public class CustomDbContext : IntegrationEventLogContext { public DbSet<User> Users { get; set; } = null!; public CustomDbContext(MasaDbContextOptions<CustomDbContext> options) : base(options) { } } 发送 Event IIntegrationEventBus eventBus; // from DI await eventBus.PublishAsync(new DemoIntegrationEvent()); 订阅 Event(基于 Dapr Pub/Sub 的版本) [Topic("pubsub", nameof(DomeIntegrationEvent))] public async Task DomeIntegrationEventHandleAsync(DomeIntegrationEvent @event) { //todo } Domain Event Bus 在领域中同时提供 Event Bus 和 Integration Event Bus 的能力,允许实时发送事件或在 Save 时一次性触发 Domain Event Bus 是最完整的能力,所以使用 Domain Event Bus 相当于已经开启了 Event Bus 和 Integration Event Bus,在 Domain Event Bus 内部会自动协调事件分类往 Event Bus 和 Integration Event Bus 分流 启用 Domain Event Bus builder.Services .AddDomainEventBus(options => { options.UseEventBus()//Use in-process events .UseUoW<CustomDbContext>(dbOptions => dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=idientity")) .UseDaprEventBus<IntegrationEventLogService>()///Use cross-process events .UseEventLog<LocalMessageDbContext>() .UseRepository<CustomDbContext>(); }) 添加 DomainCommand Domain Event 是进程内事件,IntegrationDomainEvent 是跨进程事件 public class RegisterUserSucceededIntegrationEvent : IntegrationDomainEvent { public override string Topic { get; set; } = nameof(RegisterUserSucceededIntegrationEvent); public string Account { get; set; } = default!; } public class RegisterUserSucceededEvent : DomainEvent { public string Account { get; set; } = default!; } 进程内事件订阅 [EventHandler] public Task RegisterUserHandlerAsync(RegisterUserDomainCommand command) { //TODO } 跨进程事件订阅 [Topic("pubsub", nameof(RegisterUserSucceededIntegrationEvent))] public async Task RegisterUserSucceededHandlerAsync(RegisterUserSucceededIntegrationEvent @event) { //todo } 发送 DomainCommand IDomainEventBus eventBus;//from DI await eventBus.PublishAsync(new RegisterUserDomainCommand()); 使用场景 兼顾遗留系统对接 游走在云与非云中 流计算 微服务解耦和跨集群通信(需要将 Dapr Pub/Sub 改为 Dapr Binding,不难) 部分 AOP 类场景 总结 事件驱动可以解决一些特定场景的问题,凡事都有两面性,在本来就很简单的业务场景中使用如此复杂的模式会带来不小的负担。 学以致用,学无止境。 开源地址 MASA.BuildingBlocks:https://github.com/masastack/MASA.BuildingBlocks MASA.Contrib:https://github.com/masastack/MASA.Contrib MASA.Utils:https://github.com/masastack/MASA.Utils MASA.EShop:https://github.com/masalabs/MASA.EShop 如果你对我们的 MASA Framework 感兴趣,无论是代码贡献、使用、提 Issue,欢迎联系我们

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册