Android应用开发(35)SufaceView基本用法

2023-11-19

Android应用开发学习笔记——目录索引

 参考Android官网:https://developer.android.com/reference/android/view/SurfaceView

一、SurfaceView简介

SurfaceView派生自View,提供嵌入视图层次结构内部的专用绘图表面,SurfaceView可以在主线程之外的线程中向屏幕绘图,这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。

通过 SurfaceHolder 接口提供对Surface的访问,调用getHolder()方法获取SurfaceHolder。

实现SurfaceHolder.Callback回调接口,回调是通过 SurfaceHolder.addCallback方法设置。

SurfaceHolder.Callback中定义了三个接口方法:

SurfaceHolder.Callback#surfaceCreated  // 当首次创建surface后立即调用。
SurfaceHolder.Callback#surfaceChanged  //当surface进行任何更改立即调用此方法。
​SurfaceHolder.Callback#surfaceDestroyed  //当surface即将被破坏之前调用的。

//当surface对象创建后,该方法就会被立即调用。 
public voidsurfaceCreated(SurfaceHolder holder)   {  
             
}  

//当surface发生任何结构性的变化时(格式或者大小),该方法就会被立即调用。
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, intarg3) {  

}  
      
//当surface对象在将要销毁前,该方法会被立即调用。   
public voidsurfaceDestroyed(SurfaceHolder holder)  {  

}  

什么是Surface?简单的说Surface对应了一块屏幕缓冲区,每个window对应一个Surface,任何View都要画在Surface的Canvas(画布)上。传统的view共享一块屏幕缓冲区,所有的绘制必须在UI线程中进行。
在SDK的文档中,对Surface的描述是这样的:“Handle onto a raw buffer that is being managed by the screen compositor”,翻译成中文就是“由屏幕显示内容合成器(screen compositor)所管理的原始缓冲区的句柄”,这句话包括下面两个意思:
1、通过Surface就可以获得原生缓冲器以及其中的内容(因为Surface是句柄)。就像在C++语言中,可以通过一个文件的句柄,就可以获得文件的内容一样。
2、原始缓冲区(a raw buffer)是用于保存当前窗口的像素数据的。引伸地,可以认为Android中的Surface就是一个用来画图形(graphics)或图像(image)的涂鸦场所。由此,可以推知一个Surface对象中应该包含有一个Canvas(画布)对象。
因此,在前面提及的两个意思的基础上,可以再加上一条:
3、Surface中有一个Canvas成员,专门用于画图的。
由以上的概括,我们总结如下:Surface中的Canvas成员,是专门用于供程序员画图的场所,就像黑板一样;其中的原始缓冲区是用来保存数据的地方;Surface本身的作用类似一个句柄,得到了这个句柄就可以得到其中的Canvas、原始缓冲区以及其它方面的内容。
Surface是用来管理数据的(句柄),在这里“数据”指的就是画板的内容。。

SurfaceView 的 Public 方法

void applyTransactionToFrame(SurfaceControl.Transaction transaction)

添加一个事务,该事务将与显示 SurfaceView 的下一帧同步应用。

void draw(Canvas canvas)

手动将此视图(及其所有子视图)渲染到给定的画布。

boolean gatherTransparentRegion(Region region)

当视图层次结构包含一个或多个 SurfaceView 时,ViewRoot 使用它来执行优化。

SurfaceHolder getHolder()

返回 SurfaceHolder,提供对此 SurfaceView 底层表面的访问和控制。

IBinder getHostToken()

用于构造 的令牌SurfaceControlViewHost

int getImportantForAccessibility()

获取用于确定此 View 对于可访问性是否重要的​​模式。

SurfaceControl getSurfaceControl()

返回一个 SurfaceControl,可用于将 Surface 设为此 SurfaceView 的父级。

boolean hasOverlappingRendering()

返回此视图是否有重叠的内容。

void setAlpha(float alpha)

将视图的不透明度设置为 0 到 1 之间的值,其中 0 表示视图完全透明,1 表示视图完全不透明。

void setChildSurfacePackage(SurfaceControlViewHost.SurfacePackage p)

显示嵌入此 SurfaceView 中的视图层次结构SurfaceControlViewHost.SurfacePackage 。

void setClipBounds(Rect clipBounds)

在此视图上设置一个矩形区域,绘制视图时将剪裁到该区域。

