全部 文章 问答 分享 共找到131个相关内容
[文章] 23、Android开发基础之通过意图来实现界面的跳转
Android开发基础之通过意图来实现界面的跳转在上一节课里头,我们通过显意图来实现界面的跳转。什么是显意图?什么是意图
2019-10-22 10:45 · activity / 安卓 / 显示意图 / 隐式意图 / android
[问答] 学习Activity 无法跳转到第三方页面 完全按照视频教程 APP闪退求解决

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


意图

2021-08-12 17:42 · Activity

[文章] 22、Android开发基础之Activity之间的跳转
包括Activity的启动模式….显意图意图。……我们还要学习Activity的生命周期….详细的内容大家请看视频吧!这是一个很简单的demo,教大家怎么实现界面之间的跳转!
2019-10-22 10:40 · android / activity / 四大组件 / 安卓开发
[文章] 初学组件一 Activity
//跳转到另外一个activity,通过显示意图intent指定的class类。
2021-09-16 17:44 · android
[文章] Android 实现沉浸状态
本文使用Andorid10@TOC前言简单三步实现沉浸状态栏一、什么是沉浸状态栏?实质上就是使手机状态栏的颜色改变。使其成为自己想要的颜色。假设把它设置成和APP主色调同样。
2022-09-29 16:15 · android / 安卓 / 沉浸式状态栏
[问答] 通过显示意图跳转第三方应用出现问题
通过显示意图跳转短信或者浏览器时崩溃,显示错误显示activity没有注册请问大佬们这个问题怎么解决啊
2020-04-02 21:03 · Android四大组件之activity
[文章] 分布信号量(Redis)
分布信号量是一种在分布环境中用于控制并发访问资源的机制,通常基于像Redis这样的分布键值存储系统实现。在单机环境下,信号量是一个同步原语,用于限制同时访问特定资源的进程数或者线程数。
2024-01-25 12:08 · redis / 信号量 / 计数器
[文章] Final 关键字深入解析
Java中final关键字可以修饰类,方法,变量修饰类:表示类是不可以被继承的,所有的成员方法都会被指定为final方法修饰方法:表示方法不可以重写,但是可以重载主要为了防止子类修改父类的方法修饰变量
2020-09-04 13:19 · Java / final关键字
[文章] 初识Python之Selenium操作浏览器
初识Python之Selenium操作浏览器由于Python安装是傻瓜的,比较简单。So,我就不讲了。
[问答] 大佬们请教个分布并发编程的问题
如果要给修改钱包,修改订单,修改库存三个方法加分布锁,最后,给paySuccess再加一个分布锁锁住所有这个支付订单相关的资源,这种做法是不是不正确。或者有什么其他的思路?
2023-11-16 11:17 · 后端 / 高并发
[问答] 【每日面试题】懒汉的单例为什么要使用double check?
懒汉的单例为什么要使用doublecheck?单例,我们知道有懒汉和饿汉!为什么懒汉要进行doublecheck呢?相关问题:如果使用静态内部类的方式创建单例,有什么好处?(为什么要这么做?)
2020-11-06 16:36 · 每日面试题
[文章] Android5.1格化sd卡AOSP
Android5.1格化sd卡AOSP今天下午在做一个格式化的,看了一下系统的API,实现了。分享给大家吧。
2019-10-04 17:33 · AOSP / 安卓 / 系统移植 / 系统开发 / 裁剪系统
[文章] 30、Android开发基础之服务Service
在配置文件里配置如下:<serviceandroid:name=".FirstService"></service>以前我们在学习Activity的时候,就知道显示意图意图
2019-10-22 19:12 · 服务 / service / 四大组件 / 安卓开发 / android
[文章] git分布版本控制的介绍以及安装
1、版本控制工具的介绍以及功能1.1、协调开发git是分布的代码管理平台,通过配置属性进行代码托管,从而进行协调开发。
1970-01-01 00:00 · git / git安装 / 版本控制
[文章] 25、Android开发基础之Activity之间数据回传
实现分析首先,我们还是一样,要打开Activity,先创建意图对象。如果是第三方的那么就用意图,自己的就用显示意图
[文章] 分布ID生成-雪花算法SnowflakeIdWorker
分布ID生成-雪花算法SnowflakeIdWorker我们生成ID的方式有多种,比如说UUID,比如说自动增长...但是,随着业务的增长与用户数量的增长,这就满足不了需求了。
2020-02-01 16:27 · 雪花算法 / 随机数 / ID / 算法 / 分布式
[文章] TypeScript学习-什么是TypeScript
弱类型语言类型系统按照是否允许类型转换来分类,可以分为强类型和弱类型。
2021-12-24 17:29 · TypeScript / 前端
[文章] 【android学习笔记二】mySQL学习笔记
mySQL学习笔记基础篇启动服务以管理员运行CMD(普通运行会报错)输入命令:netstartmysql登录mysql密码显登录:mysql-hlocalhost-uroot-ppassword密码登录
2020-02-13 16:12 · 学习笔记 / android / mysql
[文章] kotlin中构造方法,compain object ,init ,lazy代码块的加载顺序探究
里面的代码块只会执行一次,且优先级最高,最先被加载2.加载顺序为伴生对象====》init代码块====》大于次级构造方法反编译一下程序1.在反编译代码,我们发现了红色框中,次级构造方法,在没有主构造方法的情况下会调用
2022-05-11 16:19 · Android / kotlin
[分享] Android上层应用源代码
我们需要去阅读源码,查看里的意图过滤规则。这个链接就是Android上层应用的源码。拿去吧...
2019-10-27 22:04 · 安卓 / 源码 / 应用 / android / app
[文章] Swift快速入门常量和变量(2)
常量letsex="男"//如果放在一行,应该添加分号letname="Jack";varage=18//常量和变量的声明可以显示指定类型,用':'隔开;也可以不指定类型
2020-09-14 22:53 · Swift
[文章] 水一篇:尝试用分布跑密码字典
那么针对单个网站,我们其实可以对响应进行去重,具体的日志只记录响应的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 / 文件服务器
[文章] 安卓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 · 网易 / 验证码 / 行为验证码
[文章] 24、Android开发基础之组件之间的数据传输
基本数据类型的传输前面我们要跳转的话需要创建一个意图对象,也就是Intent。这个Intent其实就是我们数据的载体,我们把数据扔intent里面。
[文章] Docker创建Mysql容器
创建容器docker-composeup[-d]-d选填,如果有-d则为守护运行,可以先看看有没有出错,再守护运行。
2020-09-03 17:53 · mysql / docker
[文章] Kotlin基础学习2
Lambda编程——集合的函数API入门介绍想也知道,函数API多的一批。这里我们就简单了解一些简单的函数API,主要是为了学习Lambda表达式的语法结构。
2020-08-06 15:15 · Kotlin / 基础
  • 1
  • 2
  • 3
  • 4
  • 5