当前位置: 首页 > news >正文

Android中级——屏幕和绘图

屏幕和绘图

  • 屏幕
    • 系统屏幕密度
    • 独立像素密度dp
    • 单位转换
  • XML绘图(需放在Drawable)
    • Bitmap
    • Shape
    • Layer
    • Selector
  • 绘图技巧
    • Canvas
    • Layer
    • PorterDuffXfermode
    • Shader
    • PathEffect
    • SurfaceView

屏幕

  • 屏幕大小:指屏幕对角线长度,单位为寸
  • 分辨率:指屏幕宽高的像素点个数,如720x1280
  • PPI:每英寸像素(Pixels Per Inch),指对角线的像素点数除以屏幕大小,又称屏幕密度DPI(Dots Per Inch)

系统屏幕密度

不同手机的大小和像素密度都不同,为统一,定义了几个标准的DPI值

在这里插入图片描述

独立像素密度dp

相同的像素,在不同密度的屏幕上显示,长度会不同,因为高密度的屏幕包含更多像素点

  • 规定密度为mdpi(即密度值为160)时1px=1dp
  • 故上图各分辨率的换算比例为3:4:6:8:12

单位转换

如下工具类提供了px、dp、sp的互相转换

public class DisplayUtil {// dp = 像素/密度public static int px2dip(Context context, float pxValue) {float scale = context.getResources().getDisplayMetrics().density;return (int) (pxValue / scale + 0.5f);}public static int dip2px(Context context, float dipValue) {float scale = context.getResources().getDisplayMetrics().density;return (int) (dipValue * scale + 0.5f);}// sp = 像素/缩放密度public static int px2sp(Context context, float pxValue) {float fontScale = context.getResources().getDisplayMetrics().scaledDensity;return (int) (pxValue / fontScale + 0.5f);}public static int sp2px(Context context, float spValue) {float fontScale = context.getResources().getDisplayMetrics().scaledDensity;return (int) (spValue * fontScale + 0.5f);}
}

或可以使用TypedValue.applyDimension()方法

public int dp2px(int dp) {return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,getResources().getDisplayMetrics());
}public int sp2px(int sp) {return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,sp,getResources().getDisplayMetrics());
}

XML绘图(需放在Drawable)

Bitmap

如下引用图片并转为Bitmap

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"android:src="@mipmap/ic_launcher" />

Shape

Shape可实现不同类型的形状,如下实现渐变阴影

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle"><gradientandroid:angle="45"android:endColor="#805FBBFF"android:startColor="#FF5DA2FF" /><paddingandroid:bottom="7dp"android:left="7dp"android:right="7dp"android:top="7dp" /><corners android:radius="8dp" />
</shape>

效果如图

在这里插入图片描述

Layer

Layer可实现类似PS中图层的概念

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@mipmap/ic_launcher" /><itemandroid:bottom="50dp"android:drawable="@mipmap/ic_launcher"android:left="50dp"android:right="50dp"android:top="50dp" />
</layer-list>

上面两个item分别为图片进行叠加,效果如图

在这里插入图片描述

Selector

Selector实现不同事件设置反馈,如下实现修改为圆角矩形,点击后切换颜色

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:state_pressed="true"><shape android:shape="rectangle"><solid android:color="#33444444" /><corners android:radius="5dp" /><padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" /></shape></item><item><shape android:shape="rectangle"><solid android:color="#FFFFFF" /><corners android:radius="5dp" /><padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" /></shape></item>
</selector>

绘图技巧

Canvas

下面为常用的方法

  • save():将已绘制图像保存,在此之后的操作绘制在新图层
  • restore():合并图层,将save()之后绘制的图像和save()之前的合并
  • translate():坐标系平移
  • ratate():坐标系旋转

如下绘制一个时钟,通过平移、旋转坐标系简化实现