void setSecure(boolean isSecure)

控制是否应将表面视图的内容视为安全,以防止其出现在屏幕截图中或在非安全显示器上查看。

void setSurfaceLifecycle(int lifecycleStrategy)

控制此 SurfaceView 拥有的 Surface 的生命周期。

void setVisibility(int visibility)

设置此视图的可见性状态。

void setZOrderMediaOverlay(boolean isMediaOverlay)

控制表面视图的表面是否放置在窗口中另一个常规表面视图的顶部(但仍在窗口本身的后面)。

void setZOrderOnTop(boolean onTop)

控制表面视图的表面是否放置在其窗口的顶部。

SurfaceView 的 Protected 方法

void dispatchDraw(Canvas canvas)

由draw调用来绘制子视图。

void onAttachedToWindow()

当视图附加到窗口时调用此方法。

void onDetachedFromWindow()

当视图与窗口分离时调用此方法。

void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect)

当该视图的焦点状态发生变化时,由视图系统调用。

void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

测量视图及其内容以确定测量的宽度和测量的高度。

boolean onSetAlpha(int alpha)

如果存在涉及 alpha 的 Transform,则调用。

void onWindowVisibilityChanged(int visibility)

当包含的窗口的可见性发生更改(在GONEINVISIBLE和 之间VISIBLE)时调用。

二、SurfaceView和View的不同之处

Android提供了View来进行绘图处理,在大部分情况下View都能满足绘图需求。大家都知道View是通过刷新来重绘视图,Android系统通过发出VSYNC信号来进行屏幕的重绘,刷新的间隔时间为16ms。如果在16ms内View完成了你所需要执行的所有操作,那么用户在视觉上,就不会产生卡顿的感觉;反之,如果操作的逻辑过多时,处理时间超过了一帧的时间周期,就会掉帧,从而使得用户感觉到卡顿。特别的需要频繁刷新的界面上,如游戏(60FPS以上)、高帧率视频等,就会不断阻塞主线程,从而导致界面卡顿。基于此Android提供SurfaceView来解决这种情况。

View SurfaceView
共享Surface 独立Surface
在主线程中进行画面更新 通常通过一个子线程来进行画面更新

SurfaceView和View一大不同:View通过invalidate方法通知系统来主动刷新界面的,但View的刷新是依赖于系统的VSYSC信号的,而且因为UI线程中的其他一些操作会导致掉帧卡顿。而对于SurfaceView而言,SurfaceView是在子线程中绘制图形,根据这一特性即可控制其显示帧率,通过简单地设置休眠时间,即可,并且由于在子线程中,一般不会引起UI卡顿。

Thread.sleep(50);即可以控制1s内刷新20次

三、SurfaceView的基本操作

1. 测试程序一:下面通过画圆来介绍SurfaceView的基本操作

public class MainActivity extends AppCompatActivity implements View.OnClickListener, SurfaceHolder.Callback {
    private final static String TAG = "lzl-test";
    private Button mButton;
    private SurfaceView mSurfaceView;
    private SurfaceHolder mSurfaceHolder;
    private Paint mPaint = new Paint();
    private int mCircleRadius = 10;
    private boolean isRunning = false;
    private boolean isStart = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.d(TAG, "onCreate...");

        // 获取 SurfaceView
        mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
        // 调用getHolder()方法获取SurfaceHolder
        mSurfaceHolder = mSurfaceView.getHolder();
        // 通过 SurfaceHolder.addCallback方法设置:实现SurfaceHolder.Callback回调接口
        mSurfaceHolder.addCallback(this);

