全部 文章 问答 分享 共找到127个相关内容
[文章] 分布式信号量(Redis)
分布式信号量是一种在分布式环境中用于控制并发访问资源的机制,通常基于像Redis这样的分布式键值存储系统实现。在单机环境下,信号量是一个同步原语,用于限制同时访问特定资源的进程数或者线程数。
2024-01-25 12:08 · redis / 信号量 / 计数器
[问答] 大佬们请教个分布式并发编程的问题
如果要给修改钱包,修改订单,修改库存三个方法加分布式锁,最后,给paySuccess再加一个分布式锁锁住所有这个支付订单相关的资源,这种做法是不是不正确。或者有什么其他的思路?
2023-11-16 11:17 · 后端 / 高并发
[文章] git分布式版本控制的介绍以及安装
1、版本控制工具的介绍以及功能1.1、协调开发git是分布式的代码管理平台,通过配置属性进行代码托管,从而进行协调开发。
1970-01-01 00:00 · git / git安装 / 版本控制
[文章] 分布式ID生成-雪花算法SnowflakeIdWorker
分布式ID生成-雪花算法SnowflakeIdWorker我们生成ID的方式有多种,比如说UUID,比如说自动增长...但是,随着业务的增长与用户数量的增长,这就满足不了需求了。
2020-02-01 16:27 · 雪花算法 / 随机数 / ID / 算法 / 分布式
[文章] 水一篇:尝试用分布式跑密码字典
那么针对单个网站,我们其实可以对响应进行去重,具体的日志只记录响应的id由于数据量较大,可以在本地做一层缓存,定时同步,找不到该响应,再向数据库发起请求可以参考现有开源分布式爬虫进行改造结尾没了
2024-03-19 09:06 · 我tm / 我tm偏不信 / java
[问答] 找人教我部署分布式单体项目上线(悬赏200元)
部署上线,现在正式向大家救助:


情况描述:


1、我看了很多教程,根据自己的想法拼凑起来的一个还不完善的个人文学类论坛社区项目,前后端分离、分布式

2021-09-30 15:44 · 项目部署 / java / springCloud
[文章] 安装Minio文件服务器
安装Minio-Minio快速入门文档链接:http://docs.minio.org.cn/docs/Minio有什么好处在大数据领域,通常的设计理念都是无中心和分布式
2021-12-24 21:18 · Linux / minio / 文件服务器
[问答] 大佬的摸鱼君项目有教 刷新 token 吗?

我尝试在这里去查数据库的 refreshToken ,来生成新的 token, 但分布式项目,我操作 cookie 失败了。

