Android自定义View实现数字密码锁

最近项目上用到一个密码加锁功能,需要一个数字密码界面,就想着封装成一个View来方便管理和使用。

废话不多说,先上最终效果图:

img

思路

整体可分为2个部分来实现,1.顶部是4个密码位的填充;2.数字键盘部分。整体可以是一个纵向LinearLayout,4个密码位用横向LinearLayout即可,键盘由于是宫格形式,因此可用GridLayout来布局。由于密码位和键盘数字都是以圆圈为背景,这里采用自定义一个圆形背景ImageView来使用。

实现

1.页面布局

首先定义一个圆形背景的ImageView,由于最终实现的效果是点击的时候要填充圆背景,非点击状态下是空心圆,因此可通过改变Paint的style来动态更改显示:

/** * 圆形背景ImageView(设置实心或空心) */ public class CircleImageView extends ImageView{ private Paint mPaint; private int mWidth; private int mHeight; public CircleImageView(Context context) { this(context, null); } public CircleImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } public void initView(Context context){ mPaint = new Paint(); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(mPanelColor); mPaint.setStrokeWidth(mStrokeWidth); mPaint.setAntiAlias(true); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = w; mHeight = h; } @Override public void draw(Canvas canvas) { canvas.drawCircle(mWidth/2, mHeight/2, mWidth/2 - 6, mPaint); super.draw(canvas); } /** * 设置圆为实心状态 */ public void setFillCircle(){ mPaint.setStyle(Paint.Style.FILL); invalidate(); } /** * 设置圆为空心状态 */ public void setStrokeCircle(){ mPaint.setStyle(Paint.Style.STROKE); invalidate(); } } 

可以看到,在onDraw中绘制了一个圆,默认为空心状态,定义setFillCircle和setStrokeCircle这两个方法以便外界可以方便地切换圆为实心或者空心。

圆形ImageView定义好了,开始添加密码位,布局如下:

inputResultView = new LinearLayout(context); 
for(int i=0; i<4; i++){ CircleImageView mResultItem = new CircleImageView(context); mResultIvList.add(mResultItem); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mResultIvRadius, mResultIvRadius); params.leftMargin = dip2px(context, 4); params.rightMargin = dip2px(context, 4); mResultItem.setPadding(dip2px(context, 2),dip2px(context, 2),dip2px(context, 2),dip2px(context, 2)); mResultItem.setLayoutParams(params); inputResultView.addView(mResultItem); 
} 
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 
params.gravity = Gravity.CENTER_HORIZONTAL; 
params.bottomMargin = dip2px(context, 34); 
inputResultView.setLayoutParams(params); 
addView(inputResultView); 

接着添加数字键盘部分的布局:

GridLayout numContainer = new GridLayout(context); 
numContainer.setColumnCount(3); 
for(int i=0; i<numArr.length; i++){ RelativeLayout numItem = new RelativeLayout(context); numItem.setPadding(mPaddingLeftRight,mPaddingTopBottom,mPaddingLeftRight,mPaddingTopBottom); RelativeLayout.LayoutParams gridItemParams = new RelativeLayout.LayoutParams(mNumRadius, mNumRadius); gridItemParams.addRule(CENTER_IN_PARENT); final TextView numTv = new TextView(context); numTv.setText(numArr[i]); numTv.setTextColor(mPanelColor); numTv.setTextSize(30); numTv.setGravity(Gravity.CENTER); numTv.setLayoutParams(gridItemParams); final CircleImageView numBgIv = new CircleImageView(context); numBgIv.setLayoutParams(gridItemParams); numItem.addView(numBgIv); numItem.addView(numTv); numContainer.addView(numItem); if(i == 9){ numItem.setVisibility(INVISIBLE); } 
} //删除按钮 
RelativeLayout deleteItem = new RelativeLayout(context); 
deleteItem.setPadding(mPaddingLeftRight,mPaddingTopBottom,mPaddingLeftRight,mPaddingTopBottom); 
RelativeLayout.LayoutParams gridItemParams = new RelativeLayout.LayoutParams(mNumRadius, mNumRadius); 
gridItemParams.addRule(CENTER_IN_PARENT); 
//假如删除按钮是设置自定义图片资源的话,可用注释这段 
//ImageView deleteIv = new ImageView(context); 
//deleteIv.setImageResource(R.drawable.icn_delete_pw); 
//deleteIv.setLayoutParams(gridItemParams); 
//deleteItem.addView(deleteIv); 
TextView deleteTv = new TextView(context); 
deleteTv.setText("Delete"); 
deleteTv.setTextColor(mPanelColor); 
deleteTv.setTextSize(dip2px(context, 8)); 
deleteTv.setLayoutParams(gridItemParams); 
deleteTv.setGravity(Gravity.CENTER); 
deleteItem.addView(deleteTv); 
numContainer.addView(deleteItem); LinearLayout.LayoutParams gridParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 
gridParams.gravity = Gravity.CENTER_HORIZONTAL; 
numContainer.setLayoutParams(gridParams); 
addView(numContainer); 

