安卓动画
最近业务太多,好久没更新。。花了两个晚上研究了一些lottie框架的实现,学到了一些思路,有机会可以把view绘制深入学习一下,ok开始。
https://github.com/airbnb/lottie-android
Lottie,Airbnb开源的一个牛逼的动画框架,绚丽的动画效果令人瞠目。
没错这在以往的意识来看是根本不可能实现的动画效果,那么究竟它是如何实现的呢?
初探
打开LottieSample工程,并将它运行起来,首页就可以看到上图中间的这个动画效果,而代码实现更是简单到没朋友。
xml:
java代码:
没错就是初始化了一个LottieAnimationView并且调用playAnimation()方法,就出现了上图的动画效果,这里注意到在xml初始化参数中有个lottie_fileName参数,传了一个貌似是json文件路径,而在assets的Logo目录下,确实有个LogoSmall.json文件,打开一看懵逼了,完全看不懂。
原来这个json文件的内容不是手写的,而是软件生成的,设计师可以使用Adobe的 After Effects(简称 AE)工具制作这个动画,在AE中安装一个叫做Bodymovin的插件,使用这个插件可以将动画效果生成一个json文件,而这个json文件通过LottieAnimationView解析并最终生成绚丽的动画效果展示在我们面前。
使用方法
Lottie supports API 14 and above,要求4.0以上
依赖
dependencies {
compile 'com.airbnb.android:lottie:1.5.1'
}
使用方法一:初始化一个LottieAnimationView
只接受这三个参数,语意清楚就不多解释了。
也可以通过java代码设置
LottieAnimationView animationView = (LottieAnimationView) findViewById(R.id.animation_view);
animationView.setAnimation("hello-world.json");
animationView.loop(true);
setAnimation有三个方法
其中String是fileName,是在assets目录下的文件,CacheStrategy表示缓存策略,
代表使用何种策略进行存储,默认为None即不存储,而使用时会优先从内存缓存中命中读取,从而减小IO开销。
JSONObject直接传入一段json数据,可以通过网络获取一段json进行解析处理。
使用方法二:使用LottieComposition
在LottieComposition中提供了三种from方法,可以接受assets文件名、json对象、流对象三种参数,Sync表示同步,但是却是包可见方法,并不能被外部调用。
LottieComposition.fromJson(getResources(), jsonObject, new LottieComposition.OnCompositionLoadedListener() {
@Override
public void onCompositionLoaded(LottieComposition composition) {
animationView.setComposition(composition);
animationView.playAnimation();
}
});
外部调用时只提供异步方法,使用AsyncTask进行异步调用,将JsonObject的解析处理过程放在异步线程处理,并将解析生成的LottieComposition对象回调主线程,因为这个json对象可能有上百k之大,所以整个处理过程的复杂度和耗时还是很高的,所以不要在ui线程中解析处理。
一点想法 :
我们可以通过请求的方式获取json对象,并将解析的过程放在网络请求的异步线程中处理,使用反射调用同步方法,将调用放在异步线程中执行,这样就可以将整个过程请求和解析的过程封装在一起。
注意点:
LottieAnimationView内部有个LottieDrawable对象,setComposition方法实质上是将LottieComposition应用到LottieDrawable上,官方readme上有这样一段说明
但应该是后面改过,LottieDrawable是包可见的,外部无法调用到,并且在LottieDrawable类注释上有这样一段描述。
推荐使用LottieAnimationView而不是直接使用LottieDrawable,因为LottieDrawable的回收LottieAnimationView帮你做了,而自己操作LottieDrawable需要考虑的回收调用。
所以仅推荐以上两种用法,不推荐直接使用Drawable的方式除非一定需要。
源码解析
好了,说完用法,要来看看到底这个过程发生了什么。
有两个重要的过程
一、json文件解析成LottieComposition的过程
所有的文件解析过程都会走到LottieComposition下的fromJsonSync方法,返回一个LottieComposition对象,中间都是对jsonObject的解析过程,将jsonObject中的信息解析到LottieComposition对象中。
static LottieComposition fromJsonSync(Resources res, JSONObject json) {
LottieComposition composition = new LottieComposition(res);
···
try {
JSONArray jsonLayers = json.getJSONArray("layers");
for (int i = 0; i < jsonLayers.length(); i++) {
Layer layer = Layer.fromJson(jsonLayers.getJSONObject(i), composition);
addLayer(composition, layer);
}
} catch (JSONException e) {
throw new IllegalStateException("Unable to find layers.", e);
}
····
return composition;
}
这段代码就是把jsonobject中的数据赋值给LottieComposition对象变量,看下图LottieComposition的变量。
bounds代表边界,start和end代表开始和结束时间,duration为时长,scale为为density。Layer就是图层的概念,里面存放的是图层的数据,在循环遍历jsonLayers生成Layer对象时调用了fromJson方法,同样的也是解析和赋值过程。
static Layer fromJson(JSONObject json, LottieComposition composition) {
Layer layer = new Layer(composition);
····
return layer;
}
以上为Layer类中的变量,除了基础变量外,会看到红框中的变量,这些变量是跟动画相关的参数,都是AnimatableValue的实现类。
AnimatableValue的继承关系如图,看样子是控制颜色、scale、path等基础动画的。
那么生成的LottieComposition对象可以理解成一个包含所有图层动画信息的对象,等下看看这些变量是如何被使用的。
二、生成LayerView树
生成的LottieComposition是通过LottieDrawable的setComposition方法将动画信息进行设置的,核心调用方法为buildLayersForComposition。
private void buildLayersForComposition(LottieComposition composition) {
···
LongSparseArray layerMap = new LongSparseArray<>(composition.getLayers().size());
List layers = new ArrayList<>(composition.getLayers().size());
LayerView maskedLayer = null;
for (int i = composition.getLayers().size() - 1; i >= 0; i--) {
Layer layer = composition.getLayers().get(i);
LayerView layerView;
if (maskedLayer == null) {
layerView =
new LayerView(layer, composition, getCallback(), mainBitmap, maskBitmap, matteBitmap);
} else {
···
layerView =
new LayerView(layer, composition, getCallback(), mainBitmapForMatte, maskBitmapForMatte,
null);
}
layerMap.put(layerView.getId(), layerView);
if (maskedLayer != null) {
maskedLayer.setMatteLayer(layerView);
maskedLayer = null;
} else {
layers.add(layerView);
if (layer.getMatteType() == Layer.MatteType.Add) {
maskedLayer = layerView;
}
}
}
for (int i = 0; i < layers.size(); i++) {
LayerView layerView = layers.get(i);
addLayer(layerView);
}
for (int i = 0; i < layerMap.size(); i++) {
long key = layerMap.keyAt(i);
LayerView layerView = layerMap.get(key);
LayerView parentLayer = layerMap.get(layerView.getLayerModel().getParentId());
if (parentLayer != null) {
layerView.setParentLayer(parentLayer);
}
}
}
将之前解析出来的Layers数据倒序遍历并生成同等数量的LayerView,将LayerView通过addLayer方法添加到layers列表里面,这段代码执行完,就生成了一个LayerView的树状结构,以LottieDrawable为根节点(LottieDrawable也是继承自AnimatableLayer,跟LayerView相同)。
void addLayer(AnimatableLayer layer) {
layer.parentLayer = this;
layers.add(layer);
layer.setProgress(progress);
invalidateSelf();
}
在LayerView的构造器中有个方法:
private void setupForModel() {
setBackgroundColor(layerModel.getSolidColor());
setBounds(0, 0, layerModel.getSolidWidth(), layerModel.getSolidHeight());
setPosition(layerModel.getPosition().createAnimation());
setAnchorPoint(layerModel.getAnchor().createAnimation());
setTransform(layerModel.getScale().createAnimation());
setRotation(layerModel.getRotation().createAnimation());
setAlpha(layerModel.getOpacity().createAnimation());
setVisible(layerModel.hasInAnimation(), false);
List reversedItems = new ArrayList<>(layerModel.getShapes());
Collections.reverse(reversedItems);
Transform currentTransform = null;
ShapeTrimPath currentTrimPath = null;
ShapeFill currentFill = null;
ShapeStroke currentStroke = null;
for (int i = 0; i < reversedItems.size(); i++) {
Object item = reversedItems.get(i);
if (item instanceof ShapeGroup) {
GroupLayerView groupLayer = new GroupLayerView((ShapeGroup) item, currentFill,
currentStroke, currentTrimPath, currentTransform, getCallback());
addLayer(groupLayer);
} else if (item instanceof ShapeTransform) {
currentTransform = (ShapeTransform) item;
} else if (item instanceof ShapeFill) {
currentFill = (ShapeFill) item;
} else if (item instanceof ShapeTrimPath) {
currentTrimPath = (ShapeTrimPath) item;
} else if (item instanceof ShapeStroke) {
currentStroke = (ShapeStroke) item;
} else if (item instanceof ShapePath) {
ShapePath shapePath = (ShapePath) item;
ShapeLayerView shapeLayer =
new ShapeLayerView(shapePath, currentFill, currentStroke, currentTrimPath,
new ShapeTransform(composition), getCallback());
addLayer(shapeLayer);
} else if (item instanceof RectangleShape) {
RectangleShape shapeRect = (RectangleShape) item;
RectLayer shapeLayer =
new RectLayer(shapeRect, currentFill, currentStroke, new ShapeTransform(composition),
getCallback());
addLayer(shapeLayer);
} else if (item instanceof CircleShape) {
CircleShape shapeCircle = (CircleShape) item;
EllipseShapeLayer shapeLayer =
new EllipseShapeLayer(shapeCircle, currentFill, currentStroke, currentTrimPath,
new ShapeTransform(composition), getCallback());
addLayer(shapeLayer);
}
}
if (maskBitmap != null && layerModel.getMasks() != null && !layerModel.getMasks().isEmpty()) {
setMask(new MaskLayer(layerModel.getMasks(), getCallback()));
maskCanvas = new Canvas(maskBitmap);
}
buildAnimations();
}
这里的layerModel就是刚才解析出来的Layer,这里用到了刚才红框圈起来的那些变量,调用了AnimatableValue的createAnimation方法,生成了一个KeyframeAnimation对象,查看KeyframeAnimation,发现是抽象类,可以看到有几个关键的变量。
首先有个AnimationListener的list,通过观察者模式修改订阅者的信息,等下看看谁是订阅者。还有个progress变量和setProgress方法,应为进度控制。
void setProgress(@FloatRange(from = 0f, to = 1f) float progress) {
if (progress < getStartDelayProgress()) {
progress = 0f;
} else if (progress > getDurationEndProgress()) {
progress = 1f;
} else {
progress = (progress - getStartDelayProgress()) / getDurationRangeProgress();
}
if (progress == this.progress) {
return;
}
this.progress = progress;
T value = getValue();
for (int i = 0; i < listeners.size(); i++) {
listeners.get(i).onValueChanged(value);
}
}
调用setProgress方法,会将getValue的结果传递给所有的订阅者。
拿ColorKeyframeAnimation的getValue的实现类为例
float percentageIntoFrame = 0;
if (!isDiscrete) {
percentageIntoFrame = (progress - startKeytime) / (endKeytime - startKeytime);
if (interpolators != null) {
percentageIntoFrame =
interpolators.get(keyframeIndex).getInterpolation(percentageIntoFrame);
}
}
int startColor = values.get(keyframeIndex);
int endColor = values.get(keyframeIndex + 1);
return (Integer) argbEvaluator.evaluate(percentageIntoFrame, startColor, endColor);
以上这段代码是getValue的具体实现,可以看到是将开始颜色和结束颜色通过progress计算一个当前进度值,并计算介于两个颜色的中间颜色。
其他类似。
最后再看一下AnimatableLayer的变量
每个图层会有自己的parentLayer,会有平移动画、透明度动画、旋转动画、位置及进度信息,这些都放在animations列表里面,同时还有个layers列表,表示当前层还会包含的一些图层信息。
所以第二步可以理解为把第一步的信息生成AnimatableLayer树的过程,包含所有的图层实现,进度控制,动画信息,都已经准备好等待被调用了。
三、动画执行
最后来说动画执行,调用了playAnimation方法,最终是调用到一个属性动画执行,
private final ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override public void onAnimationUpdate(ValueAnimator animation) {
setProgress(animation.getAnimatedFraction());
}
});
属性动画的执行是通过调用setProgress。
public void setProgress(@FloatRange(from = 0f, to = 1f) float progress) {
this.progress = progress;
for (int i = 0; i < animations.size(); i++) {
animations.get(i).setProgress(progress);
}
for (int i = 0; i < layers.size(); i++) {
layers.get(i).setProgress(progress);
}
}
刚才提到这是个树状结构,所以通过修改progress,整个树就运作起来,通过layers.setProgress设置所有子图层的progress,子图层又包含了animations和layers,每个图层的animations存放了很多的AnimatableValue,通过setProgress,将修改的value值回调订阅者,而订阅者其实就是LottieDrawable,从根节点开始invalidateSelf,调用到draw方法中进行绘制。
@Override
public void draw(@NonNull Canvas canvas) {
int saveCount = canvas.save();
applyTransformForLayer(canvas, this);
int backgroundAlpha = Color.alpha(backgroundColor);
if (backgroundAlpha != 0) {
int alpha = backgroundAlpha;
if (this.alpha != null) {
alpha = alpha * this.alpha.getValue() / 255;
}
solidBackgroundPaint.setAlpha(alpha);
if (alpha > 0) {
canvas.drawRect(getBounds(), solidBackgroundPaint);
}
}
for (int i = 0; i < layers.size(); i++) {
layers.get(i).draw(canvas);
}
canvas.restoreToCount(saveCount);
}
void applyTransformForLayer(@Nullable Canvas canvas, AnimatableLayer layer) {
if (canvas == null) {
return;
}
// TODO: Determine if these null checks are necessary.
if (layer.position != null) {
PointF position = layer.position.getValue();
if (position.x != 0 || position.y != 0) {
canvas.translate(position.x, position.y);
}
}
if (layer.rotation != null) {
float rotation = layer.rotation.getValue();
if (rotation != 0f) {
canvas.rotate(rotation);
}
}
if (layer.transform != null) {
ScaleXY scale = layer.transform.getValue();
if (scale.getScaleX() != 1f || scale.getScaleY() != 1f) {
canvas.scale(scale.getScaleX(), scale.getScaleY());
}
}
if (layer.anchorPoint != null) {
PointF anchorPoint = layer.anchorPoint.getValue();
if (anchorPoint.x != 0 || anchorPoint.y != 0) {
canvas.translate(-anchorPoint.x, -anchorPoint.y);
}
}
}
看到这里,明白了,每次value值发生变化,drawable就会重绘,所有的图层都会进行绘制,重绘时使用新的值进行绘制,从而完成了动画的变化。简单点说,就是每个progress的值,会对应每个图层中的一个状态,progress的改变,就是把这些状态不断绘制出来,从而实现了动画的效果。
一开始以为是属性动画相关,没想到深入到view的绘制,实现相当复杂,�膜拜大神。
你可能感兴趣的:(lottie-android 框架使用及源码解析)
详解DeepSeek模型底层原理及和ChatGPT区别点
瞬间动力
语言模型 机器学习 AI编程 云计算 阿里云
一、DeepSeek大模型原理架构基础DeepSeek基于Transformer架构,Transformer架构主要由编码器和解码器组成,在自然语言处理任务中,通常使用的是Transformer的解码器部分。它的核心是自注意力机制(Self-Attention),这个机制允许模型在处理输入序列时,关注序列中不同位置的信息。例如,在处理句子“Thecatchasedthemouse”时,自注意力机制
华为面试题及答案——机器学习(二)
麦当当MDD
题目挖掘 机器学习 人工智能 数据库开发 数据库 大数据
21.如何评价分类模型的优劣?(1)模型性能指标准确率(Accuracy):定义:正确分类的样本数与总样本数之比。适用:当各类样本的数量相对均衡时。精确率(Precision):定义:预测为正类的样本中实际为正类的比例。适用:当关注假阳性错误的成本较高时(例如垃圾邮件检测)。召回率(Recall):定义:实际为正类的样本中被正确预测为正类的比例。适用:当关注假阴性错误的成本较高时(例如疾病检测)。
VsCode使用
keep one's resolveY
前端 vscode ide 编辑器
vscode前端vue项目启动:Vue项目的创建启动及注意事项-CSDN博客vscode使用教程:史上最全vscode配置使用教程-夏天的思考-博客园vscode如何从git拉取代码:vscode如何从git拉取代码•Worktile社区
vue3 Teleport的使用及场景。
gxw_viva
vue3学习笔记 vue.js 前端 javascript
Vue3中的Teleport(传送门)是一个非常有用的特性,它允许你在DOM树中的任意位置动态地渲染组件。Teleport实质上是将组件的内容“传送”到指定的目标位置,而不受组件自身所在位置的限制。Teleport的使用场景包括但不限于:模态框(Modal):你可以使用Teleport将模态框的内容渲染到标签之外,以避免模态框受到父级容器CSS样式的影响,并且可以保证在层叠顺序上处于最顶层。弹出菜
【PCIe 总线及设备入门学习专栏 4.5 -- PCIe 中断 MSI 与 MSI-X 机制介绍】
主公讲 ARM
# 【PCIe Bus 专栏】 PCIe msi PCIe MSI-X PCIe 中断机制 MSI-X 中断机制 MSI 中断机制 PCI 中断
文章目录PCI设备中断机制PCIe设备中断机制PCIeMSI中断机制MSICapabilityMSI-X中断机制MSI-XcapabilityMSI-XTablePBAMSI-Xcapability解析MSI/MSI-X操作流程扫描设备配置设备MSI配置MSI-X配置中断触发与处理PCI设备中断机制以前的PCI设备是支持物理上的INTA/B/C/D中断信号,设备可以可以表明自己通过哪个引脚来发出中
vue框架使用
asuka613
前端基础知识汇总 前端 javascript vue.js
1.vue基础1.1特点渐进式框架国人开发、易学、易上手Vue的核心库只关注视图层声明式渲染组件系统1.2开发模式比较常见的三种开发模式:MVC、MVP、MVVMMVVM模式M:(model)数据对象,数据层V:(view)前端展示页面,显示层VM:(ViewModel)vue对象,逻辑层所谓的mvvm模式,通过vm层可以将v层和m层的数据进行双向绑定1.3设计模式设计模式:开发模式、发布订阅模式
Mongodb数据库的基本语法及使用
璟*
Python
数据库MongoDB(芒果数据库)数据存储阶段文件管理阶段(.txt.doc.xls)优点:数据可以长期保存可以存储大量的数据使用简单缺点:数据一致性差数据查找修改不方便数据冗余度可能比较大数据库管理阶段优点:数据组织结构化降低了冗余度提高了增删改查的效率容易扩展方便程序调用,做自动化处理缺点:需要使用sql或者其他特定的语句,相对比较复杂几个概念数据:能够输入到计算机中并被识别处理的信息集合数据
Visual Studio Code 如何编写运行 C、C++ 程序
赵孝正
其它工具 vscode c语言 c++
目录安装MinGW-w64编译器(推荐)在VSCode中配置C++开发环境参考链接在vscode上运行c++脚本,报了下面的错误,我仅仅安装了vscode及在商店里下载了插件,其它配置操作没有做,直接对一个脚本进行运行,报了下面的报错信息。正在执行任务:f:\src\g++-Wall-Wextra-g3f:\src\AnemometerTowerRecommend.cpp-of:\src\outp
C# 实现短信验证码发送:详尽步骤、代码与注释解
墨瑾轩
一起学学C#【一】 开发语言 c#
实现C#环境下短信验证码发送功能通常涉及以下几个关键步骤:选择短信服务商、集成短信发送API、生成验证码、存储验证码及有效期、发送短信以及验证用户输入的验证码。以下是一个详细的实现过程,包含代码示例和注释说明。1.选择短信服务商首先,选择一家提供短信服务的平台,如Twilio、阿里云短信服务、腾讯云短信服务等。这些服务商通常会提供API接口供开发者调用,以实现短信发送功能。2.集成短信发送API注
vue使用keep-alive缓存页面优化项目
Y18.
vue vue.js 缓存 javascript
概念keep-alive是Vue的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。keep-alive是一个抽象组件:它自身不会渲染成一个DOM元素,也不会出现在父组件链中。作用在组件切换过程中把切换出去的组件保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性参数include字符串或正则表达式。只有名称匹配的组件会被缓存。exclude字符串或正则表达
XXL-JOB完全开发手册(一篇学会XXL-JOB所有知识点)
hao_kkkkk
JAVA实战开发手册 java xxl-job
目录1、什么是XXL-JOB1.1、XXL-JOB简介1.2、XXL-JOB构成调度模块(调度中心):执行模块(执行器):任务:1.3、XXL-JOB总结编辑2、XXL-JOB原理2.1、执行器的注册和发现2.2、调度中心调用执行器调度中心的操作:执行器的操作:3、XXL-JOB能够解决哪些问题4、XXL-JOB优点特性5、XXL-JOB安装部署5.1、文档及源码5.2、调度中心部署5.2.1、初
小学生python游戏编程arcade----坦克大战4
信息化未来
助孩成长 python 游戏 word
小学生python游戏编程arcade----坦克大战4前言坦克大战41.1每单元英语单词学完升级效果1.2单词调用及敌坦克随机问题1.3效果图1.4代码实现源码获取前言接上篇文章继续解绍arcade游戏编程的基本知识。今天基本可玩了,让孩子试试坦克大战41.1每单元英语单词学完升级效果1.2单词调用及敌坦克随机问题self.scene.add_sprite_list_after(LAYER_ta
Qt的QGroupBox样式设置
水瓶丫头站住
Qt 样式表 qt 开发语言
在Qt中,可以通过样式表(QSS)为QGroupBox定制外观。以下是一些常用的样式设置方法及示例:基础样式设置QGroupBox{border:2pxsolid#FF0000;/*边框颜色*/border-radius:5px;/*圆角半径*/margin-top:1ex;/*标题与内容间距*/font-weight:bold;/*标题字体加粗*/color:#333;/*标题文字颜色*/bac
SqlServer自定义函数
呀243
sqlserver 数据库
SqlServer自定义函数参考了前辈lanxingbudui的文章SQLserver自定义函数FUNCTION的使用_sqlserverfunction-CSDN博客1.创建及调用自定义函数1.1标量值函数(返回一个值)--创建CREATEFUNCTIONfunction_name(@参数名参数类型)--传参,可空RETURNS返回值类型--返回值的数据类型ASBEGIN函数体RETURN表达式
Vue 监听器的魔法之旅:@Watch(‘form.productId’) vs @Watch(‘value’) 大揭秘!✨
小丁学Java
产品资质管理系统 vue.js 前端 javascript vue2
以下是一篇技术博客,主题围绕@Watch('form.productId')和@Watch('value')这两个watcher的功能、区别及使用场景,基于compare-form.vue的代码。准备好一起探索Vue监听器的魔法了吗?Vue监听器的魔法之旅:@Watch(‘form.productId’)vs@Watch(‘value’)大揭秘!✨嘿,Vue开发者们!你有没有在项目中遇到过“数据变
HTTP/1.1 和 HTTP/2 的区别,HTTP/2 有哪些新特性?
程序员黄同学
node.js 前端开发 JavaScript http 网络协议 网络
HTTP/1.1和HTTP/2的区别及新特性详解一、核心区别:连接管理与多路复用HTTP/1.1使用「短连接」或「持久连接」,但每个TCP连接在同一时刻只能处理一个请求(HOLBlocking)。浏览器通常通过开启多个TCP连接(6-8个)缓解阻塞,但增加了服务器压力。//HTTP/1.1下需合并资源减少请求数(但可能影响缓存)//使用工具如Webpack合并JS:module.exports={
深入理解网络通信中的关键概念:HTTP、TCP与Socket的关系及TCP的可靠性保障
guihong004
java面试题 http tcp/ip 网络协议
在网络编程和Web开发中,了解HTTP、TCP和Socket之间的关系以及TCP如何保证数据传输的可靠性是至关重要的。这些概念不仅构成了现代互联网通信的基础,而且对于优化应用性能、确保数据安全和完整性具有重要意义。本文将详细探讨HTTP、TCP和Socket三者之间的联系,解析HTTP长连接与短连接的区别,解释为什么TCP需要三次握手而不仅仅是两次,讨论TCP粘包现象产生的原因及其解决方案,并总结
【Java】数组的定义和使用
牵熊掌卖鱼
Java 数据结构 算法
目录1.数组的基本概念1.1什么是数组1.2数组的创建及初始化1.2.1数组的创建1.2.2数组的初始化1.3数组的基本使用1.3.1数组的基本使用1.3.2遍历数组2.数组是引用类型2.1基本类型变量与引用类型变量的区别2.2认识null3.数组的应用场景3.1保存数据3.2作为函数的参数3.3作为函数的返回值4.操作数据工具类Arrays与数组练习4.1数组转字符串4.2数组拷贝4.3查找数组
JavaOOP02——继承、重载与重写
搬码红绿灯
java 开发语言
目录一、继承的概念及其重要性二、继承关键字使用三、访问修饰符的作用及应用四、Object类的重要性及其方法五、this与super的理解六、方法重载与重写的区别一、继承的概念及其重要性在我们的日常生活中,有很多东西是彼此之间具有相似性的。比如,轿车和卡车都是车辆的一种,它们都具有轮胎、引擎等共同特征。在软件开发中,如果每当我们遇到类似的问题就需要从头开始编写代码的话,将会非常低效。因此,继承的概念
Java实战 | 手把手教你编写双色球模拟系统中奖逻辑(附源码解析)
北岸避凶
java 开发语言
一、引言双色球作为国内经典彩票玩法,其核心逻辑是号码匹配与中奖规则判断。本文将用Java语言实现一个简易双色球模拟系统,涵盖用户投注、随机开奖、中奖匹配等功能,并深入解析代码实现中的关键点。文末提供完整源码,适合Java初学者练手学习!二、功能概述用户投注输入6个红球(1-33)和1个蓝球(1-16),号码不可重复。随机开奖系统生成6个红球+1个蓝球作为中奖号码。中奖判断根据红球和蓝球的匹配数量,
YashanDB共享集群部署
数据库
本文内容来自YashanDB官网,原文内容请见https://doc.yashandb.com/yashandb/23.3/zh/%E5%AE%89%E8%A3%85%...本文以典型规格(2台服务器,1共享存储且包含3个及以上LUN)为例,介绍共享集群部署形态的安装步骤。执行安装部署前,请以安装用户(yashan)登录192.168.1.2服务器,并进入/home/yashan/install安
Linux 日志处理
1:find1.find基本语法find[path][expression][path]:指定从哪个目录开始搜索(默认为当前目录)。[expression]:定义搜索条件和操作。它可以包含测试条件(如文件名模式)、动作(如删除文件)以及操作符(如AND和OR)示例:查找当前目录及其子目录下的所有.txt文件:find.-name"*.txt"2.常见使用场景及示例(1)按名称查找文件查找特定名称或
深入浅出:UniApp 从入门到精通全指南
大胖丫
uni-app
https://juejin.cn/post/7440119937644101684uni-app官网本文是关于UniApp从入门到精通的全指南,涵盖基础入门(环境搭建、创建项目、项目结构、编写运行)、核心概念与进阶知识(组件与开发、页面路由与导航、数据绑定与响应式原理、生命周期钩子)、电商应用开发(商品展示、购物车、订单结算等功能)、项目优化与部署(性能、安全优化及不同平台部署)、案例分析及总结
摘录及思考《被讨厌的勇气》
智阅人生
生活 交友 学习
生活给我们各种束缚,表面看起来,这些束缚是时间的、金钱的、人际关系的,但实际上,这些束缚是心灵的。第一个束缚,来自过去。从精神分析创始人弗洛伊德开始,许多心理学家都相信人是过去、尤其是童年经历的产物,这些经历变成了潜意识,决定着我们的人生。阿德勒却告诉我们,重要的不是过去,而是你怎么看待过去,而我们对过去的看法,是可以改变的。比如,和异性谈话会脸红,这是一种典型的社交焦虑,但阿德勒告诉我们,探讨这
Qt | 窗口的显示及可见性|标题、透明度、启用/禁用|窗口标志、设置其他属性|获取窗口部件、设置父部件|鼠标光标
Qt历险记
Qt 高级开发工程师 qt QEvent QWidget QCursor
显示事件:QEvent::show,处理函数为showEvent(QShowEvent*)隐藏事件:QEvent::hide,处理函数为hideEvent(QHideEvent*)01QWidget类中与可见性有关的属性visible:bool访问函数:boolisVisible()const;virtualvoidsetVisible(boolvisible);02QWidget类中与可见性有关
qt.network.ssl: QSslSocket: cannot call unresolved function 问题解决
清海风缘
Qt qt.network.ssl
转:Qt5.4.2实现一个简单的浏览器及相关问题的解决首先,介绍一下我使用的Qt版本:QtCreator3.4.1(opensource)BasedonQt5.4.2(MSVC2013,32bit)BuiltonMay28201519:07:19运行平台为Windows。至于linux平台,以后再说吧。主要使用的是Qt中的QtWebKit和QWebView。这里Qt5做了相应的调整,可视化的QWe
安全渗透测试的全面解析与实践
软件测试 web安全
引言随着网络安全威胁的日益增加,企业和组织对自身系统的安全性提出了更高的要求。安全渗透测试(PenetrationTesting,简称渗透测试)作为主动发现和修复系统安全漏洞的重要手段,已成为安全防护体系中的关键环节。本文将深入探讨安全渗透测试的概念、流程、方法、工具及最佳实践,帮助读者全面理解渗透测试的价值与应用。一、安全渗透测试概述1.什么是安全渗透测试?安全渗透测试是一种模拟黑客攻击的安全评
PyTorch 与 NVIDIA GPU 的适配版本及安装
小赖同学啊
人工智能 pytorch 人工智能 python
PyTorch与NVIDIAGPU的适配版本需要通过CUDA和cuDNN来实现。以下是详细的安装教程,包括如何选择合适的PyTorch版本以及如何配置NVIDIAGPU环境。1.检查NVIDIAGPU和驱动1.1检查GPU型号确保你的机器上有NVIDIAGPU,并知道其型号。可以通过以下命令检查:nvidia-smi输出示例:+-----------------------------------
rabbitmq的三个交换机及简单使用
m0_71908411
rabbitmq 分布式
提前说一下,创建队列,交换机,绑定交换机和队列都是在生产者。消费者只负责监听就行了,不用配其他的。完成这个场景需要两个服务哦。1直连交换机-生产者的代码。在配置类中创建队列,交换机,绑定交换机和队列@ConfigurationpublicclassDirectRabbitConfigTest{//队列@BeanpublicQueueTestDirectQueue(){returnnewQueue(
Redis雪崩、穿透、击穿及其解决方案
Good Note
redis 数据库 缓存 开发语言 golang 面试 SQL
大家好,这里是编程Cookbook,关注公众号「编程Cookbook」,获取更多面试资料。本文先简要介绍为什么需要使用Redis,以及过期键的删除策略,进而详细介绍Redis雪崩、穿透、击穿的发生场景和解决方案。文章目录前情提要为什么使用redis?Redis的过期键删除策略数据读取流程三种问题及解决方案1.缓存雪崩2.缓存穿透3.缓存击穿对比总结历史文章MySQL数据库Redis前情提要关注公众
web前段跨域nginx代理配置
刘正强
nginx cms Web
nginx代理配置可参考server部分
server {
listen 80;
server_name localhost;
spring学习笔记
caoyong
spring
一、概述
a>、核心技术 : IOC与AOP
b>、开发为什么需要面向接口而不是实现
接口降低一个组件与整个系统的藕合程度,当该组件不满足系统需求时,可以很容易的将该组件从系统中替换掉,而不会对整个系统产生大的影响
c>、面向接口编口编程的难点在于如何对接口进行初始化,(使用工厂设计模式)
Eclipse打开workspace提示工作空间不可用
0624chenhong
eclipse
做项目的时候,难免会用到整个团队的代码,或者上一任同事创建的workspace,
1.电脑切换账号后,Eclipse打开时,会提示Eclipse对应的目录锁定,无法访问,根据提示,找到对应目录,G:\eclipse\configuration\org.eclipse.osgi\.manager,其中文件.fileTableLock提示被锁定。
解决办法,删掉.fileTableLock文件,重
Javascript 面向对面写法的必要性?
一炮送你回车库
JavaScript
现在Javascript面向对象的方式来写页面很流行,什么纯javascript的mvc框架都出来了:ember
这是javascript层的mvc框架哦,不是j2ee的mvc框架
我想说的是,javascript本来就不是一门面向对象的语言,用它写出来的面向对象的程序,本身就有些别扭,很多人提到js的面向对象首先提的是:复用性。那么我请问你写的js里有多少是可以复用的,用fu
js array对象的迭代方法
换个号韩国红果果
array
1.forEach 该方法接受一个函数作为参数, 对数组中的每个元素
使用该函数 return 语句失效
function square(num) {
print(num, num * num);
}
var nums = [1,2,3,4,5,6,7,8,9,10];
nums.forEach(square);
2.every 该方法接受一个返回值为布尔类型
对Hibernate缓存机制的理解
归来朝歌
session 一级缓存 对象持久化
在hibernate中session一级缓存机制中,有这么一种情况:
问题描述:我需要new一个对象,对它的几个字段赋值,但是有一些属性并没有进行赋值,然后调用
session.save()方法,在提交事务后,会出现这样的情况:
1:在数据库中有默认属性的字段的值为空
2:既然是持久化对象,为什么在最后对象拿不到默认属性的值?
通过调试后解决方案如下:
对于问题一,如你在数据库里设置了
WebService调用错误合集
darkranger
webservice
Java.Lang.NoClassDefFoundError: Org/Apache/Commons/Discovery/Tools/DiscoverSingleton
调用接口出错,
一个简单的WebService
import org.apache.axis.client.Call;import org.apache.axis.client.Service;
首先必不可
JSP和Servlet的中文乱码处理
aijuans
Java Web
JSP和Servlet的中文乱码处理
前几天学习了JSP和Servlet中有关中文乱码的一些问题,写成了博客,今天进行更新一下。应该是可以解决日常的乱码问题了。现在作以下总结希望对需要的人有所帮助。我也是刚学,所以有不足之处希望谅解。
一、表单提交时出现乱码:
在进行表单提交的时候,经常提交一些中文,自然就避免不了出现中文乱码的情况,对于表单来说有两种提交方式:get和post提交方式。所以
面试经典六问
atongyeye
工作 面试
题记:因为我不善沟通,所以在面试中经常碰壁,看了网上太多面试宝典,基本上不太靠谱。只好自己总结,并试着根据最近工作情况完成个人答案。以备不时之需。
以下是人事了解应聘者情况的最典型的六个问题:
1 简单自我介绍
关于这个问题,主要为了弄清两件事,一是了解应聘者的背景,二是应聘者将这些背景信息组织成合适语言的能力。
我的回答:(针对技术面试回答,如果是人事面试,可以就掌
contentResolver.query()参数详解
百合不是茶
android query()详解
收藏csdn的博客,介绍的比较详细,新手值得一看 1.获取联系人姓名
一个简单的例子,这个函数获取设备上所有的联系人ID和联系人NAME。
[java]
view plain
copy
public void fetchAllContacts() {
ora-00054:resource busy and acquire with nowait specified解决方法
bijian1013
oracle 数据库 kill nowait
当某个数据库用户在数据库中插入、更新、删除一个表的数据,或者增加一个表的主键时或者表的索引时,常常会出现ora-00054:resource busy and acquire with nowait specified这样的错误。主要是因为有事务正在执行(或者事务已经被锁),所有导致执行不成功。
1.下面的语句
web 开发乱码
征客丶
spring Web
以下前端都是 utf-8 字符集编码
一、后台接收
1.1、 get 请求乱码
get 请求中,请求参数在请求头中;
乱码解决方法:
a、通过在web 服务器中配置编码格式:tomcat 中,在 Connector 中添加URIEncoding="UTF-8";
1.2、post 请求乱码
post 请求中,请求参数分两部份,
1.2.1、url?参数,
【Spark十六】: Spark SQL第二部分数据源和注册表的几种方式
bit1129
spark
Spark SQL数据源和表的Schema
case class
apply schema
parquet
json
JSON数据源 准备源数据
{"name":"Jack", "age": 12, "addr":{"city":"beijing&
JVM学习之:调优总结 -Xms -Xmx -Xmn -Xss
BlueSkator
-Xss -Xmn -Xms -Xmx
堆大小设置JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制;系统的可用虚拟内存限制;系统的可用物理内存限制。32位系统下,一般限制在1.5G~2G;64为操作系统对内存无限制。我在Windows Server 2003 系统,3.5G物理内存,JDK5.0下测试,最大可设置为1478m。典型设置:
java -Xmx355
jqGrid 各种参数 详解(转帖)
BreakingBad
jqGrid
jqGrid 各种参数 详解 分类:
源代码分享
个人随笔请勿参考
解决开发问题 2012-05-09 20:29 84282人阅读
评论(22)
收藏
举报
jquery
服务器
parameters
function
ajax
string
读《研磨设计模式》-代码笔记-代理模式-Proxy
bylijinnan
java 设计模式
声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
* 下面
应用升级iOS8中遇到的一些问题
chenhbc
ios8 升级iOS8
1、很奇怪的问题,登录界面,有一个判断,如果不存在某个值,则跳转到设置界面,ios8之前的系统都可以正常跳转,iOS8中代码已经执行到下一个界面了,但界面并没有跳转过去,而且这个值如果设置过的话,也是可以正常跳转过去的,这个问题纠结了两天多,之前的判断我是在
-(void)viewWillAppear:(BOOL)animated
中写的,最终的解决办法是把判断写在
-(void
工作流与自组织的关系?
comsci
设计模式 工作
目前的工作流系统中的节点及其相互之间的连接是事先根据管理的实际需要而绘制好的,这种固定的模式在实际的运用中会受到很多限制,特别是节点之间的依存关系是固定的,节点的处理不考虑到流程整体的运行情况,细节和整体间的关系是脱节的,那么我们提出一个新的观点,一个流程是否可以通过节点的自组织运动来自动生成呢?这种流程有什么实际意义呢?
这里有篇论文,摘要是:“针对网格中的服务
Oracle11.2新特性之INSERT提示IGNORE_ROW_ON_DUPKEY_INDEX
daizj
oracle
insert提示IGNORE_ROW_ON_DUPKEY_INDEX
转自:http://space.itpub.net/18922393/viewspace-752123
在 insert into tablea ...select * from tableb中,如果存在唯一约束,会导致整个insert操作失败。使用IGNORE_ROW_ON_DUPKEY_INDEX提示,会忽略唯一
二叉树:堆
dieslrae
二叉树
这里说的堆其实是一个完全二叉树,每个节点都不小于自己的子节点,不要跟jvm的堆搞混了.由于是完全二叉树,可以用数组来构建.用数组构建树的规则很简单:
一个节点的父节点下标为: (当前下标 - 1)/2
一个节点的左节点下标为: 当前下标 * 2 + 1
&
C语言学习八结构体
dcj3sjt126com
c
为什么需要结构体,看代码
# include <stdio.h>
struct Student //定义一个学生类型,里面有age, score, sex, 然后可以定义这个类型的变量
{
int age;
float score;
char sex;
}
int main(void)
{
struct Student st = {80, 66.6,
centos安装golang
dcj3sjt126com
centos
#在国内镜像下载二进制包
wget -c http://www.golangtc.com/static/go/go1.4.1.linux-amd64.tar.gz
tar -C /usr/local -xzf go1.4.1.linux-amd64.tar.gz
#把golang的bin目录加入全局环境变量
cat >>/etc/profile<
10.性能优化-监控-MySQL慢查询
frank1234
性能优化 MySQL慢查询
1.记录慢查询配置
show variables where variable_name like 'slow%' ; --查看默认日志路径
查询结果:--不用的机器可能不同
slow_query_log_file=/var/lib/mysql/centos-slow.log
修改mysqld配置文件:/usr /my.cnf[一般在/etc/my.cnf,本机在/user/my.cn
Java父类取得子类类名
happyqing
java this 父类 子类 类名
在继承关系中,不管父类还是子类,这些类里面的this都代表了最终new出来的那个类的实例对象,所以在父类中你可以用this获取到子类的信息!
package com.urthinker.module.test;
import org.junit.Test;
abstract class BaseDao<T> {
public void
Spring3.2新注解@ControllerAdvice
jinnianshilongnian
@Controller
@ControllerAdvice,是spring3.2提供的新注解,从名字上可以看出大体意思是控制器增强。让我们先看看@ControllerAdvice的实现:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Co
Java spring mvc多数据源配置
liuxihope
spring
转自:http://www.itpub.net/thread-1906608-1-1.html
1、首先配置两个数据库
<bean id="dataSourceA" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close&quo
第12章 Ajax(下)
onestopweb
Ajax
index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/
BW / Universe Mappings
blueoxygen
BO
BW Element
OLAP Universe Element
Cube Dimension
Class
Charateristic
A class with dimension and detail objects (Detail objects for key and desription)
Hi
Java开发熟手该当心的11个错误
tomcat_oracle
java 多线程 工作 单元测试
#1、不在属性文件或XML文件中外化配置属性。比如,没有把批处理使用的线程数设置成可在属性文件中配置。你的批处理程序无论在DEV环境中,还是UAT(用户验收
测试)环境中,都可以顺畅无阻地运行,但是一旦部署在PROD 上,把它作为多线程程序处理更大的数据集时,就会抛出IOException,原因可能是JDBC驱动版本不同,也可能是#2中讨论的问题。如果线程数目 可以在属性文件中配置,那么使它成为
推行国产操作系统的优劣
yananay
windows linux 国产操作系统
最近刮起了一股风,就是去“国外货”。从应用程序开始,到基础的系统,数据库,现在已经刮到操作系统了。原因就是“棱镜计划”,使我们终于认识到了国外货的危害,开始重视起了信息安全。操作系统是计算机的灵魂。既然是灵魂,为了信息安全,那我们就自然要使用和推行国货。可是,一味地推行,是否就一定正确呢?
先说说信息安全。其实从很早以来大家就在讨论信息安全。很多年以前,就据传某世界级的网络设备制造商生产的交