public class Clock extends View {private int mWidth;private int mHeight;public Clock(Context context) {super(context);}public Clock(Context context, AttributeSet attrs) {super(context, attrs);}public Clock(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = getMeasuredWidth();mHeight = getMeasuredHeight();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);// 绘制外圆,以(mWidth / 2, mHeight / 2)为圆形,以mWidth / 2为半径Paint paintCircle = new Paint();paintCircle.setStyle(Paint.Style.STROKE);paintCircle.setAntiAlias(true);paintCircle.setStrokeWidth(5);canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, paintCircle);// 绘制刻度Paint paintDegree = new Paint();for (int i = 0; i < 24; i++) {if (i == 0 || i == 6 || i == 12 || i == 18) {paintDegree.setStrokeWidth(5);paintDegree.setTextSize(30);canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2,mWidth / 2, mHeight / 2 - mWidth / 2 + 60,paintDegree);String degree = String.valueOf(i);canvas.drawText(degree,mWidth / 2 - paintDegree.measureText(degree) / 2,mHeight / 2 - mWidth / 2 + 90,paintDegree);} else {paintDegree.setStrokeWidth(3);paintDegree.setTextSize(15);canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2,mWidth / 2, mHeight / 2 - mWidth / 2 + 30,paintDegree);String degree = String.valueOf(i);canvas.drawText(degree,mWidth / 2 - paintDegree.measureText(degree) / 2,mHeight / 2 - mWidth / 2 + 60,paintDegree);}// 将画布以圆心旋转15°,简化坐标运算canvas.rotate(15, mWidth / 2, mHeight / 2);}// 绘制指针Paint paintHour = new Paint();paintHour.setStrokeWidth(20);Paint paintMinute = new Paint();paintMinute.setStrokeWidth(10);canvas.save();canvas.translate(mWidth / 2, mHeight / 2); // 将坐标系平移到圆点,再画指针canvas.drawLine(0, 0, 100, 100, paintHour);canvas.drawLine(0, 0, 100, 200, paintMinute);canvas.restore();}
}

Layer

图层基于栈结构,入栈后操作都发生在该图层上,出栈后则把图像绘制到上层Canvas

  • 入栈:saveLayer()、saveLayerAlpha()
  • 出栈:restore()、restoreToCount()
public class MyView extends View {private static final String TAG = MyView.class.getSimpleName();private Paint mPaint;public MyView(Context context) {this(context, null);}public MyView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MyView(Context context, AttributeSet attrs, int defStyleAttr) {this(context, attrs, defStyleAttr, 0);}public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);mPaint = new Paint();}@Overrideprotected void onDraw(Canvas canvas) {canvas.drawColor(Color.WHITE);mPaint.setColor(Color.BLUE);canvas.drawCircle(150, 150, 100, mPaint);canvas.saveLayerAlpha(0, 0, 400, 400, 127);mPaint.setColor(Color.RED);canvas.drawCircle(200, 200, 100, mPaint);canvas.restore();}
}

如下图,透明度为127的红色圆叠加在蓝色圆上方

在这里插入图片描述

PorterDuffXfermode

PorterDuffXfermod设置的是两个图层交集区域的显示方式,dst是先画的图形,而src是后画的图形,共有16种模式,如图

在这里插入图片描述

如下实现圆角图形,mOut为先画的图像,mBitmap为后画的图像,用SrcIn取交集

public class MyView extends View {private static final String TAG = MyView.class.getSimpleName();private Bitmap mBitmap;private Bitmap mOut;private Paint mPaint;public MyView(Context context) {this(context, null);}public MyView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MyView(Context context, AttributeSet attrs, int defStyleAttr) {this(context, attrs, defStyleAttr, 0);}public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);mOut = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(mOut);mPaint = new Paint();mPaint.setAntiAlias(true);canvas.drawRoundRect(0, 0, mBitmap.getWidth(), mBitmap.getHeight(), 80, 80, mPaint);mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));canvas.drawBitmap(mBitmap, 0, 0, mPaint);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawBitmap(mOut, 0, 0, null);}
}

效果如图

在这里插入图片描述

如下代码设置透明的画笔,实时获取坐标调用drawPath()涂抹上面的图层,实现刮刮乐

public class XfermodeView extends View {private Bitmap mBgBitmap, mFgBitmap;private Paint mPaint;private Canvas mCanvas;private Path mPath;public XfermodeView(Context context) {this(context, null);}public XfermodeView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public XfermodeView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mPaint = new Paint();mPaint.setAlpha(0);mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeJoin(Paint.Join.ROUND);mPaint.setStrokeWidth(50);mPaint.setStrokeCap(Paint.Cap.ROUND);mPath = new Path();mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.b);mFgBitmap = Bitmap.createBitmap(mBgBitmap.getWidth(), mBgBitmap.getHeight(), Bitmap.Config.ARGB_8888);mCanvas = new Canvas(mFgBitmap);mCanvas.drawColor(Color.GRAY);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mPath.reset();mPath.moveTo(event.getX(), event.getY());break;case MotionEvent.ACTION_MOVE:mPath.lineTo(event.getX(), event.getY());break;}mCanvas.drawPath(mPath, mPaint);invalidate();return true;}@Overrideprotected void onDraw(Canvas canvas) {canvas.drawBitmap(mBgBitmap, 0, 0, null);canvas.drawBitmap(mFgBitmap, 0, 0, null);}
}