数字键盘这里用一个数组存数字内容,遍历添加,注意此处由于第10个的子View的时候是空白的,所以当遍历到第10个元素的时候,可以将其隐藏。遍历完后再单独添加删除按钮。

2.输入逻辑

页面布局完成了,接下来就是密码输入的逻辑部分,最终的效果是每点击一次数字,密码位就填充一个,每点击删除按钮一次,密码位就回退一个,输入4个数字之后,即完成输入,获取结果,并重置密码位。这里用一个StringBuilder变量来记录当前已输入的密码,每次添加就append进去,每次删除就调用deleteCharAt。

由于点击数字按下的时候填充,松开的时候为空心状态,所以可以在ACTION_DOWN和ACTION_UP事件中分别操作:

numTv.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: numBgIv.setFillCircle(); numTv.setTextColor(Color.WHITE); if(mPassWord.length() < 4){ mPassWord.append(numTv.getText()); mResultIvList.get(mPassWord.length()-1).setFillCircle(); if(mInputListener!=null && mPassWord.length() == 4){ //已完整输入4个 } } break; case MotionEvent.ACTION_UP: numBgIv.setStrokeCircle(); numTv.setTextColor(mPanelColor); break; } return true; } }); 

每次点击的时候,判断当前已输入的密码位是否已经超过4位,如果没超过,就继续追加。如果等于4,就说明输入完成,此时的mPassWord的内容就是最终的密码,可以用一个接口将其回调出去方便Activity中获取输入的密码:

/** * 监听输入完毕的接口 */ 
private InputListener mInputListener; public void setInputListener(InputListener mInputListener) { his.mInputListener = mInputListener; 
} public interface InputListener{ void inputFinish(String result); 
} 

然后在上面的ACTION_DOWN中输入数字等于4的时候,回调该接口:

if(mInputListener!=null && mPassWord.length() == 4){ mInputListener.inputFinish(mPassWord.toString()); 
} 

另外,删除的操作单独封装为一个方法:

/** * 删除 */ 
public void delete(){ if(mPassWord.length() == 0){ return; } mResultIvList.get(mPassWord.length()-1).setStrokeCircle(); mPassWord.deleteCharAt(mPassWord.length()-1); 
} 

**注意点:**当前无输入密码时,直接return不作任何操作,假如已有输入数字,就删除最尾部的那个数字。

最后,还要考虑一种情况,即用户输入密码错误时的一些反馈,参照平时的习惯,一般是4个密码位左右摆动并且手机震动效果,震动结束之后,当前存储的密码位重置为初始状态,如下:

/** * 输入错误的状态显示(包括震动,密码位左右摇摆效果,重置密码位) */ 
public void showErrorStatus(){ mVibrator.vibrate(new long[]{100,100,100,100},-1); List<Animator  animators = new ArrayList< (); ObjectAnimator translationXAnim = ObjectAnimator.ofFloat(inputResultView, "translationX", -50.0f,50.0f,-50.0f,0.0f); translationXAnim.setDuration(400); animators.add(translationXAnim); AnimatorSet btnSexAnimatorSet = new AnimatorSet(); btnSexAnimatorSet.playTogether(animators); btnSexAnimatorSet.start(); btnSexAnimatorSet.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { resetResult(); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); 
} 

可以看到,在onAnimationEnd中调用了resetResult,即动画结束时重置密码,resetResult方法如下:

/** * 重置密码输入 */ 
public void resetResult(){ for(int i=0; i<mResultIvList.size(); i++){ mResultIvList.get(i).setStrokeCircle(); } mPassWord.delete(0, 4); 
} 

遍历所有密码位View设置为空心,并且删除当前mPassWord变量存储的所有内容。

完整代码

完整的自定义数字密码锁代码如下:

package com.example.zjyang.viewtest.view; 
import android.animation.Animator; 
import android.animation.AnimatorSet; 
import android.animation.ObjectAnimator; 
import android.app.Service; 
import android.content.Context; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.os.Vibrator; 
import android.util.AttributeSet; 
import android.util.DisplayMetrics; 
import android.view.Gravity; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.GridLayout; 
import android.widget.ImageView; 
import android.widget.LinearLayout; 
import android.widget.RelativeLayout; 
import android.widget.TextView; 
import java.util.ArrayList; 
import java.util.List; 
import static android.widget.RelativeLayout.CENTER_HORIZONTAL; 
import static android.widget.RelativeLayout.CENTER_IN_PARENT; 
/** 
* Created by IT_ZJYANG on 2018/1/22. 
* 数字解锁键盘View 
*/ 
public class NumLockPanel extends LinearLayout { 
private String[] numArr = new String[]{"1","2","3","4","5","6","7","8","9", "", "0"}; 
private int mPaddingLeftRight; 
private int mPaddingTopBottom; 
//4个密码位ImageView 
private ArrayList<CircleImageView  mResultIvList; 
private LinearLayout inputResultView; 
//存储当前输入内容 
private StringBuilder mPassWord; 
//振动效果 
private Vibrator mVibrator; 
//整个键盘的颜色 
private int mPanelColor; 
//4个密码位的宽度 
private int mResultIvRadius; 
//数字键盘的每个圆的宽度 
private int mNumRadius; 
//每个圆的边界宽度 
private int mStrokeWidth; 
public NumLockPanel(Context context) { 
this(context, null); 
} 
public NumLockPanel(Context context, AttributeSet attrs) { 
this(context, attrs, 0); 
} 
public NumLockPanel(Context context, AttributeSet attrs, int defStyleAttr) { 
super(context, attrs, defStyleAttr); 
mPaddingLeftRight = dip2px(context, 21); 
mPaddingTopBottom = dip2px(context, 10); 
mPanelColor = Color.BLACK; //颜色代码可采用Color.parse("#000000"); 
mResultIvRadius = dip2px(context, 20); 
mNumRadius = dip2px(context, 66); 
mStrokeWidth = dip2px(context, 2); 
mVibrator = (Vibrator)context.getSystemService(Service.VIBRATOR_SERVICE); 
mResultIvList = new ArrayList< (); 
mPassWord = new StringBuilder(); 
setOrientation(VERTICAL); 
setGravity(CENTER_HORIZONTAL); 
initView(context); 
} 
public void initView(Context context){ 
//4个结果号码 
inputResultView = new LinearLayout(context); 
for(int i=0; i<4; i++){ 
CircleImageView mResultItem = new CircleImageView(context); 
mResultIvList.add(mResultItem); 
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mResultIvRadius, mResultIvRadius); 
params.leftMargin = dip2px(context, 4); 
params.rightMargin = dip2px(context, 4); 
mResultItem.setPadding(dip2px(context, 2),dip2px(context, 2),dip2px(context, 2),dip2px(context, 2)); 
mResultItem.setLayoutParams(params); 
inputResultView.addView(mResultItem); 
} 
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 
params.gravity = Gravity.CENTER_HORIZONTAL; 
params.bottomMargin = dip2px(context, 34); 
inputResultView.setLayoutParams(params); 
addView(inputResultView); 
//数字键盘 
GridLayout numContainer = new GridLayout(context); 
numContainer.setColumnCount(3); 
for(int i=0; i<numArr.length; i++){ 
RelativeLayout numItem = new RelativeLayout(context); 
numItem.setPadding(mPaddingLeftRight,mPaddingTopBottom,mPaddingLeftRight,mPaddingTopBottom); 
RelativeLayout.LayoutParams gridItemParams = new RelativeLayout.LayoutParams(mNumRadius, mNumRadius); 
gridItemParams.addRule(CENTER_IN_PARENT); 
final TextView numTv = new TextView(context); 
numTv.setText(numArr[i]); 
numTv.setTextColor(mPanelColor); 
numTv.setTextSize(30); 
numTv.setGravity(Gravity.CENTER); 
numTv.setLayoutParams(gridItemParams); 
final CircleImageView numBgIv = new CircleImageView(context); 
numBgIv.setLayoutParams(gridItemParams); 
numTv.setOnTouchListener(new OnTouchListener() { 
@Override 
public boolean onTouch(View v, MotionEvent event) { 
switch (event.getAction()){ 
case MotionEvent.ACTION_DOWN: 
numBgIv.setFillCircle(); 
numTv.setTextColor(Color.WHITE); 
if(mPassWord.length() < 4){ 
mPassWord.append(numTv.getText()); 
mResultIvList.get(mPassWord.length()-1).setFillCircle(); 
if(mInputListener!=null && mPassWord.length() == 4){ 
mInputListener.inputFinish(mPassWord.toString()); 
} 
} 
break; 
case MotionEvent.ACTION_UP: 
numBgIv.setStrokeCircle(); 
numTv.setTextColor(mPanelColor); 
break; 
} 
return true; 
} 
}); 
numItem.addView(numBgIv); 
numItem.addView(numTv); 
numContainer.addView(numItem); 
if(i == 9){ 
numItem.setVisibility(INVISIBLE); 
} 
} 
//删除按钮 
RelativeLayout deleteItem = new RelativeLayout(context); 
deleteItem.setPadding(mPaddingLeftRight,mPaddingTopBottom,mPaddingLeftRight,mPaddingTopBottom); 
RelativeLayout.LayoutParams gridItemParams = new RelativeLayout.LayoutParams(mNumRadius, mNumRadius); 
gridItemParams.addRule(CENTER_IN_PARENT); 
//假如删除按钮是设置自定义图片资源的话,可用注释这段 
//ImageView deleteIv = new ImageView(context); 
//deleteIv.setImageResource(R.drawable.icn_delete_pw); 
//deleteIv.setLayoutParams(gridItemParams); 
//deleteItem.addView(deleteIv); 
TextView deleteTv = new TextView(context); 
deleteTv.setText("Delete"); 
deleteTv.setTextColor(mPanelColor); 
deleteTv.setTextSize(dip2px(context, 8)); 
deleteTv.setLayoutParams(gridItemParams); 
deleteTv.setGravity(Gravity.CENTER); 
deleteItem.addView(deleteTv); 
numContainer.addView(deleteItem); 
deleteTv.setOnClickListener(new OnClickListener() { 
@Override 
public void onClick(View v) { 
delete(); 
} 
}); 
LinearLayout.LayoutParams gridParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 
gridParams.gravity = Gravity.CENTER_HORIZONTAL; 
numContainer.setLayoutParams(gridParams); 
addView(numContainer); 
} 
/** 
* 输入错误的状态显示(包括震动,密码位左右摇摆效果,重置密码位) 
*/ 
public void showErrorStatus(){ 
mVibrator.vibrate(new long[]{100,100,100,100},-1); 
List<Animator  animators = new ArrayList< (); 
ObjectAnimator translationXAnim = ObjectAnimator.ofFloat(inputResultView, "translationX", -50.0f,50.0f,-50.0f,0.0f); 
translationXAnim.setDuration(400); 
animators.add(translationXAnim); 
AnimatorSet btnSexAnimatorSet = new AnimatorSet(); 
btnSexAnimatorSet.playTogether(animators); 
btnSexAnimatorSet.start(); 
btnSexAnimatorSet.addListener(new Animator.AnimatorListener() { 
@Override 
public void onAnimationStart(Animator animation) { 
} 
@Override 
public void onAnimationEnd(Animator animation) { 
resetResult(); 
} 
@Override 
public void onAnimationCancel(Animator animation) { 
} 
@Override 
public void onAnimationRepeat(Animator animation) { 
} 
}); 
} 
/** 
* 删除 
*/ 
public void delete(){ 
if(mPassWord.length() == 0){ 
return; 
} 
mResultIvList.get(mPassWord.length()-1).setStrokeCircle(); 
mPassWord.deleteCharAt(mPassWord.length()-1); 
} 
/** 
* 重置密码输入 
*/ 
public void resetResult(){ 
for(int i=0; i<mResultIvList.size(); i++){ 
mResultIvList.get(i).setStrokeCircle(); 
} 
mPassWord.delete(0, 4); 
} 
/** 
* 监听输入完毕的接口 
*/ 
private InputListener mInputListener; 
public void setInputListener(InputListener mInputListener) { 
this.mInputListener = mInputListener; 
} 
public interface InputListener{ 
void inputFinish(String result); 
} 
/** 
* dip/dp转像素 
* 
* @param dipValue 
*      dip或 dp大小 
* @return 像素值 
*/ 
public static int dip2px(Context context, float dipValue) { 
DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 
return (int) (dipValue * (metrics.density) + 0.5f); 
} 
/** 
* 圆形背景ImageView(设置实心或空心) 
*/ 
public class CircleImageView extends ImageView{ 
private Paint mPaint; 
private int mWidth; 
private int mHeight; 
public CircleImageView(Context context) { 
this(context, null); 
} 
public CircleImageView(Context context, AttributeSet attrs) { 
this(context, attrs, 0); 
} 
public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) { 
super(context, attrs, defStyleAttr); 
initView(context); 
} 
public void initView(Context context){ 
mPaint = new Paint(); 
mPaint.setStyle(Paint.Style.STROKE); 
mPaint.setColor(mPanelColor); 
mPaint.setStrokeWidth(mStrokeWidth); 
mPaint.setAntiAlias(true); 
} 
@Override 
protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
super.onSizeChanged(w, h, oldw, oldh); 
mWidth = w; 
mHeight = h; 
} 
@Override 
public void draw(Canvas canvas) { 
canvas.drawCircle(mWidth/2, mHeight/2, mWidth/2 - 6, mPaint); 
super.draw(canvas); 
} 
/** 
* 设置圆为实心状态 
*/ 
public void setFillCircle(){ 
mPaint.setStyle(Paint.Style.FILL); 
invalidate(); 
} 
/** 
* 设置圆为空心状态 
*/ 
public void setStrokeCircle(){ 
mPaint.setStyle(Paint.Style.STROKE); 
invalidate(); 
} 
} 
} 

