李华明Himi 原创,转载务必在明显处注明:
转载自 【黑米GameDev街区】 原文链接:  http://www.himigame.com/android-game/331.html

很多童鞋说我的代码运行后,点击home或者back后会程序异常,如果你也这样遇到过,那么你肯定没有仔细读完Himi的博文,第十九篇Himi专门写了关于这些错误的原因和解决方法,这里我在博客都补充说明下,省的童鞋们总疑惑这一块;请点击下面联系进入阅读:

【Android游戏开发十九】(必看篇)SurfaceView运行机制详解—剖析Back与Home按键及切入后台等异常处理!

之前在【Android2D游戏开发之四】中我给大家介绍了一张13帧的png的图,利用设置可视区域的方式来实现动画效果,但是这些属于我们自己来实现动画的方式,其实Android给我们的有两类自定义动画方式:

第一类:Frame By Frame 帧动画( 不推荐游戏开发中使用)

所谓帧动画,就是顺序播放事先做好的图像,类似于放电影;

分析: 此种方式类似我之前的那种利用设置可视区域的方式来实现动画效果,不仅类似而且还不如!所以此种方式在此不予分析;

第二类:Tween Animation 渐变动画

即通过对对象不断做图像变换(平移、缩放、旋转)产生动画效果!实现方式其实就是预先定义一组指令,这些指令指定了图形变换的类型、触发时间、持续时间。这些指令可以是以 XML 文件方式定义,也可以是以源代码方式定义。程序沿着时间线执行这些指令就可以实现动画 效果。

总结:那么在Android 游戏开发中我们优先选用两种方式:第一种设置可视区域的方式来实现动画效果(帧动画),需要童鞋们手动实现,那么在之前我的博文【Android2D游戏开发之四】中已经有了相应的源码!大家可以去下载研究;那么这里就主要为大家详细分析 Tween Animation!

在讲述SurfaceView添加动画之前,我们先来看看在View中如何实现Tween Animation以及Tween 中的四种效果;

MyViewAnimation .java

