花名/ID: 天析

邮箱: 2200475850@qq.com

主攻方向: 物联网安全、WEB安全

兴趣爱好: 乒乓球、羽毛球、排球、业余无线电···

备案信息:蜀ICP备19023334号

物联网技能大赛-安卓方向学习笔记

导语

由于笔者需要参加物联网技能大赛,赛中分三个方向,本次我选择了安卓方向,由于长时间没有去写过安卓了,不足以达到参赛时的要求,因此重新开始学习并整理了这篇文档,本文档一直维护到比赛预选前夕,由于笔者学识浅薄,文中难免有一定的错误或疏漏,望看到本篇文章的各位师傅们予以斧正!

感谢名单

在本篇文档中,Java基础部分的知识由我好友 言断 提供。

设备平台

本文中描述的设备均属于新大陆物联网综合应用平台 NLE-JS3033 中的设备。

必备基础知识:Java数据类型

数据类型:
在Java的数据类型当中,分为 基本数据类型引用数据类型

基本数据类型:

1、数值型

  • 整数类型(byte、short、int、long)
  • 浮点类型(float、double)

2、字符型(char)
3、布尔型(boolean)

必备基础知识:Java中的变量声明

声明格式:数据类型 变量名

例如:

int  // 声明整型变量n
long count; // 声明长整型变量count

必备基础知识:基本数据类型变量的存储

数据类型分为 基本数据类型引用数据类型 。引用数据类型包括数据和类等,类定义的变量又叫对象

按照作用范围分为:
类级(全局变量)对象实例级方法级(局部变量)块级(内部变量)

必备基础知识:Java中的类型转换

其实类型转换在任何一门编程语言中,都存在着他的身影,在类型转换当中,分为两种,强制类型转换隐式类型转换 ,强制类型转换没有什么可说的,隐式类型转换一般都是都是由 低精度高精度 的转换,在转换的过程中,可能涉及到一个转换时精度丢失的问题,会产生精度丢失的转换类型如下:

  • int -> float
  • log -> float
  • log -> double

强制类型转换语法格式: (需要强制转换的数据类型)数值

 double d = 123.4;
 float f = (float)d;

必备基础知识:Java中的条件结构

if 判断

if(条件判断表达式){
    <语句块> 逻辑判断为真时执行
}

if else 判断

if(条件判断表达式){
    <语句块> 逻辑判断为真时执行
}else{
    <语句块> 逻辑判断为假时执行
}

if else if else 判断

if(条件判断表达式1){
    <语句块> 逻辑1判断为真时执行
}else if(条件判断表达式2){
    <语句块> 逻辑2判断为真时执行
}else if(条件判断表达式3){
    <语句块> 逻辑3判断为真时执行
}else{
    <语句块> 逻辑判断全为假时执行
}

switch 选择

switch(表达式){
    case 常量表达式1:
        语句1:break;
    case 常量表达式2:
        语句2:break;
    default:
        语句3;
}

while 循环(如果循环体只有一条语句 大括号可以省略)

while(循环条件){
    语句;
}

do while 循环(循环最少都要执行一次)

do{
    语句;
}while(循环条件);

for 循环

for(表达式1;表达式2;表达式3){
语句;
}

逻辑运算符

  • 与:&& or &
  • 或:|| or |
  • 非:!

break 的作用

  1. break语句可以结束当前循环的执行
  2. 执行完的break语句后 循环体中未予break语句后面的语句就不会执行
  3. 在多重循环中 break语句只向外跳一层

continue 的作用

  1. 只能用在循环里
  2. 可以结束当前循环的执行 但是要继续下一次循环的执行

必备基础知识:Java中的数组

数组是相同类型的数据按顺序组成的一种 引用数据类型

如何声明一个数组:

语法1(先声明后创建):数据类型[]  数组名;
语法2(声明的同时创建数据):数据类型  数组名[];
  • 方法一:

    int[] arr;
    arr = new int[10];
    // 创建一个长度为10的整型数组
  • 方法二:

    int[] arr = new int[10]
    // 创建长度为10的整型数组arr, 注意:数组长度必须指定
    