在这里插入图片描述

Shader

用于实现渐变、渲染效果,包括

  • BitmapShader——位图Shader
  • LinnerGradient——线性Shader
  • RadialGradient——光束Shader
  • SweepGradient——梯度Shader
  • ComposeShader——混合Shader

上述渐变都有三种模式选择:

  • CLAMP:拉伸,拉伸的是图片最后一个像素,不断重复
  • REPEAT:重复,横向、纵向不断重复
  • MIRROR:镜像,横向、纵向不断翻转重复

如下,将图片填充到BitmapShader,创建一支具有图像填充功能的Paint

public class MyView extends View {private static final String TAG = MyView.class.getSimpleName();private Bitmap mBitmap;private Paint mPaint;private BitmapShader mBitmapShader;public MyView(Context context) {this(context, null);}public MyView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MyView(Context context, AttributeSet attrs, int defStyleAttr) {this(context, attrs, defStyleAttr, 0);}public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);mPaint = new Paint();mPaint.setShader(mBitmapShader);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawCircle(mBitmap.getWidth() / 2.0f, mBitmap.getHeight() / 2.0f, 50, mPaint);}
}

利用Paint在图片中心绘制圆形,效果如下

在这里插入图片描述
如下改为REPEAT,并扩大半径,可看到图片不断重复绘制

public class MyView extends View {private static final String TAG = MyView.class.getSimpleName();private Bitmap mBitmap;private Paint mPaint;private BitmapShader mBitmapShader;public MyView(Context context) {this(context, null);}public MyView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MyView(Context context, AttributeSet attrs, int defStyleAttr) {this(context, attrs, defStyleAttr, 0);}public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);mPaint = new Paint();mPaint.setShader(mBitmapShader);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawCircle(mBitmap.getWidth() / 2.0f, mBitmap.getHeight() / 2.0f, 500, mPaint);}
}

在这里插入图片描述

如下利用PorterDuffXfermode和LinnerGradient实现倒影效果的图片

public class ReflectView extends View {private Bitmap mSrcBitmap, mRefBitmap;private Paint mPaint;private PorterDuffXfermode mXfermode;public ReflectView(Context context, AttributeSet attrs) {super(context, attrs);init();}private void init() {mSrcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.b);Matrix matrix = new Matrix();matrix.setScale(1F, -1F);//垂直翻转mRefBitmap = Bitmap.createBitmap(mSrcBitmap, 0, 0,mSrcBitmap.getWidth(), mSrcBitmap.getHeight(), matrix, true);mPaint = new Paint();mPaint.setShader(new LinearGradient(0, mSrcBitmap.getHeight(),0, mSrcBitmap.getHeight() * 2,0xDD000000, 0x10000000, Shader.TileMode.REPEAT));mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.BLACK);//原图canvas.drawBitmap(mSrcBitmap, 0, 0, null);//倒影图canvas.drawBitmap(mRefBitmap, 0, mSrcBitmap.getHeight(), null);mPaint.setXfermode(mXfermode);//绘制渐变效果层canvas.drawRect(0, mRefBitmap.getHeight(), mRefBitmap.getWidth(), mSrcBitmap.getHeight() * 2, mPaint);mPaint.setXfermode(null);}
}

先将图片翻转,再添加黑色透明度递减的渐变,DST_IN是为了避免上面的图像被渐变效果遮挡

在这里插入图片描述

PathEffect

PathEffect指用各种笔触效果来绘制一个路径
在这里插入图片描述

如上,分别为

  • 无效果
  • CornerPathEffect:线段拐角圆滑
  • DiscretePathEffect:线段出现杂点
  • DashPathEffect:绘制虚线,用一个数组来设置各个点之间的间隔,还可设置偏移量实现动态路径效果
  • PathPathEffect:类似DashPathEffect,但还可设置点的图形,如上面的圆点虚线
  • ConposePathEffect:组合效果