        // 绘图 启动/ 停止 按键
        mButton = (Button) findViewById(R.id.button);
        mButton.setOnClickListener(this);
        mButton.setText("启动");
    }

    @Override
    public void onClick(View v) {
        // 绘图 启动/ 停止 按键
        if (v.getId() == R.id.button) {
            isStart = !isStart;
            if (isStart) {
                mButton.setText("停止");
                Log.d(TAG, "按键按下:开始绘制");
                start();
            } else {
                mButton.setText("启动");
                Log.d(TAG, "按键按下:停止绘制");
                stop();
            }
        }
    }

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
        Log.d(TAG, "surfaceCreated...");
        if (mSurfaceHolder == null) {
            // 调用getHolder()方法获取SurfaceHolder
            mSurfaceHolder = mSurfaceView.getHolder();
            // 通过 SurfaceHolder.addCallback方法设置:实现SurfaceHolder.Callback回调接口
            mSurfaceHolder.addCallback(this);
        }
        mPaint.setAntiAlias(true); // 设置画笔为无锯齿
        mPaint.setColor(Color.RED); // 设置画笔的颜色
        mPaint.setStrokeWidth(10); // 设置画笔的线宽
        mPaint.setStyle(Paint.Style.FILL); // 设置画笔的类型。STROK表示空心,FILL表示实心
        mPaint.setTextSize(30);
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        Log.d(TAG, "surfaceChanged...");
    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
        Log.d(TAG, "surfaceDestroyed...");
        Log.d(TAG, "surfaceDestroyed:停止绘制");
        mSurfaceHolder = null;
        isStart = false;
        mButton.setText("启动");
        stop();
    }

    // 开始绘制
    public void start() {
        isRunning = true;
        new Thread() {
            @Override
            public void run() {
                while (isRunning) {
                    drawCircle();
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

    // 停止绘制
    public void stop() {
        isRunning = false;
    }

    // 绘制图形
    private void drawCircle() {
        long now = System.currentTimeMillis();
        if (mSurfaceHolder != null) {
            Canvas canvas = mSurfaceHolder.lockCanvas();
            if (canvas != null) {
                // 设置画布为灰色背景色
                canvas.drawARGB(255, 55, 55, 55);
                // 画圆
                canvas.drawCircle(canvas.getWidth() / 2, canvas.getWidth() / 2, mCircleRadius, mPaint);

                if (mCircleRadius < canvas.getWidth() / 2) {
                    mCircleRadius++;
                } else {
                    mCircleRadius = 10;
                }
                if (canvas != null && mSurfaceHolder != null)
                    mSurfaceHolder.unlockCanvasAndPost(canvas);
            }
        }
    }
}

layout XML:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="350dp"
        android:layout_height="350dp"
        android:layout_marginTop="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="启动"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/surfaceView" />
</androidx.constraintlayout.widget.ConstraintLayout>

2. 测试程序二:下面通过touch划线来介绍SurfaceView的基本操作

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
    private final static String TAG = "lzl-test";
    private SurfaceView mSurfaceView;
    //SurfaceHolder
    private SurfaceHolder mHolder;
    //用于绘图的Canvas
    private Canvas mCanvas;
    //子线程标志位
    private boolean mIsDrawing;
    //画笔
    private Paint mPaint;
    //路径
    private Path mPath;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.d(TAG, "onCreate...");

        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); //设置屏幕不随手机旋转
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); //设置屏幕直向显示

        mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
        mHolder = mSurfaceView.getHolder();
        mHolder.addCallback(this);

        /* 清屏 */
        findViewById(R.id.button_clear).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (v.getId() == R.id.button_clear) {
                    mPath.reset();
                }
            }
        });
    }

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        Log.d(TAG, "surfaceCreated...");
        if (mHolder == null) {
            mHolder = mSurfaceView.getHolder();
            mHolder.addCallback(this);
        }

        mPath = new Path();
        //初始化画笔
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(6);
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.RED);
        mSurfaceView.setFocusable(true);
        mSurfaceView.setFocusableInTouchMode(true);
        mSurfaceView.setKeepScreenOn(true);

        mIsDrawing = true;
        new Thread(runnable).start();
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
        Log.d(TAG, "surfaceChanged...");
    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        Log.d(TAG, "surfaceDestroyed...");
        mIsDrawing = false;
        mHolder = null;
    }

    private void draw() {
        if (mHolder != null) {
            Canvas canvas = null;
            try{
                //用于绘图的Canvas, 锁定画布并返回画布对象
                canvas = mHolder.lockCanvas();
                //接下去就是在画布上进行一下draw
                canvas.drawColor(Color.WHITE);
                canvas.drawPath(mPath,mPaint);
            } catch (Exception e){

            } finally {
                //当画布内容不为空时,才post,避免出现黑屏的情况。
                if(canvas !=null && mHolder != null)
                    mHolder.unlockCanvasAndPost(canvas);
            }
        }
    }

    private  Runnable runnable = new Runnable() {
        @Override
        public void run() {
            long start =System.currentTimeMillis();
            while(mIsDrawing){
                draw();
                long end = System.currentTimeMillis();
                if(end-start<100){
                    try{
                        Thread.sleep(100-end+start);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    };

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x=(int) event.getX();
        int y= (int) event.getY();
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Log.d(TAG, "onTouchEvent: down");
                mPath.moveTo(x,y);
                break;
            case MotionEvent.ACTION_MOVE:
                Log.d(TAG, "onTouchEvent: move");
                mPath.lineTo(x,y);
                break;
            case MotionEvent.ACTION_UP:
                Log.d(TAG, "onTouchEvent: up");
                break;
        }
        return true;
    }
}

四、测试程序

完整源码

百度网盘链接:百度网盘 请输入提取码 提取码:test

SurfaceViewTest和SufaceViewTest(android-studio-2022.3.1.18)目录

运行效果

备注:

参考:

SurfaceView和普通view的区别及简单使用

Android系统view与SurfaceView的基本使用及区别分析

点此查看Android应用开发学习笔记的完整目录

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android应用开发(35)SufaceView基本用法 的相关文章

  • 查看寻呼机 - 使用静态变量以编程方式滑动到下一页

    我想在我的 ViewPager 中以编程方式制作幻灯片 我的问题是 滑动事件是由放置在 ViewPager 保存的片段内部的按钮调用的 我知道代码 viewpager setCurrentItem int index 现在我的想法是使 Vi
  • Google Play 商店中基于服务的 Android 应用程序

    我正在开发一个应用程序 该应用程序仅包含一些服务 没有任何活动 即没有 UI 基本上 当用户在他 她的设备上安装应用程序时 我希望有 2 到 3 个服务在后台运行 对此我有几个疑问 应用程序安装后我的服务将如何启动 我的BroadcastR
  • 如何使用retrofit2进行GET请求?

    我有一个在本地主机上运行的安静的 Web 服务 我想在该剩余 URL 上发出 Retrofit2 GET 请求 MainActivity java private void requestData public static final S
  • Android Manifest 自动生成无效权限

    我不小心在 Android 清单中输入了无效的权限名称 并且无法将其删除 这是我的清单代码
  • 编译后从字节代码中删除注释

    我们正在使用一个包含使用 JAXB 注释进行注释的 bean 的库 我们使用这些类的方式完全不依赖于 JAXB 换句话说 我们不需要 JAXB 也不依赖注释 但是 由于注释存在 它们最终会被处理注释的其他类引用 这要求我将 JAXB 捆绑到
  • Android ListView 自定义适配器 ImageButton

    这可能不是正确的方法 如果有更好的方法请告诉我 我创建了一个自定义适配器类 在我的 getView 方法中我膨胀了我想要使用的视图 public View getView int position View convertView View
  • 从 BroadcastReceiver 获取方法来更新 UI

    我正在尝试根据变量的变化更新用户界面BroadcastReceiver 因此 我需要调用一个扩展类的方法 以获取我提到的变量 BroadcastReceiver in MainActivity取决于但我无法以任何方式获得真正的返回值 扩展的
  • 如何忽略 LeakCanary 中的某些类?

    有人能给我一个如何忽略 LeakCanary 中的某些类的有效示例吗 我正在查看这个示例 以忽略 LeakCanary 中第三方库中的某些类 但我不知道将其放在应用程序中的何处 我把它放在我的应用程序类中 但这些变量和方法有错误 isInA
  • Android CursorAdapter、ListView 和后台线程

    我一直在开发的这个应用程序有包含数兆字节数据的数据库可供筛选 许多活动只是列表视图 通过数据库中的各个级别的数据下降 直到到达 文档 即从数据库中提取并显示在手机上的 HTML 我遇到的问题是 其中一些活动需要能够通过捕获击键并重新运行带有
  • 需要在 Android 中伪造正在扫描的 NFC 标签

    好的 我有一个应用程序 此应用程序仅在扫描 NFC 标签 任何标签 时才会完成任务 唯一的问题是 我没有任何 nfc 标签 无论如何 我正试图消除对卡的需要 所以我需要的是一种 伪造 使其看起来 就像已扫描 nfc 标签的方法 我可以编写应
  • 在 Android 中始终以横向模式打开相机

    在我的 Android 应用程序中 单击按钮后我希望相机以横向模式打开 即使我将手机旋转为纵向模式 相机也应始终处于横向模式或纵向模式 使用此代码在横向模式下打开相机 Intent cameraIntent new Intent Media
  • 无法在云控制台中启用 Maps SDK for Android

    我在云控制台中启用适用于 Android 的 Maps SDK 时遇到此问题 https console cloud google com https console cloud google com 它会抛出以下错误 附截图 我收到错误消
  • 如何知道用户是否在 Android 应用程序中输入了错误的密码(锁定屏幕)

    我正在开发一个 Android 应用程序 如果用户在 Android 锁定屏幕中输入错误的密码 则必须完成其中一项活动 例如 如果用户输入错误的密码 则会发送电子邮件 我将不胜感激任何帮助 提前致谢 Kshitij 锁屏在完全沙箱环境中运行
  • 如何在Android网格视图中设置单元格大小?

    我正在尝试为应用程序制作一个带有大图标的网格视图 但我找不到任何有关修改 Android 上网格布局上的单元格大小的教程 有人可以给我一个例子或相关链接吗 Thanks 就像另一个一样适配器视图 http developer android
  • 在 android 版本 7.0 上膨胀类 android.widget.DatePicker 时出错

    我想显示弹出日期选择器并且我使用此代码 Calendar mcurrentDate Calendar getInstance int mYear mcurrentDate get Calendar YEAR int mMonth mcurr
  • 在 android 中,第一次单击时按钮侦听器未注册

    因为我是 Android 新手 所以我遇到了按钮监听器的问题 我正在使用 OnClickListener 来处理胸像 但它第一次点击后不执行一旦我单击多个 它就会表现良好 但如何使其在第一次单击时成为可能 这是我的代码 public cla
  • 无法登录 Google Play 游戏服务

    我在开发者控制台上使用包名称和正确的签名证书设置了我的游戏 并为其创建了排行榜 但没有创建任何成就 然后 我从以下位置下载了示例 Type A Number Challenge 和 BaseGameUtils https developer
  • Android 4.2 - Environment.getExternalStorageDirectory().getPath() 行为

    我一直在开发一个android应用程序 在上次更新到4 2之前 我使用 Environment getExternalStorageDirectory getPath 它返回了我 storage sdcard0 但自从更新后我现在得到了 s
  • 制作弹跳动画

    我想做图层的弹跳动画 我已经完成了该图层从右到中心的操作 现在我想将其向后移动一点 然后回到中心 这会产生反弹效果 我想我可以用这样的翻译来做到这一点
  • 在android中使用BaseActivity的不同活动中的通用标头

    我想编写一次代码并在不同的活动中使用 我创建了一个Base Activity class为了那个原因 此外 不同活动中所有布局的标题都是相同的 我在以下人员的帮助下做到了这一点

随机推荐

  • C++中的.和->

    C 中的 和 gt 1 C 中的点 的应用 如果是一个对象或者引用去调用成员变量或者成员函数函数的话 会使用到点 include
  • vue-cli webpack配置cdn路径 以及 上线之后的字体文件跨域处理

    昨天搞了一下vue项目打包之后静态资源走阿里云cdn 配置了半天 终于找到了设置的地方 config index js 里面设置build 下的 assetsPublicPath 打包的时候便可以添加公共前缀路径 assetsSubDire
  • c++ 封装

    目录 封装的意义一 封装的意义二 struct和class区别 成员属性设置为私有 封装的意义一 封装是c 面向对象的三大特征之一 1 将属性和行为作为一个整体 表现生活中的事物
  • 阿里云在线扩展云盘记录-ubuntu系统

    fdisk l 查看真实磁盘大小 apt get update 更新库 apt get install y cloud guest utils 安装命令 growpart dev vda 1 扩容命令在线扩展磁盘 若报错 执行以下操作 LA
  • C语言动态内存开辟,malloc,calloc,free,realloc函数使用

    目录 一 内存的动态分配 1 函数malloc 2 函数calloc 3 函数realloc 4 函数free 关于动态内存错误的操作案例 一 内存的动态分配 1 函数malloc 函数原型 void malloc size t size
  • 为什么抖音总显示连不上服务器,抖音登录不上怎么回事

    大家好 我是时间财富网智能客服时间君 上述问题将由我为大家进行解答 以抖音v12 5 0为例 抖音登录不上 一般来说都是由于网速过慢 无法连接抖音的服务器 网速过慢一般都是由于手机的信号过低 或者是处于在人群较多的地方 造成了手机的网速变慢
  • Euromap 63协议认识

    Euromap 63协议认识 一 用途 Euromap 63是欧洲塑料和橡胶机械制造商协会颁布的专用于注塑机和上位计算机进行数据交互的协议 全称 Euromap 63 SPI SPI 塑料工业协会 Euromap 63的目标是为不同制造商的
  • Arduino String.h库函数详解

    此库中包含 1 charAT 2 compareTo 3 concat 4 endsWith 5 equals 6 equalslgnoreCase 7 getBytes 8 indexOf 9 lastlndexOf 10 length
  • 控制理论个人学习笔记-非线性系统理论

    文章目录 非线性系统理论 非线性系统的一般概念 相平面基础 非线性系统的相平面分析 描述函数法基础 非线性系统的描述函数法分析 非线性系统理论 非线性系统的一般概念 典型非线性 死区 饱和 间隙 摩擦 继电特性 继电特性使得系统产生振荡 死
  • 利用Java访问WEB Service

    最近在学习Web Service 发现了一个国内的Web Service提供站点 其中最简单的是查询QQ在线状态服务 我通过Java直接发送SOAP请求文件访问Web Service成功 这种方式实现比较简单 不需要第三方的软件包 impo
  • STEP_7计数器相关

    计数器的使用
  • 阿里云服务器租用费用清单表(CPU内存带宽磁盘)

    阿里云服务器租用费用包括CPU内存 公网带宽和系统盘三部分 云服务器购买可以选择活动机型也可以选择自定义购买 活动机型配置固定选择不自由 自定义购买配置自由选择但是费用贵的一批 阿里云百科来详细说下云服务器1核2G 2核4G 4核8G 8核
  • VMware vSphere 6.7先睹为快

    vSphere是老朋友了 还用再多介绍吗 最新的好消息是 VMware vSphere推出了最新版本6 7 相较两年前推出的VMware vSphere 6 5版本 新增了很多强大的功能 作为业内领先的虚拟化和云平台 vSphere的一举一
  • nginx root&alias文件路径配置

    nginx指定文件路径有两种方式root和alias 这两者的用法区别 使用方法总结了下 方便大家在应用过程中 快速响应 root与alias主要区别在于nginx如何解释location后面的uri 这会使两者分别以不同的方式将请求映射到
  • 第4章 用GPT-2生成文本

    BERT 是基于双向 Transformer 结构构建 而 GPT 2 是基于单向 Transformer 这里的双向与单向 是指在进行注意力计算时 BERT会同时考虑被遮蔽词左右的词对其的影响 融合了双向上下文信息 它比较适合于文本生成类
  • IO流介绍和异常处理

    IO流 1 1IO的分类 根据数据的流向分为 输入流和输出流 输入流 把数据从其他设备上读取到内存中的流 输出流 把数据从内存中写到其他设备上的流 根据功能类型分为 字节流和字符流 字节流 以字节为单位 读写数据的流 字符流 以字符为单位
  • tomcat无法启动,也没找到错误日志

    最近做项目的时候 遇到一个问题 项目启动不了 并且没有任何错误日志 1 bug描述 在做项目的时候 启动Tomcat时报错 2 bug信息 Connected to server 2017 11 16 09 28 36 551 Artifa
  • Python:用tkinter制做一个音乐下载小软件

    人生苦短 我用Python 平常我们下载的歌曲 都是各种妖魔鬼怪的格式横行 想下载下来用一下都不行 还只能在它的播放器内听 这谁受得了 学Python是用来干嘛的 当然是解决问题咯 于是我直接写了一手音乐下载软件 强制全部保存mp3 这样就
  • netty服务端的代码

    client code 客户端的ChannelHandler集合 由子类实现 这样做的好处 继承这个接口的所有子类可以很方便地获取ChannelPipeline中的Handlers 获取到handlers之后方便ChannelPipelin
  • Android应用开发(35)SufaceView基本用法

    Android应用开发学习笔记 目录索引 参考Android官网 https developer android com reference android view SurfaceView 一 SurfaceView简介 SurfaceV