在声明数组的同时给数组赋初始值的这个过程,我们叫做数组的初始化

必备基础知识:Java的类和对象

  1. 类是模子,确定对象将会拥有的 特征(属性)行为(方法)
  2. 对象是类的实例表现

属性和方法:
属性:对象具有的各种静态特征
对象有什么
方法:对象具有的各种动态行为
对象能做什么

类和对象的关系:
类:抽象的概念 模板
对象:一个看得到 摸得着的具体实体
类 《---实例化---》 对象

对象实例化:
实例化对象的过程可以分为两部分:
声明对象--> Cat one
实例化对象--> new Cat();

构造方法(不能被单独调用需要使用new关键字进行调用):构造函数构造器

  1. 构造方法 同名且没有返回值
  2. 构造方法的语句格式
  3. 只能在对象实例化的时候调用
    构造方法
    构造方法
  4. 当没有指定构造方法时 系统会自动添加无参的构造方法
  5. 当有指定构造方法 无论是有参 无参的构造方法都不会制动添加无参构造方法
  6. 一个类中可以有多个构造方法
    通过this()调用构造方法 必须放在方法体内的第一行

封装:
将类的某些信息隐藏在内部类 不允许外部程序直接访问
通过该类提供的方法来实现对隐藏信息的操作和访问
隐藏对象的信息
留出访问的接口

封装的特点:
1、只能通过规定的方法访问数据
2、隐藏类的实例细节 方便修改和实现

使用包进行类管理:
1、Java中一个包不能存在同名类
2、域名倒序+模块+功能
3、域名全部小写
4、必须放在Java源文件的第一行
5、建议每个包存储信息功能单一
6、建议采用 import 包名.类名; 的方式加载 提高效率
7、加载类的顺序和 import 导入语句的位置无关
8、import包名.*; 只能访问指定包名下的类 无法访问子包下的类
9、包的作用 管理Java文件 解决同名文件冲突

10、定义包:

11、导入包:

static关键字:
1、类对象共享
2、类加载时产生 销毁时释放 生命周期长
3、在成员方法中可以直接访问类中的静态成员
4、static中不能用this this代表当前实例
5、静态方法中不能直接访问同一个类中的非静态成员 只能直接调用同一个类中的静态成员
6、只能通过对象实例化后 对象.成员方法的方式访问非静态成员

代码块的执行顺序:
普通代码块:顺序执行 先出现 在执行
构造代码块:创建对象时调用 优先于构造方法执行
静态代码块:类加载时调用 优先于构造代码块执行

static的使用:
static+属性
static+方法
static+类
static+方法内局部变量
static+代码块

静态成员static声明周期:类加载时产生 销毁时释放 生命周期长
静态代码块无论new几个对象 都只执行一次
构造代码块new几个对象执行几次
各种代码块的执行顺序:静态代码块只执行一次 构造代码块在每次对象构造的时候调用

继承(利于代码复用 缩短开放周期):
1、一种类与类之间的关系
2、使用已存在的类的定义作为基础建立新类
3、新类的定义可以增加新的数据or新的功能 也可以用父类的功能 但不能选择性的继承父类

子承父类
子承父类

父类私有成员 子类不能访问
子类的成员 父类也无法进行访问

方法重写->(语法规则):
返回值类型 方法名 参数类型 顺序 个数 都要与父类继承的方法相同

当子类重写父类方法后 子类对象调用的是重写后的方法

访问修饰符:
1、公有的 public 允许在任意位置访问
2、私有的 private 只允许在本类中进行访问
3、受保护的 protected 允许在当前类 同包子类 非子类 跨包子类调用 跨包非子类不允许
4、默认 允许在当前类 同包子类 非子类调用 跨包子类 非子类不允许调用

方法重写与方法重载的特点:
重载:
1、同一个类中
2、方法名相同 参数列表不同(参数顺序,个数,类型)
3、方法返回值 访问修饰符任意
4、与方法的参数名无关
重写:
1、有继承关系的子类中
2、方法名相同 参数列表相同(参数顺序 个数 类型) 方法返回值相同
3、访问修饰符 访问范围需要大于等于父类的访问范围
4、与方法的参数名无关