package com.himi.frameAnimation; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.view.KeyEvent; import android.view.View; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.RotateAnimation; import android.view.animation.ScaleAnimation; import android.view.animation.TranslateAnimation; /** *@author Himi *@AlphaAnimation 渐变透明度动画效果 *@ScaleAnimation 渐变尺寸伸缩动画效果 *@TranslateAnimation 画面转换位置移动动画效果 *@RotateAnimation 画面转移旋转动画效果 */ public class MyViewAnimation extends View { private Paint paint; private Bitmap bmp; private int x = 50; private Animation mAlphaAnimation; private Animation mScaleAnimation; private Animation mTranslateAnimation; private Animation mRotateAnimation; public MyViewAnimation(Context context) { super(context); paint = new Paint(); paint.setAntiAlias(true); bmp = BitmapFactory.decodeResource(getResources(), R.drawable.icon); this.setFocusable(true);//只有当该View获得焦点时才会调用onKeyDown方法 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.BLACK); paint.setColor(Color.WHITE); canvas.drawText("Himi", x, 50, paint);//备注1 canvas.drawText("方向键↑ 渐变透明度动画效果", 80, this.getHeight() - 80, paint); canvas.drawText("方向键↓ 渐变尺寸伸缩动画效果", 80, this.getHeight() - 60, paint); canvas.drawText("方向键← 画面转换位置移动动画效果", 80, this.getHeight() - 40, paint); canvas.drawText("方向键→ 画面转移旋转动画效果", 80, this.getHeight() - 20, paint); canvas.drawBitmap(bmp, this.getWidth() / 2 - bmp.getWidth() / 2, this.getHeight() / 2 - bmp.getHeight() / 2, paint); x += 1; } public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {//渐变透明度动画效果 mAlphaAnimation = new AlphaAnimation(0.1f, 1.0f); //第一个参数fromAlpha 为动画开始时候透明度 //第二个参数toAlpha 为动画结束时候透明度 //注意:取值范围[0-1];[完全透明-完全不透明] mAlphaAnimation.setDuration(3000); 设置时间持续时间为3000 毫秒=3秒 this.startAnimation(mAlphaAnimation); } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {//渐变尺寸伸缩动画效果 mScaleAnimation = new ScaleAnimation(0.0f, 1.5f, 0.0f, 1.5f, Animation .RELATIVE_TO_PARENT, 0.5f, Animation.RELATIVE_TO_PARENT, 0.0f); //第一个参数fromX为动画起始时X坐标上的伸缩尺寸 //第二个参数toX为动画结束时X坐标上的伸缩尺寸 //第三个参数fromY为动画起始时Y坐标上的伸缩尺寸 //第四个参数toY 为动画结束时Y 坐标上的伸缩尺寸 //注意: //0.0表示收缩到没有 //1.0表示正常无伸缩 //值小于1.0表示收缩 //值大于1.0表示放大 //-----我这里1-4参数表明是起始图像大小不变,动画终止的时候图像被放大1.5倍 //第五个参数pivotXType 为动画在X 轴相对于物件位置类型 //第六个参数pivotXValue 为动画相对于物件的X 坐标的开始位置 //第七个参数pivotXType 为动画在Y 轴相对于物件位置类型 //第八个参数pivotYValue 为动画相对于物件的Y 坐标的开始位置 //提示:位置类型有三种,每种效果大家自己尝试哈~这里偷下懒~ //毕竟亲眼看到效果的区别才记忆深刻~ //Animation.ABSOLUTE 、Animation.RELATIVE_TO_SELF、Animation.RELATIVE_TO_PARENT mScaleAnimation.setDuration(2000); this.startAnimation(mScaleAnimation); } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {//画面转换位置移动动画效果 mTranslateAnimation = new TranslateAnimation(0, 100, 0, 100); //第一个参数fromXDelta为动画起始时X坐标上的移动位置 //第二个参数toXDelta为动画结束时X坐标上的移动位置 //第三个参数fromYDelta为动画起始时Y坐标上的移动位置 //第四个参数toYDelta 为动画结束时Y 坐标上的移动位置 mTranslateAnimation.setDuration(2000); this.startAnimation(mTranslateAnimation); } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {//画面转移旋转动画效果 mRotateAnimation = new RotateAnimation(0.0f, 360.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); //第一个参数fromDegrees为动画起始时的旋转角度 //第二个参数toDegrees 为动画旋转到的角度 //第三个参数pivotXType 为动画在X 轴相对于物件位置类型 //第四个参数pivotXValue 为动画相对于物件的X 坐标的开始位置 //第五个参数pivotXType 为动画在Y 轴相对于物件位置类型 //第六个参数pivotYValue 为动画相对于物件的Y 坐标的开始位置 mRotateAnimation.setDuration(3000); this.startAnimation(mRotateAnimation); } return super.onKeyDown(keyCode, event); } }

补充:有童鞋说对三种相对位置不太理解,那么我简单说补充下:

//Animation.ABSOLUTE 相对位置是屏幕左上角,绝对位置! //Animation.RELATIVE_TO_SELF 相对位置是自身View;取值为0,是自身左上角,取值为1是自身的右下角; //Animation.RELATIVE_TO_PARENT 相对父类View的位置

当设定了位置类型之后,会让你传入X或者Y的值,这里的X,Y可以理解成为一个点坐标!比如是旋转动画,那么这个(X,Y)就是旋转中心点!


OK,对于Tween Animation下的每种动画效果的实例化的每个参数都解释的很详细了!其实动画的实现不光用代码可以实现,在xml中注册实现也是可以的,这里就不多写了,大家可以自己去尝试写一下,那么在view中我们播放一种特效动画,只要实例化其对象,然后设置下参数,然后startAnimation()就好了,步骤很简单,只是每个动画实例化的参数确有着千变万化的改法,这些我也没法子一一来给大家演示,大家可以自己改改参数看看实际的效果!当然对于每种动画我们不光有设置播放的时候,还有一些属性和方法可以调用,比如Animation.restart()重放动画,getTransformation()此方法返回假,说明动画完成等等很多属性,请各位童鞋自定实验 o(∩_∩)o 哈哈~

顺便先解释下MyViewAnimation .java 类中onDraw()方法里的(备注1)!其实这里我是想跟大家说明下Android Animation实现机制

【启动任意一种动画效果之前 和 之后 的对比图】

            

很明显、"Himi"字样在动画开始前和开始后出现了移动,而且在MyViewAnimation.java中我没有使用Runnable接口,也没有调用刷新的函数,那么我来给各位童鞋解释下原因:

动画的每种变换其实内部都是一次矩阵运算。在Android 中,Canvas 类中包含当前矩阵,当调用 Canvas.drawBitmap (bmp, x, y, Paint) 绘制时,android 会先把 bmp 做一次矩阵运算,然后将运算的结果显示在 Canvas 上,然后不断修改 Canvas 的矩阵并刷新屏幕,View 里的对象就会不停的做图形变换,动画就形成了。

还有一点提醒大家:动画的播放是对整个游戏画布进行的操作,这一点要知道哟~

那么下面就要给大家介绍如何在我们的SurfaceView中运用Tween Animation!


MySurfaceViewAnimation.java 

package com.himi.frameAnimation; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.Log; import android.view.KeyEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.SurfaceHolder.Callback; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.RotateAnimation; import android.view.animation.ScaleAnimation; import android.view.animation.TranslateAnimation; /***@author Himi*/ public class MySurfaceViewAnimation extends SurfaceView implements Callback, Runnable {private Thread th = new Thread(this);private SurfaceHolder sfh;private Canvas canvas;private Paint paint;private Bitmap bmp;/// private Animation mAlphaAnimation; private Animation mScaleAnimation; private Animation mTranslateAnimation; private Animation mRotateAnimation; public MySurfaceViewAnimation(Context context) {super(context);Log.v("Himi", "MySurfaceView");this.setKeepScreenOn(true);bmp = BitmapFactory.decodeResource(getResources(), R.drawable.icon);sfh = this.getHolder();sfh.addCallback(this);paint = new Paint();paint.setAntiAlias(true);setFocusable(true);setFocusableInTouchMode(true); // this.setBackgroundResource(R.drawable.icon);//备注2 } public void surfaceCreated(SurfaceHolder holder) {Log.v("Himi", "surfaceCreated");th.start(); } public void draw() {try {canvas = sfh.lockCanvas();if (canvas != null) {canvas.drawColor(Color.BLACK);paint.setColor(Color.WHITE);canvas.drawText("方向键↑ 渐变透明度动画效果", 80, this.getHeight() - 80, paint);canvas.drawText("方向键↓ 渐变尺寸伸缩动画效果", 80, this.getHeight() - 60, paint);canvas.drawText("方向键← 画面转换位置移动动画效果", 80, this.getHeight() - 40, paint);canvas.drawText("方向键→ 画面转移旋转动画效果", 80, this.getHeight() - 20, paint);canvas.drawBitmap(bmp, this.getWidth() / 2 - bmp.getWidth() / 2, this.getHeight() / 2 - bmp.getHeight() / 2, paint);}} catch (Exception e) {Log.v("Himi", "draw is Error!");} finally {sfh.unlockCanvasAndPost(canvas);} } @Override public boolean onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {//渐变透明度动画效果mAlphaAnimation = new AlphaAnimation(0.1f, 1.0f);mAlphaAnimation.setDuration(3000);this.startAnimation(mAlphaAnimation);} else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {//渐变尺寸伸缩动画效果mScaleAnimation = new ScaleAnimation(0.0f, 2.0f, 1.5f, 1.5f, Animation.RELATIVE_TO_PARENT, 0.5f, Animation.RELATIVE_TO_PARENT, 0.0f);mScaleAnimation.setDuration(2000);this.startAnimation(mScaleAnimation);} else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {//画面转换位置移动动画效果mTranslateAnimation = new TranslateAnimation(0, 100, 0, 100);mTranslateAnimation.setDuration(2000);this.startAnimation(mTranslateAnimation);} else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {//画面转移旋转动画效果mRotateAnimation = new RotateAnimation(0.0f, 360.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);mRotateAnimation.setDuration(3000);this.startAnimation(mRotateAnimation);}return super.onKeyDown(keyCode, event); } public void run() {// TODO Auto-generated method stubwhile (true) {draw();try {Thread.sleep(100);} catch (Exception ex) {}} } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {Log.v("Himi", "surfaceChanged"); } public void surfaceDestroyed(SurfaceHolder holder) {Log.v("Himi", "surfaceDestroyed");} }

动画代码实现跟View中的做法一样,运行模拟器发现按键没效果,不是按键没触发是本来就存在问题, - -。但是!大家可以把此类里有一行,也就是(备注2)的注释打开,我们给设置背景图,然后在模拟器上的运行效果如下图:

很明显的看到,我们的动画正常运行了,虽然效果并不是我们想到的!但是这里可以说明一点问题:

     SurfaceView 本身具备双缓冲机制!!!!!

有些文章里说“给SurfaceView添加双缓冲”,其实是在画蛇添足 - -,而且介绍的时候拿着单线程与双线程例子来解释双缓冲更高效的实现方法;我想弱弱的问什么是双缓冲??? 如果SurfaceView不具备双缓冲,那敢问上面这张截图如何解释????

其实要实现双缓冲,只需要是新建一个Bitmap和Canvas,用这个新建的Canvas把正弦波画到新建的Bitmap,画完再通过sfh.lockCanvas获取SurfaceView对应的Canvas,用这个Canvas把新建的Bitmap画到SurfaceView上去,这才叫双缓冲; 还有双缓存和多线程没关系!

 那么View中动画的实现机制是在不断的刷屏不断的重复调用重写的onDraw()方法、而在Surfaceview的那张截图确实也正常的动画操作了,原因又何在?而且我们设置的背景图覆盖我们draw出来的字体!!效果很不理想;那么经过考虑我决定利用布局把View和SurfaceView都一并显示,用View主要去完成动画部分,(那么关于如何一并显示,或者说同时在SurfaceView中添加组件,在之前的【Android 2D开发之六】 和 【Android 2D开发之七】都有了详细讲解,那么在这里),当然一并显示也会有问题,比如我们存在了view和Surfaceiew,那么按键的时候触发的哪个?或者说如何去控制这两个View?放心,我下面就跟大家一一来讲解!

   

下面先让我们把我们的view 和 Surfaceview 先同时显示出来:【黑色的是MyView (View),白色是MySurfaceView(SurfaceView)

先上张运行截图:  (图4)


main.xml中的代码

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"> <RelativeLayoutandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_weight="1" ><com.himi.MySurfaceView android:id="@+id/view3d"android:layout_width="fill_parent"android:layout_height="fill_parent"/> <com.himi.MyView android:id="@+id/myview"android:layout_width="fill_parent"android:layout_height="fill_parent"/> </RelativeLayout> </LinearLayout>

xml中我们注册了我们自定义的view-MyView 和 SurfaceView-MySurfaceView;

需要强调的有两点:

1 : 当我们xml中注册我们的View时,我们View类中的构造函数必须要用

      public MyView(Context context, AttributeSet attrs) {} 两个参数的形式,以前的文章有讲解。

2 : 当我们在Xml中注册两个View的时候,它们显示的次序就是根据xml注册的顺序来显示,比如上面我们先注册了MySurfaceView,然后注册的MyView ,那么显示的时候会把后添加进去的MyView显示在最上层!

下面我们来看MySurfaceView.java中的代码:

package com.himi; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.SurfaceHolder.Callback; /*** * @author Himi**/ public class MySurfaceView extends SurfaceView implements Callback, Runnable {public static MySurfaceView msrv ;//----备注1private int move_x = 2, x = 20;private Thread th;private SurfaceHolder sfh;private Canvas canvas;private Paint p; public MySurfaceView(Context context, AttributeSet attrs) { super(context, attrs);msrv=this;p = new Paint(); p.setAntiAlias(true);sfh = this.getHolder();sfh.addCallback(this);th = new Thread(this);this.setKeepScreenOn(true); this.setFocusable(true);// ----备注2} public void surfaceCreated(SurfaceHolder holder) {th.start(); } public void draw() {canvas = sfh.lockCanvas();if(canvas!=null){canvas.drawColor(Color.WHITE);canvas.drawText("我是 - Surfaceview", x + move_x, 280, p);sfh.unlockCanvasAndPost(canvas);} }private void logic() { x += move_x;if (x > 200 || x < 80) {move_x = -move_x;}}@Overridepublic boolean onKeyDown(int key, KeyEvent event) { //备注2return super.onKeyDown(key, event);} public void run() {// TODO Auto-generated method stubwhile (true) {draw();logic();try {Thread.sleep(100);} catch (Exception ex) {}}} public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) { } public void surfaceDestroyed(SurfaceHolder holder) { } }

代码都很熟悉了, 主要我们来给大家解释下备注1,备注2:

备注1:

   我在两个MyView 和 MySurfaceView中都定义了本类一个静态对象,然后在初始化的时候都利用=this的形式进行了实例化;

注意:=this; 的这种实例形式要注意!只能在当前程序中仅存在一个本类对象才可使用!

       为什么要实例两个View的实例而且定义成静态,这样做主要为了类之间方便调用和操作!比如在我们这个项目中,我这样做是为了在MainActivity中去管理两个View按键焦点!下面我会给出MainActivity的代码,大家一看便知;

备注2:   

我在两个MyView 和 MySurfaceView中都对获取按键焦点注释掉了,而是在别的类中的调用其View的静态实例对象就可以任意类中对其设置!这样就可以很容易去控制到底谁来响应按键了。

这里还要强调一下:当xml中注册多个 View的时候,当我们点击按键之后,Android会先判定哪个View setFocusable(true)设置焦点了,如果都设置了,那么Android 会默认响应在xml中第一个注册的view ,而不是两个都会响应。那么为什么不同时响应呢?我解释下:

上面这截图是Android SDK Api的树状图,很明显SurfaceView继承了View,它俩是基继承关系,那么不管是子类还是基类一旦响应了按键,其基类或者父类就不会再去响应;

下面我们来看MainActivity.java:

package com.himi; import android.app.Activity; import android.os.Bundle; import android.view.KeyEvent; import android.view.Window; import android.view.WindowManager; /*** * @author Himi**/ public class MainActivity extends Activity {/** Called when the activity is first created. */ @Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);this.requestWindowFeature(Window.FEATURE_NO_TITLE);this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);setContentView(R.layout.main); MySurfaceView.msrv.setFocusable(false);//备注1MyView.mv.setFocusable(true);//备注1}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {//备注2return super.onKeyDown(keyCode, event);}}

备注1:

这里是当程序运行的时候我们默认让我们的MyView(View)来响应按键。通过类名调用对应的View实例,然后设置获取焦点的函数;

备注2:

    这里要注意:不管你在xml中注册了多少个View ,也不管View是否都设置了获取焦点,只要你在 MainActivity 中重写onKeyDown()函数,Android 就会调用此函数。

那么直接在SurfaceView中进行实现动画的想法这里没有得到很好的解决,而是我利用布局的方式来一同显示的方式,希望各位童鞋如果有好的方法,在SurfaceView中直接能使用动画的建议和想法,希望留言给我,大家一起学习 讨论,谢谢 下面给出项目源码:

源码下载地址: http://www.himigame.com/android-game/331.html

(欢迎各位童鞋订阅本博客,因为咱的更新速度可是很快的~娃哈哈)

【Android游戏开发十四】深入Animation,在SurfaceView中照样使用Android—Tween Animation!相关推荐

  1. 【Android游戏开发十四】深入Animation,在SurfaceView中照样使用Android—Tween Animation!...

    本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/331.html 之 ...

  2. 【Android游戏开发十二】(保存游戏数据 [上文])详解SharedPreference 与 FIleInputStream/FileOutputStream将数据存储到SD卡中!

     李华明Himi 原创,转载务必在明显处注明: 转载自 [黑米GameDev街区] 原文链接:  http://www.himigame.com/android-game/327.html 很多童鞋说 ...

  3. 【ANDROID游戏开发十六】ANDROID GESTURE之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!...

    本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/337.html - ...

  4. Android游戏开发十日通(7)- 开发一个双人游戏

    提要 游戏需要分享才能获得快乐,想想你以前玩过的那些游戏,那些会是真正地存在你婶婶的脑海里?是独自一人躲在被窝里酣战PSP,还是和哥们在网吧一起开黑?是一个人单刷迅龙三连,还是和朋友联机怒刷黄黑龙? ...

  5. 【Android游戏开发十八】解放手指,利用传感器开发游戏!

    本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/344.html 前 ...

  6. 【Android游戏开发十八】解放手指,利用传感器开发游戏!(本文讲解在SurfaceView中用重力传感器控制圆球的各方向移动)

    本站文章均为 李华明Himi 原创,转载务必在明显处注明:(作者新浪微博: @李华明Himi ) 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/andr ...

  7. 【Android游戏开发十六】Android Gesture之【触摸屏手势识别】操作!

    本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/337.html   ...

  8. Android游戏开发十日通(6)- 太空大战

    今天要学习的是coscos2d-x官网索引的一篇初级游戏教程.作为小白的入门,再适合不过了. 资源文件下载 工程源码下载 大师的源码 环境: lubuntu 13.10 32bit  Android ...

  9. unity3D游戏开发十四之NGUI一

    在Unity中,可以使用代码控制其自身所携带的GUI来实现图形界面的搭建.但是这些组件的搭建效率很低,而且已经无法满足现在市场对图形用户界面美感的要求,所以,引入了NGUI来增加所要开发的图形用户界面 ...

最新文章

  1. python3中format方法_python3 自定制format格式化,很多很多的内置方法。。。。。。。。。。。...
  2. 在 Delphi 下使用 DirectSound (12): 测试失真效果器 IDirectSoundFXDistortion8
  3. 手机数据抓包以及wireshark技巧
  4. 白话Elasticsearch49-深入聚合数据分析之 Percentile Ranks Aggregation-percentiles rank以及网站访问时延SLA统计
  5. 博士申请 | 美国罗格斯大学王灏助理教授招收机器学习方向博士生
  6. ssh连接阿里云服务器遇到的坑
  7. libgdx游戏引擎开发笔记(十三)SuperJumper游戏例子的讲解(篇七)----各个物体的创建及其碰撞检测...
  8. 【C语言】fgets函数返回值
  9. Confluence 6 教程:在 Confluence 中导航
  10. jquery上传 php,jQuery AJAX文件上传PHP
  11. 2021.10.13 向日葵黑屏驱动卸载方法
  12. PROFINET工业以太网教程(10)——GSD文件
  13. 睿智的目标检测7——yolo3详解及其预测代码复现
  14. SAP 采购合同案例教程金额合同前台
  15. java 量化指标_量化投资学习笔记13——各种指标的绘图、计算及交易策略
  16. 邮件传输过程,MUA,MTA,MDA的概念
  17. 安卓应用开发Socket通信 客户端+服务器端
  18. if 判断条件为纯数字
  19. 记录本地 Docker 新建镜像,推送到Daocloud
  20. 计算机指令中的操作部分指的是什么,什么是指令?计算机的指令由哪两部份组成?什么是程序?...

热门文章

  1. 论文笔记20191022-平面姿态估计
  2. 麦块我的世界怎么用java_麦块我的世界盒子怎么用-麦块我的世界盒子的使用方法...
  3. html5中表格的各种属性以及应用详细介绍
  4. Mac文字处理与页面排版Pages如何在空白地方添加下划线?
  5. Catia许可证释放及使用优化管理方案
  6. 多屏互动/无线投屏技术之—Miracast Version 2修改要点
  7. Alexa Voice Service
  8. Flask最基本示例
  9. python logger.exception_Python logger.warn方法代码示例
  10. volatile能保证有序性