public class MyView extends View {private static final String TAG = MyView.class.getSimpleName();private Path mPath;private PathEffect[] mPathEffect;private Paint mPaint;public MyView(Context context) {this(context, null);}public MyView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MyView(Context context, AttributeSet attrs, int defStyleAttr) {this(context, attrs, defStyleAttr, 0);}public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);mPaint = new Paint();mPaint.setStyle(Paint.Style.STROKE);mPath = new Path();mPath.moveTo(0, 0);for (int i = 0; i <= 30; i++) {mPath.lineTo(i * 35, (float) (Math.random() * 100));}mPathEffect = new PathEffect[6];mPathEffect[0] = null;mPathEffect[1] = new CornerPathEffect(30);mPathEffect[2] = new DiscretePathEffect(3.0F, 5.0F);mPathEffect[3] = new DashPathEffect(new float[]{20, 10, 5, 10}, 0);Path path = new Path();path.addRect(0, 0, 8, 8, Path.Direction.CCW);mPathEffect[4] = new PathDashPathEffect(path, 12, 0, PathDashPathEffect.Style.ROTATE);mPathEffect[5] = new ComposePathEffect(mPathEffect[3], mPathEffect[1]);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);for (PathEffect pathEffect : mPathEffect) {mPaint.setPathEffect(pathEffect);canvas.drawPath(mPath, mPaint);canvas.translate(0, 200);}}
}

SurfaceView

Android通过VSYNC信号刷新View进行屏幕的重绘,时间间隔为16ms,若在需要频繁刷新的界面上执行太多的操作逻辑,则容易阻塞主线程,造成画面卡顿

当需要频繁刷新或刷新时数据处理量比较大时,可使用SurfaceView

  • View用于主动刷新,SurfaceView用于被动刷新
  • View在主线程刷新,SurfaceView在子线程刷新
  • View绘图未使用双缓冲机制,SurfaceView则使用双缓冲机制

SurfaceView的模板代码如下,主要原理是初始化时自行创建子线程并调用draw()方法绘制

public class SurfaceViewTemplate extends SurfaceView implements SurfaceHolder.Callback, Runnable {//内部Holder,用于获取Canvas和提交绘制private SurfaceHolder mHolder;//用于控制线程的标志位private boolean mIsDrawing;//用于绘图的Canvasprivate Canvas mCanvas;public SurfaceViewTemplate(Context context) {this(context, null);}public SurfaceViewTemplate(Context context, AttributeSet attrs) {this(context, attrs, 0);}public SurfaceViewTemplate(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mHolder = getHolder();mHolder.addCallback(this);  //将自身作为回调setFocusableInTouchMode(true);setFocusable(true);this.setKeepScreenOn(true);}//创建时开启线程,调用draw()@Overridepublic void surfaceCreated(SurfaceHolder holder) {mIsDrawing = true;new Thread(this).start();}//改变时回调@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}//结束时回调@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mIsDrawing = false;}@Overridepublic void run() {while (mIsDrawing) {draw();}}private void draw() {try {mCanvas = mHolder.lockCanvas();//获取Canvas开始绘制,获取的并非新的Canvas,而是上次的} catch (Exception e) {e.printStackTrace();} finally {if (mHolder != null) {//绘制完后需提交mHolder.unlockCanvasAndPost(mCanvas);}}}
}

如下代码利用SurfaceView实现正弦函数的动态绘制