super:父类方法 关键字的引用
父类的构造方法不允许被继承不允许被重写
访问修饰符不影响成员加载顺序 跟书写位置有关
父类的构造方法不允许被继承不允许被重写 但是会影响子类对象的实例化
子类构造默认调用父类无参构造方法

子类构造默认调用父类无参构造方法
可以通过super() 调用父类允许被访问的其他构造方法 super()必须放在子类构造方法有效代码的第一行

super:代表父类引用
1、访问父类成员方法 super.print();
2、访问父类属性 super.name;
3、访问父类构造方法 super();

1、子类的构造的过程中必须调用其父类的构造方法
2、如果子类的构造方法中没有显示标注 则系统默认调用父类的无参构造方法
3、如果子类构造方法中既没有显示标注 且父类中没有无参构造方法 则编译出错
4、使用super调用父类指定构造方法 必须在子类的构造方法的第一行

this:当前类对象的引用 super:父类对象的引用
1、访问当前类的成员方法 1、访问父类的成员方法
2、访问当前类的成员属性 2、访问父类的成员属性
3、访问当前类的构造方法 3、访问父类的构造方法
4、不能再静态方法中使用 4、不能再静态方法中使用

this和super都不能在静态方法中使用static
在同一个方法中 this和super不能同时存在 因为它们都要抢占代码块的第一行

继承:
1、一种类与类之间的关系
2、使用已存在的类的定义作为基础建立新类
3、新类的定义可以增加新的数据或新的功能 也可以用父类的功能 但不能选择性的继承父类
4、满足 A is a B的关系

Object类:
1、是所有类的父类
2、一个类没有使用extends关键字明确标识继承关系 则默认继承Object类(包括数组)
3、Java中的每个类都可以使用Object中定义的方法 如:equals() toString()

equals测试:继承Object中的equals方法时 比较的是两个引用是否指向同一个对象
子类可以通过重写equals方法的形式 改变比较的内容

toString测试:输出对象名时 默认直接调用类中的toString
继承Object中的toString方法时 输出对象的字符串表示形式 类型信息+@+地址信息
子类可以通过重写equals方法的形式 改变输出的内容以及表现形式

final关键字:
1、使用final修饰的类 没有子类 public final class
2、final方法:该方法不允许被子类重写 但是可以正常被子类继承使用
3、final方法内局部变量:只要在具体被使用之前赋值即可 一旦赋值不允许被修改
4、final类中成员属性:赋值过程:1、定义直接初始化 2、构造方法 3、构造代码块

final修饰类表示不允许被继承
final修饰方法表示不允许被子类重写 final修饰的方法可以被继承 不能修饰构造方法
final修饰变量不允许修改:
方法内部局部变量 ---》 在使用之前被初始化赋值即可
类中成员变量 ---》只能在定义时 构造方法 构造代码块中进行
基本数据类型的变量 --》 初始赋值之后不能更改
引用类型的变量 --》 初始化之后不能再指向另一个对象 但是对象的内容是可变的
可配合static使用:
public static final String URL = “..........”;
使用final修饰可以提高性能 但是会降低可扩展性

注解:
可以声明在包、类、属性、方法、局部变量、方法参数等前面 用来对这些元素进行说明 注解
按照运行机制分为: 按照来源分:
1、源码注解 1、来自JDK的注解
2、编译时注解 2、来自第三方的注解
3、运行时注解 3、我们自己定义的注解

设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案

Java23种设计模式:

必备基础知识:JVM

在Java中引入了虚拟机的概念,即在机器和编译程序之间加入了一层抽象的虚拟的机器。这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口。编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由解释器来将虚拟机代码转换为特定系统的机器码执行。在Java中,这种供虚拟机理解的代码叫做字节码(ByteCode)(class文件的内容),它不面向任何特定的处理器,只面向虚拟机。每一种平台的解释器是不同的,但是实现的虚拟机是相同的。Java源程序经过编译器编译后变成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定机器上的机器码,然后在特定的机器上运行。