2022-03-19 16:12 · gateway / jwt / springsecurity / nuxt
[文章] IntelliJ GoLand破解文件下载
对于高性能分布式系统领域而言,Go语言无疑比大多数其它语言有着更高的开发效率。它提供了海量并行的支持,这对于游戏服务端的开发而言是再好不过了。
2020-08-16 15:22 · 工具类
[文章] 学习笔记·RabbitMQ
服务网格基于消息中间件的分布式架构从上图中可以看出来,消息中间件的是利用可靠的消息传递机制进行系统和系统直接的通讯通过提供消息传递和消息的排队机制,它可以在分布式系统环境下扩展进程间的通讯。
2022-07-23 16:00 · RabbitMQ / 消息中间件 / 中间件 / 分布式
[文章] SpringCould-Zookeeper服务注册与发现
Zookeeper是一个分布式协调工具,实现了注册中心的功能。
2020-09-04 11:11 · SpringCloud / zookeeper
[文章] Android 实现沉浸状态
本文使用Andorid10@TOC前言简单三步实现沉浸状态栏一、什么是沉浸状态栏?实质上就是使手机状态栏的颜色改变。使其成为自己想要的颜色。假设把它设置成和APP主色调同样。
2022-09-29 16:15 · android / 安卓 / 沉浸式状态栏
[文章] 内存溢出和内存泄露的区别?
云服务或分布式计算:如果是在云环境或分布式环境中,根据需求动态扩展资源,避免单个节点上的内存溢出。如何避免内存泄露?避免内存泄露主要依赖于良好的编程习惯和对所用编程语言内存管理机制的深入理解。
2024-02-01 15:52 · 内存泄露 / 内存溢出
[文章] redis
数据模型:一系列键值对优势:快速查询劣势:存储的数据缺少结构化列存储数据库相关产品:Cassandra,HBase,Riak典型应用:分布式的文件系统数据模型:以列簇存储,将同一列数据存在一起优势:查找速度快
2020-10-27 14:53 · redis
[文章] 23、Android开发基础之通过隐意图来实现界面的跳转
Android开发基础之通过隐意图来实现界面的跳转在上一节课里头,我们通过显意图来实现界面的跳转。什么是显意图?什么是隐意图?
2019-10-22 10:45 · activity / 安卓 / 显示意图 / 隐式意图 / android
[问答] 【每日面试题】懒汉的单例为什么要使用double check?
懒汉的单例为什么要使用doublecheck?单例,我们知道有懒汉和饿汉!为什么懒汉要进行doublecheck呢?相关问题:如果使用静态内部类的方式创建单例,有什么好处?(为什么要这么做?)
2020-11-06 16:36 · 每日面试题
[文章] 初识promethus
Prometheus的主要特点是:一个多维数据模型,其中包含通过度量标准名称和键/值对标识的时间序列数据PromQL,一种灵活的查询语言,可利用此维度不依赖分布式存储;单服务器节点是自治的时间序列收集通过
2021-02-18 20:41 · prometheus
[文章] Android5.1格化sd卡AOSP
Android5.1格化sd卡AOSP今天下午在做一个格式化的,看了一下系统的API,实现了。分享给大家吧。
2019-10-04 17:33 · AOSP / 安卓 / 系统移植 / 系统开发 / 裁剪系统
[文章] JavaWeb博客系统后端-添加用户
BeanpublicBCryptPasswordEncodergetPasswordEncoder(){returnnewBCryptPasswordEncoder();}}这里也有一个SnowflakeIdWorker的类这个可以去查看一下这篇文章分布式
2020-02-01 18:54 · 用户 / 博客系统 / web后台 / 后端 / Java
[文章] Hadoop集群搭建-base on Ubuntu18.04
分布式存储和分布式计算。这不就是电脑的作用么?一是存储,二是运算。把各种机器的资源利用起来,处理大数据,或者需要大算力的任务。
2023-02-05 21:42 · 大数据 / hadoop / 分布式 / 运算 / hdfs
[问答] 请问,虚拟机中 nginx 如何通过IP地址配置反向代理到三个前端项目?
1443481910658584577" rel="noopener noreferrer" target="_blank" style="color: rgb(0, 132, 255);">找人教我部署分布式单体项目上线
2021-10-01 14:36 · 项目部署 / nginx / vue / nuxt
[文章] java微服务开发(基础环境篇)
和配置环境变量吧gitgit也是工作中常用的工具了,不管你的项目是大还是小我都建议使用git来管理并且找一个稳定的git仓库来保存比如国外的github国内的gitee也可以自建gitlab或者gogsGIT(分布式版本控制系统
2020-08-10 22:15 · 微服务 / docker / dockercompose / mysql / elk
[文章] Spring Cloud-Consul服务注册与发现
Consul简介什么是ConsulConsul是一个支持多数据中心分布式高可用的服务发现和配置共享的服务软件,由HashiCorp公司用Go语言开发,基于MozillaPublicLicense2.0的协议进行开源
2020-09-05 09:40 · Consul / SpringCloud
[文章] 学习笔记-MybatisPlus
仅仅通过少量配置即可实现单表大部分CRUD操作,更有强大的条件构造器,满足各类使用需求支持Lambda形式调用:通过Lambda表达式,方便的编写各类查询条件,无需再担心字段写错支持主键自动生成:支持多达4种主键策略(内含分布式唯一
2021-09-16 22:54 · JAVA / mybatis / Mybatis / MybatisPlus
[文章] Spring Cloud Config Server 连接github仓库的几种方式
之前学习了SpringCloudConfig分布式配置中心,其中使用到SpringCloudConfigServer连接github,从而读取configrepo中的配置信息。现作个笔记,以免忘记。
2020-09-07 16:01 · SpringCloud / 配置中心
[问答] 学习Activity 无法跳转到第三方页面 完全按照视频教程 APP闪退求解决

学习Activity 无法跳转到第三方页面 完全按照视频教程 APP闪退


意图

2021-08-12 17:42 · Activity

[问答] Linearlayout均分布局怎么实现

想请教一下,父布局是Linearlayout, 里面嵌套6个子view,需要这6个LinearLayout均分整个父布局,同时第一个LinearLayout和最后一个LinearLayout是紧贴父布局的,这个不在代码里面动态设置,在xml应该如何实现呢

2022-07-19 23:37 · 布局
[文章] 安卓APP应用内实现插件换肤
需求背景之前的某一天我们项目经理给我说,客户想要APP有换肤的功能,我们的OA项目要支持换肤功能,于是我就去~~Google搜索~~学习了一波~大家应该都知道,我们常用的手机QQ是支持换肤功能的,而且皮肤主题可以在线下载使用!没错,QQ不是把皮肤主题写死在APP内部的,而是通过插件形式进行换肤功能实现的,而且整个过程不需要重启APP或Activity。也就是说,我们需要做到以下几点:资源的动态加载(可以加载外部的皮肤包插件)实时换肤(无需重启APP或Activity)换肤后的状态保存(下次进入时还是上一次换肤后的效果:持久化加载皮肤插件的配置)换肤效果图什么是皮肤插件包?皮肤插件包其实就是不包含Java代码(当然,如果你不嫌皮肤插件包apk的体积变大,你也可以留着)的一个apk安装包。换肤功能介绍我们APP内换肤针对的一般有以下几种资源:View的背景(background:color、drawable、mipmap)图片资源(src:drawable、mipmap)文字的颜色(textColor:color)插件换肤原理(动态加载皮肤资源)关键点(系统源码)AssetManager.javaResources.javaAppCompatDelegate.javaAppCompatDelegateImpl.javaLayoutInflater.Factory2.javaAppCompatViewInflater.java换肤流程我们加载插件apk皮肤中的资源,其实就是要解析apk包,那么我们怎么解析呢?平时我们获取app的资产文件时是通过AssetManager这个类进行加载的,我们的换肤插件apk也是通过这个类进行加载的。获取color、drawable、mipmap资源则是通过Resources类的一系列方法进行获取的。创建AndroidLibraryModuleNewNewModule...CreateNewModule导入依赖在skinModule中的build.gradle文件内导入必要的依赖(你也可以使用你自己的Log日志打印工具类)dependencies{//AndroidX库:https://github.com/androidx/androidximplementation'androidx.appcompat:appcompat:1.3.1'implementation'androidx.core:core-ktx:1.7.0'implementation'androidx.activity:activity-ktx:1.4.0'implementation'androidx.fragment:fragment-ktx:1.3.6'//日志打印框架(可选):https://github.com/JakeWharton/timberimplementation'com.jakewharton.timber:timber:4.7.1'}新建Kotlin类文件新建activity、attr、callback、factory、manager、util这几个包新建如下kotlin类SupportSkinActivity.kt:支持换肤的Activity基类,使用者可以继承该类以获得换肤的实现SkinAttr.kt:皮肤属性SkinAttrSupport.kt:皮肤属性支持SkinAttrType.kt:皮肤属性类型SkinView.kt:皮肤View,包括需要换肤的View以及需要换肤的皮肤属性信息ISkinChangedListener.kt:换肤监听器ISkinChangingCallback.kt:换肤回调DefaultSkinConfigFactory.kt:默认皮肤配置工厂SkinConfigFactory.kt:皮肤配置工厂SkinFactory.kt:皮肤工厂SkinManager.kt:皮肤管理器,在Application中进行init初始化SkinResourcesManager.kt:皮肤资源管理器AppCompatActivity.kt:AppCompatActivity支持换肤的扩展函数项目目录创建好的项目目录如下图所示实现源码SupportSkinActivity.kt/***author:ALonelyCat*github:https://github.com/anjiemo/SunnyBeach*time:2021/11/19*desc:支持换肤的Activity基类,使用者可以继承该类以获得换肤的实现*/openclassSupportSkinActivity:AppCompatActivity(),ISkinChangedListener{@CallSuperoverridefunonCreate(savedInstanceState:Bundle?){hookActivity(this)super.onCreate(savedInstanceState)}overridefunonSkinChanged(){}@CallSuperoverridefunonDestroy(){super.onDestroy()removeActivityHook(this)}}SkinAttr.kt/***author:ALonelyCat*github:https://github.com/anjiemo/SunnyBeach*time:2021/11/19*desc:皮肤属性*/classSkinAttr(privatevalresName:String,privatevalresType:String,vartype:SkinAttrType){funapply(view:View?){type.apply(view,resType,resName)}}SkinAttrSupport.kt/***author:ALonelyCat*github:https://github.com/anjiemo/SunnyBeach*time:2021/11/19*desc:皮肤属性支持*/objectSkinAttrSupport{/***获取皮肤属性*/fungetSkinAttrs(resources:Resources,attrs:AttributeSet):List<SkinAttr>{valskinAttrs:MutableList<SkinAttr>=ArrayList()vari=0valn=attrs.attributeCountwhile(i<n){//例:id、layout_width、layout_height、background、color、drawablevalattrName=attrs.getAttributeName(i)//例:@2131296320、@2131297009、@2131230904valattrValue=attrs.getAttributeValue(i)Timber.d("getSkinAttrs:===>attrNameis%sattrValueis%s",attrName,attrValue)if(attrValue.startsWith("@")){varresId=0try{resId=attrValue.substring(1).toInt()}catch(e:NumberFormatException){e.printStackTrace()}catch(e:IndexOutOfBoundsException){e.printStackTrace()}//如果是无效的资源id则跳过if(resId==Resources.ID_NULL){i++continue}//获取资源类型名称valresType=resources.getResourceTypeName(resId)//获取资源的名称valresName=resources.getResourceEntryName(resId)Timber.d("getSkinAttrs:===>resTypeis%sresNameis%s",resType,resName)//具有换肤的前缀,是支持的换肤资源类型if(resName.startsWith(SkinConfigFactory.SKIN_PREFIX)){valattrType=getSupportAttrType(attrName)//如果不是支持换肤的属性类型,则跳过if(attrType==null){i++continue}skinAttrs.add(SkinAttr(resName,resType,attrType))}}i++}returnskinAttrs}/***通过资源属性名称,获取支持换肤的属性类型*/privatefungetSupportAttrType(attrName:String):SkinAttrType?{for(attrTypeinSkinAttrType.values()){if(attrType.resType==attrName){returnattrType}}returnnull}}SkinAttrType.kt/***author:ALonelyCat*github:https://github.com/anjiemo/SunnyBeach*time:2021/11/19*desc:皮肤属性类型*/enumclassSkinAttrType(valresType:String){/***background*/BACKGROUND("background"){overridefunapply(view:View?,resType:String,resName:String){valdrawable:Drawable?=getResourceManager().getDrawableByName(resType,resName)if(view!=null&&drawable!=null){view.background=drawable}}},/***src*/SRC("src"){overridefunapply(view:View?,resType:String,resName:String){valdrawable:Drawable?=getResourceManager().getDrawableByName(resType,resName)if(viewisImageView&&drawable!=null){view.setImageDrawable(drawable)}}},/***textColor*/TEXT_COLOR("textColor"){overridefunapply(view:View?,resType:String,resName:String){valcolorStateList:ColorStateList?=getResourceManager().getColorByResName(resType,resName)if(viewisTextView&&colorStateList!=null){view.setTextColor(colorStateList)}}};fungetResourceManager()=SkinManager.instance.resourcesManagerabstractfunapply(view:View?,resType:String,resName:String)}SkinView.kt/***author:ALonelyCat*github:https://github.com/anjiemo/SunnyBeach*time:2021/11/19*desc:皮肤View,包括需要换肤的View以及需要换肤的皮肤属性信息*/classSkinView(privatevalview:View,privatevalattrs:List<SkinAttr>){funapply(){attrs.forEach{it.apply(view)}}}ISkinChangedListener.kt/***author:ALonelyCat*github:https://github.com/anjiemo/SunnyBeach*time:2021/11/19*desc:换肤监听器*/interfaceISkinChangedListener{/***皮肤变了*/funonSkinChanged()}ISkinChangingCallback.kt/***author:ALonelyCat*github:https://github.com/anjiemo/SunnyBeach*time:2021/11/19*desc:换肤回调*/interfaceISkinChangingCallback{/***开始更换皮肤*/funonStartChangeSkin()/***更换皮肤错误*/funonChangeSkinError(e:Exception)/***更换皮肤完成*/funonChangeSkinComplete()/***默认的换肤回调*/classDefaultSkinChangingCallbackImpl:ISkinChangingCallback{overridefunonStartChangeSkin(){}overridefunonChangeSkinError(e:Exception){}overridefunonChangeSkinComplete(){}}}DefaultSkinConfigFactory.kt/***author:ALonelyCat*github:https://github.com/anjiemo/SunnyBeach*time:2021/11/19*desc:默认皮肤配置工厂*/classDefaultSkinConfigFactory(appContext:Application):SkinConfigFactory{privatevalsp=appContext.getSharedPreferences(PREF_NAME,Context.MODE_PRIVATE)overridefunsavePluginPath(path:String?){sp.edit{putString(KEY_PLUGIN_PATH,path)}}overridefunsavePluginPkg(pkg:String?){sp.edit{putString(KEY_PLUGIN_PKG,pkg)}}overridefunsaveSuffix(suffix:String?){sp.edit{putString(KEY_PLUGIN_SUFFIX,suffix)}}overridefungetPluginPath():String=sp.getString(KEY_PLUGIN_PATH,null)?:""overridefungetPluginPkg():String=sp.getString(KEY_PLUGIN_PKG,null)?:""overridefungetSuffix():String=sp.getString(KEY_PLUGIN_SUFFIX,null)?:""overridefunclearSkinConfig(){sp.edit{clear()}}}SkinConfigFactory.kt/***author:ALonelyCat*github:https://github.com/anjiemo/SunnyBeach*time:2021/11/19*desc:皮肤配置工厂*/interfaceSkinConfigFactory{/***保存皮肤插件的路径*/funsavePluginPath(path:String?)/***保存皮肤插件的包名*/funsavePluginPkg(pkg:String?)/***保存皮肤的后缀*/funsaveSuffix(suffix:String?)/***获取皮肤插件的路径*/fungetPluginPath():String/***获取皮肤插件的包名*/fungetPluginPkg():String/***获取皮肤的后缀*/fungetSuffix():String/***清空皮肤配置*/funclearSkinConfig()companionobject{/***插件换肤相关*/constvalSKIN_PREFIX="skin_"constvalPREF_NAME="skin_plugin"constvalKEY_PLUGIN_PATH="plugin_path"constvalKEY_PLUGIN_PKG="plugin_pkg"constvalKEY_PLUGIN_SUFFIX="plugin_suffix"/***插件包的路径(默认在设备sdcard的根目录下,可根据实际情况进行设置)*/valSKIN_PLUGIN_PATH=Environment.getExternalStorageDirectory().toString()+File.separator+"sunnybeach.skin"/***插件包的包名*/constvalSKIN_PLUGIN_PKG="cn.android52.sunnybeach.skin"}}SkinFactory.kt/***author:ALonelyCat*github:https://github.com/anjiemo/SunnyBeach*time:2021/11/19*desc:皮肤工厂*/classSkinFactory(privatevaldelegate:AppCompatDelegate,privatevallistener:ISkinChangedListener?):LayoutInflater.Factory2{privatevalsConstructorSignature=arrayOf(Context::class.java,AttributeSet::class.java)privatevalsClassPrefixList=arrayOf("android.widget.","android.view.","android.webkit.")privatevalsConstructorMap:MutableMap<String,Constructor<outView?>>=arrayMapOf()privatevalmConstructorArgs=arrayOfNulls<Any?>(2)privatevarmCreateViewMethod:Method?=nullprivatevalsCreateViewSignature=arrayOf(View::class.java,String::class.java,Context::class.java,AttributeSet::class.java)privatevalmCreateViewArgs=arrayOfNulls<Any>(4)overridefunonCreateView(name:String,context:Context,attrs:AttributeSet):View?{returnnull}overridefunonCreateView(parent:View?,name:String,context:Context,attrs:AttributeSet):View?{//系统有没有使用setFactory//完成AppCompatfactory的工作varview:View?=null//请参阅AppCompatDelegateImpl类,使用反射调用createView方法try{if(mCreateViewMethod==null){mCreateViewMethod=delegate.javaClass.getMethod("createView",*sCreateViewSignature)}//mCreateViewArgsmCreateViewArgs[0]=parentmCreateViewArgs[1]=namemCreateViewArgs[2]=contextmCreateViewArgs[3]=attrsview=mCreateViewMethod!!.invoke(delegate,*mCreateViewArgs)asView?}catch(e:Exception){e.printStackTrace()}//收集当前View需要换肤的属性集合valskinAttrs:List<SkinAttr>=SkinAttrSupport.getSkinAttrs(context.resources,attrs)//如果当前View需要换肤的属性集合为空,则代表该View不需要换肤,直接返回该Viewif(skinAttrs.isEmpty()){returnnull}if(view==null){view=createViewFromTag(context,name,attrs)}if(view!=null){//当前View具有需要换肤的属性,将该View和需要换肤的属性集合保存起来injectSkin(view,skinAttrs)}returnview}/***请参阅AppCompatViewInflater类中的实现*/privatefuncreateViewFromTag(context:Context,name:String,attrs:AttributeSet):View?{varattrName=nameif(attrName=="view"){attrName=attrs.getAttributeValue(null,"class")}returntry{mConstructorArgs[0]=contextmConstructorArgs[1]=attrsif(-1==attrName.indexOf('.')){for(iinsClassPrefixList.indices){valview:View?=createViewByPrefix(context,attrName,sClassPrefixList[i])if(view!=null){returnview}}null}else{createViewByPrefix(context,name,null)}}catch(e:Exception){//Wedonotwanttocatchthese,letsreturnnullandlettheactualLayoutInflater//trynull}finally{//Don'tretainreferencesoncontext.mConstructorArgs[0]=nullmConstructorArgs[1]=null}}/***请参阅AppCompatViewInflater类中的实现*/@Throws(ClassNotFoundException::class,InflateException::class)privatefuncreateViewByPrefix(context:Context,name:String,prefix:String?):View?{varconstructor=sConstructorMap[name]returntry{if(constructor==null){//Classnotfoundinthecache,seeifit'sreal,andtrytoadditvalclazz=Class.forName(if(prefix!=null)prefix+nameelsename,false,context.classLoader).asSubclass(View::class.java)constructor=clazz.getConstructor(*sConstructorSignature)sConstructorMap[name]=constructor}constructor!!.isAccessible=trueconstructor.newInstance(*mConstructorArgs)}catch(e:Exception){//Wedonotwanttocatchthese,letsreturnnullandlettheactualLayoutInflater//trynull}}/***将该View和需要换肤的属性集合保存起来*/privatefuninjectSkin(view:View,skinAttrs:List<SkinAttr>){valmanager=SkinManager.instancevarskinViews:MutableList<SkinView>?=manager.getSkinView(listener)if(skinViews==null){skinViews=ArrayList<SkinView>()manager.addSkinView(listener,skinViews)}skinViews.add(SkinView(view,skinAttrs))//检测当前是否需要自动换肤,如果需要则换肤if(manager.isNeedChangeSkin()){manager.skinChange(listener)}}}SkinManager.kt/***author:ALonelyCat*github:https://github.com/anjiemo/SunnyBeach*time:2021/11/19*desc:皮肤管理器,在Application中进行init初始化*/classSkinManagerprivateconstructor():LifecycleObserver{privatelateinitvarmAppContext:ApplicationprivatevarmSkinResourcesManager:SkinResourcesManager?=nullprivatevalmListeners:MutableList<ISkinChangedListener>=arrayListOf()privatevalmSkinViewMaps:MutableMap<ISkinChangedListener?,MutableList<SkinView>>=arrayMapOf()privatelateinitvarmSkinConfigFactory:SkinConfigFactoryprivatevarmCurrentPath:String=""privatevarmCurrentPkg:String=""//后缀privatevarmSuffix:String=""valresourcesManager:SkinResourcesManagerget()=if(!usePlugin()){SkinResourcesManager(mAppContext.resources,mAppContext.packageName,mSuffix)}elsemSkinResourcesManager!!/***请在Application中初始化SkinManager*SkinConfigFactory是可选项,若未指定皮肤配置工厂则使用默认皮肤工厂,该工厂使用SharedPreferences存储皮肤插件信息*/@JvmOverloadsfuninit(appContext:Application,factory:SkinConfigFactory=DefaultSkinConfigFactory(appContext)){mAppContext=appContextmSkinConfigFactory=factorytry{valpluginPath=mSkinConfigFactory.getPluginPath()valpluginPkg=mSkinConfigFactory.getPluginPkg()mSuffix=mSkinConfigFactory.getSuffix()valfile=File(pluginPath)if(file.exists()){loadPlugin(pluginPath,pluginPkg)}}catch(e:Exception){e.printStackTrace()mSkinConfigFactory.clearSkinConfig()}}/***是否已经初始化*/privatefunisInitialized()=::mAppContext.isInitialized&&::mSkinConfigFactory.isInitialized/***加载插件*/@Throws(Exception::class)funloadPlugin(skinPluginPath:String,skinPluginPkg:String){if(skinPluginPath==mCurrentPath&&skinPluginPkg==mCurrentPkg){return}valassetManager=AssetManager::class.java.newInstance()//获取addAssetPath方法valaddAssetPathMethod=assetManager.javaClass.getMethod("addAssetPath",String::class.java)//调用addAssetPath方法,第一个参数是当前对象,第二个参数是插件包的路径addAssetPathMethod.invoke(assetManager,skinPluginPath)valsuperResources=mAppContext.resourcesvaldisplayMetrics=superResources.displayMetricsvalconfiguration=superResources.configurationvalresources=Resources(assetManager,displayMetrics,configuration)mSkinResourcesManager=SkinResourcesManager(resources,skinPluginPkg)mCurrentPath=skinPluginPathmCurrentPkg=skinPluginPkg}/***获取皮肤视图*/fungetSkinView(listener:ISkinChangedListener?):MutableList<SkinView>?{returnmSkinViewMaps[listener]}/***添加皮肤视图*/funaddSkinView(listener:ISkinChangedListener?,views:MutableList<SkinView>){mSkinViewMaps[listener]=views}/***注册监听器*/funregisterListener(listener:ISkinChangedListener){mListeners.add(listener)}/***取消注册监听器,避免内存泄漏*1、移除监听回调*2、移除View集合*/fununRegisterListener(listener:ISkinChangedListener){mListeners.remove(listener)mSkinViewMaps.remove(listener)}/***换皮肤*/funchangeSkin(suffix:String):SkinManager{clearPluginInfo()mSuffix=suffixmSkinConfigFactory.saveSuffix(suffix)notifyChangedListener()returnthis}/***重置皮肤状态*/funresetSkin(){clearPluginInfo()notifyChangedListener()}/***清除皮肤插件信息*/privatefunclearPluginInfo(){mCurrentPath=""mCurrentPkg=""mSuffix=""mSkinConfigFactory.clearSkinConfig()updatePluginInfo(mCurrentPath,mCurrentPkg)}/***使用默认换肤配置*/funchangeSkin(lifecycle:Lifecycle,callback:ISkinChangingCallback?){changeSkin(SkinConfigFactory.SKIN_PLUGIN_PATH,SkinConfigFactory.SKIN_PLUGIN_PKG,lifecycle,callback)}/***改变皮肤*/funchangeSkin(skinPluginPath:String,skinPluginPkg:String,lifecycle:Lifecycle,callback:ISkinChangingCallback?){check(isInitialized()){"PleaseinitializeinApplication!"}performChangeSkin(this,skinPluginPath,skinPluginPkg,lifecycle,callback)}/***执行换肤*/privatefunperformChangeSkin(skinManager:SkinManager,pluginPath:String,pluginPkg:String,lifecycle:Lifecycle,callback:ISkinChangingCallback?){lifecycle.coroutineScope.launchWhenResumed{callback?.onStartChangeSkin()try{withContext(Dispatchers.IO){skinManager.loadPlugin(pluginPath,pluginPkg)}}catch(e:Exception){e.printStackTrace()callback?.onChangeSkinError(e)return@launchWhenResumed}skinManager.notifyChangedListener()skinManager.updatePluginInfo(pluginPath,pluginPkg)callback?.onChangeSkinComplete()}}/***保存插件信息*/privatefunupdatePluginInfo(path:String?,pkg:String?){mSkinConfigFactory.savePluginPath(path)mSkinConfigFactory.savePluginPkg(pkg)}/***通知更新*/privatefunnotifyChangedListener(){mListeners.forEach{skinChange(it)it.onSkinChanged()}}/***皮肤变了*/funskinChange(listener:ISkinChangedListener?){valskinViews=mSkinViewMaps[listener]if(skinViews==null){Timber.d("skinChange:===>skinViewsisnull")//此处必须返回,否则无法换肤成功return}skinViews.forEach{it.apply()}}/***是否需要换肤*/funisNeedChangeSkin():Boolean=usePlugin()||useSuffix()/***使用插件*/privatefunusePlugin():Boolean=mCurrentPath.trim().isNotEmpty()/***使用后缀*/privatefunuseSuffix():Boolean=mSuffix.trim().isNotEmpty()companionobject{@JvmStaticvalinstancebylazy{SkinManager()}@JvmStaticfunhookActivity(activity:AppCompatActivity,listener:ISkinChangedListener?){valinflater=LayoutInflater.from(activity)hookFactorySet(inflater)valfactory=SkinFactory(activity.delegate,listener)LayoutInflaterCompat.setFactory2(inflater,factory)}privatefunhookFactorySet(inflater:LayoutInflater){//利用反射去修改mFactorySet的值为false,防止抛出异常//IllegalStateException:AfactoryhasalreadybeensetonthisLayoutInflatertry{@SuppressLint("SoonBlockedPrivateApi")valmFactorySet=LayoutInflater::class.java.getDeclaredField("mFactorySet")mFactorySet.isAccessible=truemFactorySet[inflater]=false}catch(e:NoSuchFieldException){e.printStackTrace()}catch(e:IllegalAccessException){e.printStackTrace()}}}}SkinResourcesManager.kt/***author:ALonelyCat*github:https://github.com/anjiemo/SunnyBeach*time:2021/11/19*desc:皮肤资源管理器*/classSkinResourcesManager(privatevalresources:Resources,privatevalpkgName:String,privatevalsuffix:String=""){@SuppressLint("UseCompatLoadingForDrawables")fungetDrawableByName(resType:String?,name:String):Drawable?{Timber.d("getDrawableByName:===>pkgNameis%s",pkgName)try{valfixName=appendSuffix(name)valresId=resources.getIdentifier(fixName,resType,pkgName)Timber.d("getDrawableByName:===>resTypeis%snameis%sresIdis%s",resType,fixName,resId)returnresources.getDrawable(resId)}catch(e:NotFoundException){e.printStackTrace()}returnnull}@SuppressLint("UseCompatLoadingForColorStateLists")fungetColorByResName(resType:String?,name:String):ColorStateList?{Timber.d("getColorByResName:===>pkgNameis%s",pkgName)try{valfixName=appendSuffix(name)valresId=resources.getIdentifier(fixName,resType,pkgName)Timber.d("getColorByResName:===>resTypeis%snameis%sresIdis%s",resType,fixName,resId)returnresources.getColorStateList(resId)}catch(e:NotFoundException){e.printStackTrace()}returnnull}/***追加后缀*/privatefunappendSuffix(name:String):String{varfixName=nameif(!TextUtils.isEmpty(suffix)){fixName+="_$suffix"}returnfixName}}AppCompatActivity.kt/***author:ALonelyCat*github:https://github.com/anjiemo/SunnyBeach*time:2021/11/19*desc:AppCompatActivity支持换肤的扩展函数*//***劫持AppCompatActivity,使其拥有换肤功能,必须在AppCompatActivity的onCreate方法之前调用*/funAppCompatActivity.hookActivity(action:ISkinChangedListener){valmanager=SkinManager.instancemanager.registerListener(action)SkinManager.hookActivity(this,action)}/***取消AppCompatActivity的监听,避免内存泄漏,请在AppCompatActivity的onDestroy方法中调用*/funAppCompatActivity.removeActivityHook(action:ISkinChangedListener){valmanager=SkinManager.instancemanager.unRegisterListener(action)}引入方式将skin这个Module以Library的形式引入app的Module中,例:dependencies{implementationproject(':skin')}使用前初始化Application在Application中调用SkinManager.instance.init(this)初始化皮肤管理器。classApp:Application(){overridefunonCreate(){super.onCreate()SkinManager.instance.init(this)}}别忘了在appmodule的AndroidManifest.xml文件中注册该Application哦~<?xmlversion="1.0"encoding="utf-8"?><manifestxmlns:android="http://schemas.android.com/apk/res/android"package="cn.android52.sunnybeach.skin"><applicationandroid:name=".App"></application></manifest>Activity1、最简单的使用方式就是直接继承自SupportSkinActivity,让其作为基类,其它代码的按照正常业务进行编写即可,例:classTestActivity:SupportSkinActivity(){overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)setContentView(R.layout.test_activity)//获取SkinManager实例valmanager=SkinManager.instance//执行manager.changeSkin(lifecycle,this)}}2、在编写的基类中添加如下代码即可实现换肤功能,例:classSupportSkinActivity:AppCompatActivity(),ISkinChangedListener{overridefunonCreate(savedInstanceState:Bundle?){//该函数的调用必须在super.onCreate(savedInstanceState)之前hookActivity(this)super.onCreate(savedInstanceState)}overridefunonSkinChanged(){//皮肤变了}overridefunonStartChangeSkin(){//开始更换皮肤}overridefunonChangeSkinError(e:Exception){//更换皮肤错误}overridefunonChangeSkinComplete(){//更换皮肤完成}overridefunonDestroy(){super.onDestroy()//移除Activity的Hook,避免内存泄漏removeActivityHook(this)}}layout布局文件在布局文件中只需要在需要换肤的资源名称前添加skin_前缀即可,插件包中的资源名称与当前需要换肤的app中使用的资源名称保持一致。皮肤插件包(新建一个普通的appmodule)Tips:去除新建module时默认添加的依赖可以减小皮肤插件包的体积。将需要换肤的资源copy到该module中,然后直接签名打包成apk文件即可。为了避免用户误安装,可以将该apk的后缀进行修改,例:sunnybeach.skin
2021-11-20 00:44 · Android / 安卓 / Kotlin / 插件式换肤 / app换肤
[分享] 网易行为验证码

全新人机验证方式,高效拦截机器行为,业务安全第一道防线。搭载风险感知引擎,智能切换验证难度,安全性高,极致用户体验。读屏软件深度适配,视障群体也可轻松使用,符合工信部无障碍适配要求。

2022-03-03 11:13 · 网易 / 验证码 / 行为验证码
[文章] 22、Android开发基础之Activity之间的跳转
包括Activity的启动模式….显意图,隐意图。……我们还要学习Activity的生命周期….详细的内容大家请看视频吧!这是一个很简单的demo,教大家怎么实现界面之间的跳转!
2019-10-22 10:40 · android / activity / 四大组件 / 安卓开发
  • 1
  • 2
  • 3
  • 4
  • 5