public class SurfaceViewTemplate extends SurfaceView implements SurfaceHolder.Callback, Runnable {private SurfaceHolder mHolder;private boolean mIsDrawing;private Canvas mCanvas;private int x;private int y;private Path mPath;private Paint mPaint;public SurfaceViewTemplate(Context context) {this(context, null);}public SurfaceViewTemplate(Context context, AttributeSet attrs) {this(context, attrs, 0);}public SurfaceViewTemplate(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mPath = new Path();mPaint = new Paint();mPaint.setStyle(Paint.Style.STROKE);mHolder = getHolder();mHolder.addCallback(this);setFocusableInTouchMode(true);setFocusable(true);this.setKeepScreenOn(true);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {mIsDrawing = true;new Thread(this).start();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mIsDrawing = false;}@Overridepublic void run() {while (mIsDrawing) {draw();x += 1;y = (int) (100 * Math.sin(x * 2 * Math.PI / 180) + 400);mPath.lineTo(x, y);}}private void draw() {try {mCanvas = mHolder.lockCanvas();mCanvas.drawColor(Color.WHITE); //设置背景mCanvas.drawPath(mPath, mPaint);} catch (Exception e) {e.printStackTrace();} finally {if (mHolder != null) {mHolder.unlockCanvasAndPost(mCanvas);}}}
}

效果如图

在这里插入图片描述

如下代码利用SurfaceView实现绘图板,根据手指移动绘制路径,在draw()中调用sleep()避免过度频繁绘制

在这里插入图片描述

相关文章:

Android中级——屏幕和绘图

屏幕和绘图屏幕系统屏幕密度独立像素密度dp单位转换XML绘图&#xff08;需放在Drawable&#xff09;BitmapShapeLayerSelector绘图技巧CanvasLayerPorterDuffXfermodeShaderPathEffectSurfaceView屏幕 屏幕大小&#xff1a;指屏幕对角线长度&#xff0c;单位为寸分辨率&#x…...

Linux - 第6节 - 动态库和静态库

1.静态库与动态库概念 静态库&#xff08;.a&#xff09;&#xff1a;程序在编译链接的时候把库的代码拷贝到可执行文件中。程序运行的时候将不再需要静态库。动态库&#xff08;.so&#xff09;&#xff1a;程序在运行的时候才去链接动态库的代码&#xff0c;多个程序共享使用…...

【Java学习笔记】12.Character 类及String 类

前言 本章介绍Java的Character 类和String 类。 Java Character 类 Character 类用于对单个字符进行操作。 Character 类在对象中包装一个基本类型 char 的值 实例 char ch a;// Unicode 字符表示形式 char uniChar \u039A; // 字符数组 char[] charArray { a, b, c, d…...

【C++修炼之路】26.C++11(语法糖)

每一个不曾起舞的日子都是对生命的辜负 C11C11(语法糖)本节目标一.C11简介二.统一的列表初始化2.1 {}初始化2.2 std::initializer_list三.声明3.1 auto3.2 decltype3.3 nullptr四.总结C11(语法糖) 本节目标 C11简介 列表初始化 变量类型推导 一.C11简介 在2003年C标准委员…...

KD610精密油介损体积电阻率测试仪

一、概述 KD610精密油介损体积电阻率测试仪是用于绝缘油等液体绝缘介质的介质损耗角及体积电阻率的高精密仪器。 二、产品特点 1&#xff0e;仪器内部采用数字技术&#xff0c;具备多种模式测式。 2&#xff0e;智能自动化测量。 3&#xff0e;配备了大屏幕&#xff08;2401…...

快速了解原码、反码、补码和位运算

我们知道计算机使用的是二进制&#xff0c;我们⽤⼀个字节&#xff0c;也就是8个bit 来表示⼆进制数。 原码 十进制 原码20000 0010-21000 0010 原码其实是最容易理解的&#xff0c;只不过需要利⽤⼆进制中的第⼀位来表示符号位&#xff0c;0表示正数&#xff0c;1表示…...

算法的复杂度介绍

算法的复杂度介绍 算法&#xff08;Algorithm&#xff09;是指用来操作数据、解决程序问题的一组方法。对于同一个问题&#xff0c;使用不同的算法&#xff0c;也许最终得到的结果是一样的&#xff0c;但在过程中消耗的资源和时间却会有很大的区别。 为什么要进行算法分析&…...

教你如何搭建店铺—收支管理系统,demo可分享

1、简介1.1、案例简介本文将介绍&#xff0c;如何搭建店铺-收支管理。1.2、应用场景以店铺收支管理为核心&#xff0c;维度数据分析&#xff0c;智能指导门店经营&#xff0c;账目清晰一目了然&#xff0c;店铺经营更高效。2、设置方法2.1、表单搭建1&#xff09;新建表单【客户…...

java性能分析-堆内存最佳实践-堆分析

堆内存最佳实践 优化垃圾回收器标志参数很重要但是采用更好的编程实践获得更大的性能提升 1.谨慎的创建对象并尽快的丢弃&#xff0c;是更好的内存是提高gc更好的方法 2.频繁创建某种类型的对象会导致整体的性能变差 对象复用设计 线程局部变量 每个线程中创建一个局部变量…...

3月8号作业

题目&#xff1a;题目一&#xff1a;vmlinux可执行文件如何产生题目二&#xff1a;整理内核编译流程&#xff1a;uImage&#xff0c;zImage,Image,vmlinux之间的关系答案一&#xff1a;在内核源码目录下vi Makefile&#xff0c;搜索vmlinux目标&#xff0c;vmlinux: scripts/li…...

Flink相关介绍

简介 Flink的定位是&#xff1a;Apache Flink是一个框架和分布式处理引擎&#xff0c;如图所示&#xff0c;用于对无界和有界数据流进行有状态计算。Flink被设计在所有常见的集群环境运行&#xff0c;以内存执行速度和任意规模来执行计算。 Flink 框架处理流程应用场景 1、电…...

Java 8 排序

今天分享 Java 8 进行排序的 10 个姿势&#xff0c;其实就是把 Java 8 中的 Lambda、Stream、方法引用等知识点串起来 传统排序 现在有一个 List 集合&#xff1a; public static List<User> LIST new ArrayList() {{add(new User("Lisa", 23));add(new Us…...

Blazor_WASM之4:路由

Blazor_WASM之4&#xff1a;路由 路由模板 通过 Router组件可在 Blazor 应用中路由到 Razor 组件。 Router 组件在 Blazor 应用的 App 组件中使用。App组件模板如下 <Router AppAssembly"typeof(Program).Assembly"><Found Context"routeData"…...

对Vue响应式的理解

1. 啥是响应式? &#xff08;1&#xff09;.所谓的数据响应式就是能够使数据变化可以被检测到并且对这种变化做出响应式的机制 2. 为什么vue需要响应式? &#xff08;1&#xff09;.MVVM框架中要解决的核心问题数据驱动视图&#xff0c;数据的改变引起视图的更新&#xff…...

磁盘阵列Raid探讨

最近公司买服务器&#xff0c;顺便了解一下服务器配置方面的问题 以下讨论的都是入门级服务器配置&#xff0c;全部是主观意见&#xff0c;没有任何科学依据&#xff0c;欢迎大家讨论 Raid0&#xff0c;Raid1&#xff0c;Raid10&#xff0c;Raid5&#xff0c;Raid6(Raid5热备)…...

基于MyBatis依次、批量、分页增删改查

我们知道处理数据有三种思路&#xff1a;依次、批量、分页&#xff0c;对应方法如下 依次处理&#xff1a;在 Java 里面写 for 循环&#xff0c;依次使用 SQL 语句&#xff0c;频繁连接断开数据库批量处理&#xff1a;在 MyBatis 里面用 <foreach> 拼接成一条长 SQL 语句…...

Tomcat源码分析-Session源码解析

tomcat session 设计分析 tomcat session 组件图如下所示&#xff0c;其中 Context 对应一个 webapp 应用&#xff0c;每个 webapp 有多个 HttpSessionListener&#xff0c; 并且每个应用的 session 是独立管理的&#xff0c;而 session 的创建、销毁由 Manager 组件完成&…...

常见数据模型

目录 1.1两类数据模型 1.2概念模型 1.3数据模型的组成要素 1.4常见数据模型 层次模型 网状模型 关系模型 数据模型是对现实世界数据特征的抽象&#xff0c;也就是说数据模型是用来描述数据、组织数据和对数据进行操作的。数据模型是数据库系统的核心和基础。 1.1两类数…...

Lesson 8.3 ID3、C4.5 决策树的建模流程 Lesson 8.4 CART 回归树的建模流程与 sklearn 参数详解

文章目录一、ID3 决策树的基本建模流程二、C4.5 决策树的基本建模流程1. 信息值&#xff08;information value&#xff09;2. C4.5 的连续变量处理方法三、CART 回归树的基本建模流程1. 数据准备2. 生成备选规则3. 挑选规则4. 进行多轮迭代5. 回归树的预测过程四、CART 回归树…...

阿里云手机短信登录

阿里云短信服务介绍阿里云短信服务&#xff08;Short Message Service&#xff09;是广大企业客户快速触达手机用户所优选使用的通信能力。调用API或用群发助手&#xff0c;即可发送验证码、通知类和营销类短信&#xff1b;国内验证短信秒级触达&#xff0c;到达率最高可达99%&…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...