JVM结构图解
JVM结构图解

         可以看出,JVM主要由类加载器子系统、运行时数据区(内存空间)、执行引擎以及与本地方法接口等组成。其中运行时数据区又由方法区、堆、Java栈、PC寄存器、本地方法栈组成。

         从上图中还可以看出,在内存空间中方法区和堆是所有Java线程共享的,而Java栈、本地方法栈、PC寄存器则由每个线程私有,这会引出一些问题,后文会进行具体讨论。

Java程序的运行

Java程序运行过程
Java程序运行过程

详细过程:

java源码(.java) --->java编译器 --->字节码文件(.class)

类加载器 --->字节码校验器 ---> 解释器(翻译) ---> 机器码 ---> 交由execution engin执行

安卓视图(View)

在安卓系统上,也有着类似于数学中的平面直角坐标系的存在,屏幕左上角为坐标原点,向右为x轴增大方向,向下为y轴增大方向,即平面直角坐标系的第四象限。

安卓屏幕坐标系
安卓屏幕坐标系

屏幕、ViewGroup、View都有着各自的参考坐标系,它们的坐标系如上图一样,都在平面直角坐标系的第四象限。

控件的定位:

view.width              // View的宽度
view.height             // View的高度

view.x                  // View左上角相对于ViewGroup左上角的X坐标位置
view.y                  // View左上角相对于ViewGroup左上角的Y坐标位置
view.z                  // 相对于屏幕的Z位置

view.left               // View左边相对于ViewGroup左边的距离
view.top                // View上边相对于VIewGroup上边的距离
view.right              // View右边相对于ViewGroup左边的距离
view.bottom             // View底边相对于ViewGroup上边的距离
view.elevation          // View的高度

view.translationX       // 在滑动过程中,View当前位置的最左边和这个View原始位置的最左边的距离
view.translationY       // 在滑动过程中,View当前位置的最上边和这个View原始位置的最上边的距离
view.translationZ       // 在动画过程中,View当前位置的Z轴高度和这个View原始Z轴高度的距离

视图的线性布局(LinearLayout)

组件有着两个方向:垂直(vertical) or 水平(horizontal)

Analog4150Library.jar 使用说明

这个jar中封装了ADAM-4150数字量方法,用于操作ADAM-4150

类名:Analog4150ServiceAPI

数字量的采集

static void send4150()

新大陆工控平板架构

root@s5p4418_drone:/ # cat  /proc/cpuinfo
Processor   : ARMv7 Processor rev 0 (v7l)
processor   : 0
BogoMIPS    : 2383.87

processor   : 1
BogoMIPS    : 2396.16

processor   : 2
BogoMIPS    : 2396.16

processor   : 3
BogoMIPS    : 2396.16

Features    : swp half thumb fastmult vfp edsp neon vfpv3 tls 
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x3
CPU part    : 0xc09
CPU revision    : 0

Hardware    : s5p4418
Revision    : 0000
Serial      : 0000000000000000

安卓按钮事件的绑定

这里使用比较简单的方法进行绑定

按钮XML

<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="打开串口"
    android:onClick="button_click1"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.921"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.889" />

按钮按下响应方法

// 打开串口
public void button_click1(View view){

    Toast.makeText(MainActivity.this, "按钮1被点击", Toast.LENGTH_SHORT).show();

}

安卓平板的串口通信

导入相关的库和依赖

添加 Analog4150Library.jar 包到工程中。

import androidx.appcompat.app.AppCompatActivity;

布局界面按钮XML

<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="打开串口"
    android:onClick="OpenSerialPort"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.921"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.889" />

src/main 创建 jniLibs 目录,分析架构为 ARMv7 架构,引入新大陆提供的安卓工控平板的动态连接库 libuart.so 文件,同时在app目录下的 build.gradle 文件里加入下面代码 STARTEND 之间的这一段。

android {

    // START
    sourceSets {
        main {
            jniLibs.srcDirs = ['jniLibs']
        }
    }
    // END

}

打开串口方法