使用

在Activity的布局文件中:

<?xml version="1.0" encoding="utf-8"?  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools" 
android:id="@+id/activity_main" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:background="#ffffff" 
tools:context="com.example.zjyang.viewtest.MainActivity"  
<com.example.zjyang.viewtest.view.NumLockPanel 
android:id="@+id/num_lock" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:layout_marginTop="30dp"  
</com.example.zjyang.viewtest.view.NumLockPanel  
</RelativeLayout  

在代码中监听输入的密码结果:

public class MainActivity extends AppCompatActivity { 
private NumLockPanel mNumLockPanel; 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.activity_main); 
mNumLockPanel = (NumLockPanel) findViewById(R.id.num_lock); 
mNumLockPanel.setInputListener(new NumLockPanel.InputListener() { 
@Override 
public void inputFinish(String result) { 
//此处result即为输入结果 
Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show(); 
//错误效果示例 
mNumLockPanel.showErrorStatus(); 
} 
}); 
} 
} 

最后,在自定义View构造方法中初始化了圆圆和数字的颜色风格,以及空心圆的边界粗细大小,可根据需求自行更改。

更多Android进阶指南 可以扫码 解锁 《Android十大板块文档》

1.Android车载应用开发系统学习指南(附项目实战)

2.Android Framework学习指南,助力成为系统级开发高手

3.2023最新Android中高级面试题汇总+解析,告别零offer

4.企业级Android音视频开发学习路线+项目实战(附源码)

5.Android Jetpack从入门到精通,构建高质量UI界面

6.Flutter技术解析与实战,跨平台首要之选

7.Kotlin从入门到实战,全方面提升架构基础

8.高级Android插件化与组件化(含实战教程和源码)

9.Android 性能优化实战+360°全方面性能调优

10.Android零基础入门到精通,高手进阶之路

敲代码不易,关注一下吧。ღ( ´・ᴗ・` ) 🤔

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

ssm747普通话培训信息管理系统设计与实现(源码+调试+LW)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。今天给大家介绍一篇基于ssm普通话培训信息管…

服务质量目标:SLI,SLO,SLA

如果你要面试运维专家岗/运维架构师/运维经理/运维总监&#xff0c;面试中必然会问到的一个问题就是&#xff1a;“你能保障什么样的SLA&#xff1f;如何去实现你所保障的SLA&#xff1f;” SLA,SLO大家也许也都听说过&#xff0c;也知道几个9的含义&#xff0c;但是细致的去了…

数据结构知识点总结-线性表(3)-双向链表定义、循环单链表、、循环双向链表、静态链表、顺序表与链表的比较

双向链表定义 单链表结点中只有一个指向其后继的指针&#xff0c;这使得单链表只能从头结点依次顺序地向后遍历。若要访问某个结点的前驱结点&#xff08;插入、删除操作时&#xff09;&#xff0c;只能从头开始遍历&#xff0c;访问后继结点的时间复杂度为 O(1) &#xff0c; …

解决内嵌帆软报表出现重定向问题

最近收到反馈&#xff0c;某些程序的前端通过iframe标签内嵌finebi帆软报表时&#xff0c;出现一系列问题。 问题1: 如下图所示&#xff0c;单点登录(单点登录地址schema是https)后service地址的schema协议是http, 浏览器内核的安全策略不允许http访问https。 解决方案&#xf…

深入浅出JVM(十三)之垃圾回收算法细节

上篇文章深入浅出JVM&#xff08;十二&#xff09;之垃圾回收算法讨论了垃圾回收算法&#xff0c;为了能够更加充分的理解后续的垃圾收集器&#xff0c;本篇文章将深入浅出解析垃圾回收算法的相关细节&#xff0c;如&#xff1a;STW、枚举根节点如何避免长时间STW、安全点与安全…

计算机操作系统(慕课版)第五章学习笔记

第五章 存储器管理 1.1 存储器的层次结构 存储器的层次结构 速度由快到慢容量由小到大寄存器和主存掉电后存储的信息不再存在辅存的信息长期保存 1.2 物理地址&#xff08;绝对地址&#xff09; 物理内存的地址&#xff0c;内存以字节为单位编址 物理地址空间&#xff1a;所有…

元学习(meta-learning)的通俗解释

目录 1、什么是元学习 2、元学习还可以做什么 3、元学习是如何训练的 1、什么是元学习 meta-learning 的一个很经典的英文解释是 learn to learn&#xff0c;即学会学习。元学习是一个很宽泛的概念&#xff0c;可以有很多实现的方式&#xff0c;下面以目标检测的例子来解释…

ubuntu新建ap热点并分享

测试环境ubuntu16 1.方法1 直接手动新建ap热点 参考https://jingyan.baidu.com/article/ea24bc39b03fc6da62b331f0.html https://jingyan.baidu.com/article/363872ecd8f35d6e4ba16f97.html 亲测&#xff0c;发现电脑如果没有连有线&#xff0c;按照以上步骤并不能生成wifi热…

网络编程(JAVA)

前言&#xff1a;Java 是 Internet 上的语言&#xff0c;它从语言级上提供了对网络应用程序的支持&#xff0c;程序员能够很容易开发常见的网络应用程序。 Java 提供的网络类库&#xff0c;可以实现无痛的网络连接&#xff0c;联网的底层细节被隐藏在 Java 的本机安装系统里&a…

docker创建mongodb数据库容器

介绍 本文将通过docker创建一个mongodb数据库容器 1. 拉取mongo镜像 docker pull mongo:3.63.6版本是一个稳定的版本&#xff0c;可以选择安装此版本。 2. 创建并启动主数据库 容器数据卷配置 /docker/mongodb/master/data # 数据库数据目录&#xff08;宿主机&am…

kuka协作机器人LBR系列 issy15R930导入到ros2_rviz(带外观文件)

kuka协作机器人LBR系列 issy15R930导入到ros2_rviz(带外观文件&#xff09;外观文件未调整好&#xff0c;外观仍需进一步研究&#xff0c;外观文件dae与轮廓&#xff08;碰撞&#xff09;文件STL并未完全对应起来。在blender里面看了一下UR机器人的文件&#xff0c;是对应的&am…

产品经理学习-产品运营《什么是SOP》

目录 什么是SOP 如何执行SOP 执行SOP的重点 什么是SOP SOP就是项目流程操作的说明书 日常工作中的例行操作&#xff1a; 例行操作是指&#xff0c;在每一天&#xff0c;针对每一个用户&#xff0c;在每个项目之中&#xff0c;都必须完成的操作&#xff0c;这些必须完成的操…

数据可视化引领智慧工业新时代

在智慧工业的大潮中&#xff0c;数据可视化崭露头角&#xff0c;以其直观、清晰的方式赋能工业生产&#xff0c;为智慧工业的高效运转提供了强有力的支持。下面我就以可视化从业者的角度&#xff0c;简单聊聊这个话题。 数据可视化首先在智慧工业的生产监控中大显身手。通过将…

电脑休眠之后唤不醒

现象&#xff1a;午休时间电脑休眠了&#xff0c;醒来之后发现在密码输入界面&#xff0c;但鼠标键盘没反应。按重启键或电源机重新开机&#xff0c;结果开不了机。 原因&#xff1a;1、内存条脏了&#xff0c;导致内存条读取失败 2、休眠的时候硬盘休眠了&#xff0c;导致按…

[设计模式Java实现附plantuml源码~行为型]算法的封装与切换——策略模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…

【精选】Java面向对象进阶——静态内部类和局部内部类

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

计算机网络-后退N帧协议(弊端 滑动窗口 运行中的GBN 滑动窗口长度习题 GBN协议性能分析 )

文章目录 停等协议的弊端后退N帧协议中的滑动窗口GBN发送方必须响应的三件事GBN接受方要做的事运行中的GBN滑动窗口长度GBN协议重点总结习题1习题2GBN协议性能分析小结 停等协议的弊端 信道利用率低&#xff1a;在停等协议中&#xff0c;发送方在发送完一帧后必须等待接收方确…

面试redis篇-11Redis集群方案-哨兵

Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。哨兵的结构和作用如下: 监控:Sentinel 会不断检查您的master和slave是否按预期工作自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主通知:Sentinel充当…

递归与回溯(一)

递归 递归一定要有出口&#xff0c;不然会无限调用&#xff0c;死循环 string fun(int n){if(n0)return "a";if(n1)return "b";return fun(n - 1) fun(n - 2); }输出前8种结果&#xff1a; 双写数字递归例子 注意递归的return int doubleNum(int n){i…

git bash:ls查看文件颜色全部为白色的解决方法(已解决)

方法一&#xff1a; 修改~/.bashrc文件或者~/.profile文件&#xff0c;添加如下内容 alias lsls --colorauto 然后 source一下&#xff0c;让修改配置生效 source ~/.profile 然后再ls OK了