// 打开串口
public void OpenSerialPort(View view){

    // 先关闭串口,防止原本串口就处于打开状态
    Analog4150ServiceAPI.closeUart();

    // 开启串口 COM0 波特率9600
    Analog4150ServiceAPI.openPort(0,0, 3);

    Toast.makeText(MainActivity.this, "已开启串口 COM0 波特率9600", Toast.LENGTH_SHORT).show();

}

问讯帧(依照教材“智能生产”所编写的MODBUS)

#电动推杆@收回
01 05 00 10 FF 00 8D FF

#电动推杆@推出
01 05 00 11 FF 00 DC 3F

#报警灯@关闭
01 05 00 12 00 00 6D CF

#报警灯@开启
01 05 00 12 FF 00 2C 3F

#三色灯@红灯开
01 05 00 13 FF 00 7D FF

#三色灯@红灯关
01 05 00 13 00 00 3C 0F

#三色灯@黄灯关
01 05 00 14 00 00 8D CE

#三色灯@黄灯开
01 05 00 14 FF 00 CC 3E

#三色灯@绿灯关
01 05 00 15 00 00 DC 0E

#三色灯@绿灯开
01 05 00 15 FF 00 9D FE

#照明灯@关闭
01 05 00 16 00 00 2C 0E

#照明灯@开启
01 05 00 16 FF 00 6D FE

#风扇@关闭
01 05 00 17 00 00 7D CE

#风扇@开启
01 05 00 17 FF 00 3C 3E

按键的XML代码如下

<Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="BtnClicks"
        android:text="电动推杆 - 收起"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.089"
        app:layout_constraintStart_toEndOf="@+id/button3"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.058"
        tools:ignore="OnClick,UnknownId" />
        
        ···这里省略按键button2至button13···
        
<Button
        android:id="@+id/button14"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="BtnClicks"
        android:text="风扇 - 关闭"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.133"
        app:layout_constraintStart_toEndOf="@+id/button10"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.058"
        tools:ignore="OnClick,UnknownId" />

响应时间

// 按钮按下公共触发事件
@SuppressLint("ResourceType")
public void BtnClicks(View view) throws IOException {

    switch (view.getId()){
    
        case R.id.button1:
        
            char[] bt1  = {0x01, 0x05, 0x00, 0x10, 0xFF, 0x00, 0x8D, 0xFF};
            
            Analog4150ServiceAPI.sendRelayControl(bt1);
            
            break;

    ···这里省略R.id.button2至R.id.button13的响应事件···

        case R.id.button14:

            char[] bt14  = {0x01, 0x05, 0x00, 0x17, 0x00, 0x00, 0x7D, 0xCE};

            Analog4150ServiceAPI.sendRelayControl(bt14);

            break;
            
}
                

新大陆云平台设备的接入

再实现设备接入之前,需要完成以下设备创建的步骤:

第1步:注册帐号
第2步:创建项目
第3步:添加设备
第4步:定义设备传感器

之后根据所创建项目的协议类型选择相应硬件进行开发,记录下设备标识与传输密钥。

安卓线程相关问题

Thread:线程

线程可以看成是一个进程的实体,他是比进程更小的一个能独立运行的一个基本单位。

线程有几种状态:
新建状态(new)
就绪状态(Runnable)
运行状态(Running)
阻塞状态(Blocked)
死亡状态(Dead)

MQQT - Websocket 链接

服务器地址:ws://ndp.nlecloud.com:8600

安卓发起HTTP相关问题

发起网络请求不能在主线程下发起

安卓多Activity启动顺序及相互调用传参相关问题

新大陆云平台API相关问题

P2P摄像机控制及相关问题

传感器相关数据的采集

安卓四大组件相关知识

Activity:活动

Service:服务
主要用于组件之间的交互,例如与Activity、ContentProvider、BroadcastReceiver进行交互,后台去执行比较耗时操作,注意,Service在主线程中运行不能超过20s,否则会出现ANR,所有的耗时操作如无特殊意外均在子线程中运行。

ContentProvider:内容提供者

BroadcastReceiver:广播

文章所属分类:  安卓 

« 物联网技能大赛 - C# 方向学习笔记 CTF SHOW CRYPOT »