这些知识工作能用到。
我在自己的工作岗位上学习到了很多,我发现在学校学的都是基础,在工作上所学到的知识是基本知识的拓展和应用。
自动化测试“我”应该做什么
首先是先了解项目的主要功能及要求,了解你所需要在这个部分写出一个什么样的测试工具;
然后开始学习所需要学习的语言知识;
学习编写所属部分的测试用例;
再开始查看代码编写代码,形成一个测试工具;
测试用例
编写规范(自我理解)
依据需求文档编写;
影响因素不多于3个;
写清用例步骤,表达明确(能使其他人能够迅速读懂你的测试用例);
尽可能覆盖各种路径;
在什么时期完成什么用例,结合需求文档;
在写测试用例的时候一定要注意,不要把多条用例写在一个用例里面,不然会极大增加用例不通过的情况,对整体完整度是有很大的而影响的,因素个数也要注意把控,一旦出现多余三个因素就要分出来写;不断练习,就可以完善好用例;
Java核心基础
注意:在配置环境的时候一定要小心细致,该设的不能漏,不然就会像我一样,重新配置。
学习Java最重要的是流和回调函数的使用,回调函数对于我这个小白来说有点难以理解,但是不断地看文档,看程序,就可以理解是一个什么样的方法,真正的理解是自己编写可以应用到项目中;
Implements 接口
强转:
c=(char)br.read();
字符串连接分割
String类concat方法 == StringBuilder类的append方法;
或者使用“+”
或者使用join方法第一个参数为字符串连接符,第二个开始为连接字符串;
StringBuilder StringBuffer 利用append方法
在Java中 用 \" 来代替双引号,通过双引号分割:.split(“\””);
流的使用
文件、内存、或是网络连接;只可以为输入输出中的一种,先进先出,顺序存取;
文件读取为输入流FileInputStream,写文件是输出流FileOutputSteam;
缓冲流:BufferedInputStream、BufferedOutputStream;
Builder.append();//往builder写数据;
写入流之后一定要记得关闭文件;
.readline();//读取一个文本行;
自己做的Copy项目中,需要用到流的读写;
添加编码:比如:InputStreamReader(put,“UTF-8”);
异常处理
可以通过try{ }catch( ){ }抛出异常;
出现异常如果没有抛出,则会导致系统崩溃(空指针异常);
e.printSttackTrace( );//输出全部异常
检查性异常类:Exception类;
运行时异常类:RuntimeException类;
HashMap的使用
键值对(Key-Value)的应用,根据键的HashCode值存储数据;
不支持线程同步,他是无序的;
.put(“”,“”)添加键对值
this的使用
this调用本类中的属性,也就是类中的成员变量;
this调用本类中的其他方法;
this调用本类的其构造方法,调用时要放在构造方法的首行
Stringname;//定义成员变量
PrivatevoidSetName(Stringname){ //定义一个参数(局部变量)
this.name=name;//将局部变量的值传递给成员变量 }
Java反射机制
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法。
类中:modifier constructor field method;
一切皆对象---类也是对象;
一个类中用于实现另一个类的所有方法:
先获取类,然后获取某个特定的方法(利用:方法名+形参列表);
例如:
Methodm=c.getDeclaredMethod("login",String.class,String.class);
//然后通过反射机制执行方法;
Objecto=c.newInstance();
//调用o对象传递参数;
ObjectretValue=m.invoke(o, "admin","123");
设计模式(常用)
单例模式:某个类只能生成一个实例;提供全局访问点供外部获取实例;
原型模式:讲一个对象作为原型,对其进行复制而克隆出多个和原型类似的实例
工厂方法模式:定义一个用于创建产品的接口,由子类决定生产什么产品;
代理模式:Proxy 为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。
适配器模式:将一个类的接口转换为客户希望的另外一个接口。
策略模式:定义了一系列算法,并将每个算法封装起来,使他们可以互相替换。
遇到的问题及解决方法
问题:如何完成流的读写?
解决方法:
FileOutputStreamfop=newFileOutputStream(set);//构建对象,文件不存在自动建
//OutputStreamWriter参数可以指定编码,默认为操作系统默认编码
OutputStreamWriterwriter=newOutputStreamWriter(fop, "UTF-8");
FileInputStreamput=newFileInputStream(set);//构建FileInputStream
InputStreamReaderreader=newInputStreamReader(put, "UTF-8");
BufferedReaderbr=newBufferedReader (newFileReader(set));
//那么br.readline就会包含set文件
问题:如何实现字符串的分割、提取?
解决方法:
String[] split=str.split(":\|\n\| ");
//Split[i]就包含了分割的字符串以:和换行为界限
问题:如何实现拖拽功能?
解决方法:
new DropTarget(filePathText, DnDConstants.*ACTION_COPY_OR_MOVE*, new DropTargetAdapter(){});
//主要的是哪个文件框的实现,一定要先看懂方法!
问题:回调函数的使用(接口的使用);
解决方法:有三个.class文件(包括一个main) 和 两个接口文件
两个.class文件分别继承两个接口;
在第一个继承自定义接口,含接口函数(check),定义回调接口,引用;
在第二个继承回调接口,含回调方法,callback. check ();
不能正常关机(shutdown)
与系统权限相关;
需要查看相关系统代码;
与C语言异同点
我碰到过的:
异:首先就是有些语法是不一样的比如C语言中:== 在Java中是用 .equals(“str”)
C语言我接触到最多的是嵌入式开发,Java用于android;
C变量不需要赋初值,Java变量需要赋初值;
For循环Java可以用for(循环变量类型 循环变量名称 :要遍历的对象)
同:程序都从main开始,语句逻辑差不多相似;
栈、队列、set、map、list的常用方法
栈:
Push(&S, x):进栈(栈的插入操作),若栈S未满,则将x加入使之成为新栈顶。
Pop(&S, &x):出栈(栈的删除操作),若栈S非空,则弹出栈顶元素,并用x返回。
StackEmpty:判断一个栈是否为空。
记录栈顶元素:*e = S->data[S->top];
队列:
QueueEmpty(Q):判队列空,若队列Q为空返回true,否则返回false。
EnQueue(&Q, x):入队,若队列Q未满,将x加入,使之成为新的队尾。
DeQueue(&Q, &x):出队,若队列Q非空,删除队头元素,并用x返回。
GetHead(Q, &x):读队头元素,若队列Q非空,则将队头元素赋值给x。
初始状态:Q-\>front == Q-\>rear ==0
Map
采用键值对方式;
List
contain方法需要将对象转换,利用
GsonUtils.toJson(scanResults)再使用contain
遍历方法
迭代器
每个迭代器必须实现iterator()方法;
.next();//返回迭代器的下一个元素,并且更新迭代器状态
.hasNext();//用于检测集合中是否还有元素
//List上用迭代器;
Iterator<String> itr = listNames.iterator();
//Set 上用迭代器
Set<String> set = new HashSet<>();
Iterator<String> itr = set.iterator();
//Map上用迭代器;
Map<String, Integer> grade = new HashMap<>();
Iterator<String> itr = grade.keySet().iterator();
//利用
while(itr.hasNext){
String letter = itr.next();
System.out.println(letter);
//或者:
String key = itr.next();
Integer value = grade.get(key);
System.out.println(key + "=>" + value);}实现遍历
forEach(内部迭代)
只能用于遍历,不能用来修改内容;
listNames.forEach(name -> System.out.println(name));
加强for循环
for (String s : listNames) {
System.out.println(s);
}
USB相关
usbHelper = new UsbHelper(this);
usbHelper.setListener(state -> {
switch (state) {
case 0:
ToastUtils.showShort("Connect");
break;
case 2:
ToastUtils.showShort("Disconnect");
break;
default:
break;
}
Log.d(TAG, "current state is " + state);
});
::
类名::方法名。一般是用作 Lambda表达式
1️⃣指向静态方法的引用2️⃣指向某个对象的实例方法的引用3️⃣指向某个类型的实例方法的引用4️⃣指向构造方法的引用
Android核心基础
因为之前在学校有学习过一学期,但是仅仅只是了解,缺少实战,所以这次学习更多的在于基础知识以及拓展知识的应用;
设计模式一般使用MVC模式
Model(数据) Controller(以什么方式显示到(Adapter适配器)) View(界面)
值得注意的是:在运行一个app时如果点击某个按键系统突然奔溃,有可能出现的原因可能是未添加某个服务导致的系统奔溃;比如BroadcastReceiver;
Toast:显示信息的一种机制;过一段时间就消失(比如手机上信息短时间提示)
Android乱码
在vmoption 中 添加 -Dfile.encoding=UTF-8
在gradle.properties中 添加org.gradle.jvmargs=-Dfile.encoding=UTF-8
Android删除文件找回
右键文件夹-->local history 找回
View(后续用到butterknife)
Weight(权重)等比例划分Gravity 文字对齐方式Dialog 弹出对话框Vsync 垂直同步android显示机制;Margin 边缘空白Layout_constraintTop_toBottomOF 将本布局顶部放置在某个id的底部dp和sp:dp只跟屏幕的像素密度有关;因为android可以自定义文字尺寸大小,所以当设置为文字为中时:1db = 1sp ;当设置文字为大时:1sp > 1db;sp就会随系统设置变换;
滑动文本框:Java
JTextArea textArea2 = new JTextArea();
JScrollPane jsp2 = new JScrollPane(textArea2);
textArea2.setRows(20);
panel.add(jsp2);//仅需添加jsp2到画板
自定义Button
因为原始自带的按钮有可能不符合我们的预期,所以可以自己画一个图标;
首先是准备两个大小合适的图片,一个是点击的展示图片,一个是非点击的图片;
添加到资源文件夹中;
然后自定义一个.xml文件:
<selectorxmlns:android=" " target="_blank">http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/btn_false"//没有选中时的图片
android:state_checked="false" /> //点击用state_checked
<item android:drawable="@mipmap/btn_true" //选中时的图片
android:state_checked="true" />
</selector>
Context
上下文,场景;(理解:activity、service、BroadcastReceiver、ContentProvider四大组件当作演员,那么镜头就是Context,button则是配角)
getApplication()和getApplicationContext():
获取当前Application对象用 getApplicationContext.
getApplication()只有在Activity和Service中才能调用的到。
对于比如BroadcastReceiver等中也想要获取Application实例,这时就需要getApplicationContext()方法。
View.getContext():返回当前View对象的Context对象。
跳转(Intent机制)
Intent intent = new Intent(MainAction.this,secondAction(intent));
startActivity(intent);
//Intent主要是用来启动activity或service,可以将intent理解成activity的粘合剂;
//隐式intent:需要先在androidManifest.xml中
被调用的activity要带有<intent-filter>包含<activity>,在Activity中通过setAction和构造方法设置action:intent.setAction(activity名称);
startActivity(intent);
Handler机制
它是Android消息机制的上层接口,可将一个任务切换到handler所在线程中执行;
传递消息Message :Message.obtain获取消息;
Looper.loop()保证消息队列的消息不断地被拿出,并被处理;
UI线程:就是我们的主线程,系统在创建UI线程的时候会初始化一个Looper对象,同时也会创建一个与其关联的MessageQueue;
Handler:作用就是发送与处理信息,如果希望Handler正常工作,在当前线程中要有一个Looper对象;
Message:Handler接收与处理的消息对象;
MessageQueue:消息队列,先进先出管理Message,在初始化Looper对象时会创建一个与之关联的MessageQueue;
Looper循环:用于为线程运行消息循环的类。每个线程只能够有一个Looper,管理MessageQueue,不断地从中取出Message分发给对应的Handler处理!
postDelayed延迟发送,避免内存泄露;
Looper.prepare() 创建loop对象
Looper.loop() 主线程给子线程发送消息(消息队列中的消息不停拿出并被处理)
new Handler().postDelayed(() -> disConnect(stressValueItem.getBtBean().getTestBluetoothDevice()), stressValueItem.getIntervalTime() * 1000L)
在使用的时候会遇到不能使用的问题,具体原因有待考察。(有系统原因等其他原因)
不建议直接用new Message,Message内部保存了一个缓存的消息池,可以用.obtain从缓存池获取一个消息,Message用完后系统会调用recycle回收。
new Handler().sendEmptyMessage (0x1);
//发送带标记的消息(内部创建了message,并设置msg.what=0x1)
Bundle机制
两个Activity之间的通讯可以通过bundle类来实现:
Bundle mBundle = new Bundle();
//加入数据(另一个Activity里面取数据时就要用到Key,找出对应的value)
mBundle.putString("Data", "data from TestBundle");
//新建一个intent对象,并将该bundle加入这个intent对象
Intent intent = new Intent();
intent.setClass(TestBundle.this, Target.class);
intent.putExtras(mBundle);
Binder机制
在Android中实现跨进程通信;
一种虚拟设备驱动。
连接service进程、client进程和service Manager进程(属于Android基础架构)不是直接交互 必须通过Binder驱动(使用open和ioctl文件操作函数)
以代码的形式具体实现在Android中;
作用:连接两个进程,实现了mmap()系统调用,主要负责创建数据接收的缓存空间、管理数据接收缓存。(内存映射)
Server进程会创建很多线程来处理Binder请求
Binder的线程管理采用Binder驱动的线程池,并由Binder驱动自身进行管理(不是由Server进程来管理的)
一个进程的Binder线程数默认最大16;
BroadCastReceiver和EventBus比较
BroadCastReceiver消耗资源高,需要使用Context,能够用于跨进程;
EventBus事件总线管理:是一个发布/订阅事件总线,
称为MessageBus或者发布者/订阅者( publisher/subscriber)模式,可以让两个组件相互通信;适合统一进程;
注册:
EventBus.getDefault().register(this);
Unregister();取消注册
EventBusUtils.*post*(new EventMessage());//返回消息
/*注册:EventBus.getDefault().register(this);
*有四种模式:常用:ThreadMode.MAIN
*/
什么是service 用在哪里 怎么用 特点是什么 包含哪些常用的service类型
是什么
Service(服务)是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。服务可由其他应用组件启动(如Activity),服务一旦被启动将在后台一直运行,即使启动服务的组件(Activity)已销毁也不受影响。
用在哪
服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行
怎么用
如果使用startService()或者stopSelf()方法请求停止服务,系统会就会尽快销毁这个服务startForeground()方法就是将服务设置为前台服务
特点是什么
onStartCommand()
当其他的组件,比如Activity,调用startService()方法启动Service的时候,就会调用这个方法。一旦这个方法执行了,service开始了,并且在后台运行。如果你实现了这个方法,当所有的工作完成之后,你应当调用stopSelf()方法或者是stopService()方法来结束这个Service。(如果你只是想绑定这个Service,那就不要实现这个方法)
onBind()
当其他的组件使用bindService()绑定Service的时候,这个方法会被调用。如果你实现了这个方法,你必须提供一个接口供客户端和这个Service通信,这时会返回一个IBinder对象。实际在编程的时候,你必须要实现这个方法,但是如果你不想要其他的组件绑定到这个Service上,你可以返回一一个空值。
onCreate()
当Service第一次被创建时,这个方法会被调用,如果这个Service已经在运行了,就不会调用这个函数。
onDestroy()
当Service不再运行,并且被销毁,就会调用这个方法。在这个方法中应当清理Service所占用的所有系统资源,比如线程,注册的监听器,接收器等。这个方法是Services生命周期中最后被调用的方法。
Service和IntentService
IntentService会通过HandlerThread单独开启一个线程来处理所有Intent请求对象所对应的工作, ServiceHandler把处理一个intent所对应的事务都封装到叫做 onHandleIntent的虚函数
IntentService不需要主动调用stopSelf()来结束服务。因为在所有intent被处理完后,系统会自动关闭服务。
默认实现的onBind()返回null。
Service已经运行,则只调用onStartCommand()
ButterKnife
强大的View绑定和Click事件处理功能,简化代码,提升开发效率;
运行时不会影响App效率,使用配置方便;
代码清晰,可读性强。
调用findViewById的方法地方都可以设置ButterKnife.bind;
使用ButterKnife可以【settings->Plugins->ButterKnife(右键Generate)】
需要在build.gradle中添加配置
Module中build.gradle:
apply plugin: 'com.jakewharton.butterknife'
implementation 'com.jakewharton:butterknife:10.1.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
project中build.gradle:
classpath 'com.jakewharton:butterknife-gradle-plugin:10.1.0'
异常信息
【 ButterKnife If this view is optional add '@Nullable' (fields) or '@Optional' (methods) annotation】
在使用ButterKnife时,有时会发生以上错误,这可能是butterknife.bind方法写在setContentView之前了,一般要保证butterknife.bind方法要在setContentView之后。
线程Thread
继承Thread类:
继承Thread类;
重写run(),编写线程执行体;
创建线程对象,调用start()方法启动线程;
实现Runnable接口
定义MyRunnable类实现Runnable接口;
实现run()方法,编写线程执行体;
创建线程对象,调用start()方法启动线程;
线程安全与不安全集合
LinkedList、ArrayList、HashSet是非线程安全的,Vector是线程安全的;
HashMap是非线程安全的,HashTable是线程安全的;
StringBuilder是非线程安全的,StringBuffer是线程安全的。
他们都可以进行字符串连接;
String Builder:不考虑线程同步的时候使用,线程不安全;不提供加锁机制保护有可能出现多个线程先后更改数据造成所得到的数据是脏数据;
String Buffer: 线程安全,适合多线程的使用;不存在执行程序时出现意外;
恢复出厂设置遇到的问题
在doMasterClear()中未添加intent.setPackage(“android”)导致整个恢复出厂设置不能使用。
intent 指定包名Intent.setPackage设置广播仅对相同包名的有效。
只有指定的包名的应用程序才能够接收到数据,所以安全性较高。
产看相对应intent文件,看是否编写错误,要细心,不能忽视,不能乱定义。
如何在配置文件中读写文件查看属性:
配置文件中大部分是以键值对形式存在,SystemPropertiesUtils反射获取系统属性值,利用get,set可以对相应的值进行更改;
当你不知道是否存在该属性:
可以先 检查开发板是否有该属性:利用
adb root; 成功显示“restarting adbd as root”
adb remount; 成功显示“remount succeeded”
adb shell;
getprop; 查看所有属性
getprop |grep persist.sys.restoreFactory.count; 筛选属性,显示属性值;
如果没有remount 成功,可以先在设置里面Advanced-->Reset options--->Erase all data(factory reset ) 恢复出厂设置后重新查看;
查看 固件:
adb root
adb remount
adb pull /init.rc
adb pull /system/bin/restoreFactoryCount.sh
做 预制:
将app放置到/system/app/
adb push 路径 /system/app/
遇到的问题和解决方法
问题:蓝牙测试刚开始遇到了很多问题,蓝牙配对不能识别;
解决方法:原因是权限不够,在手机上是不可以自动配对,所以要注释abortBroadcast;
问题:很多机制运行情况并不是很清晰;
解决方法:百度,自学,不懂问指导老师。
问题:开关机测试开机广播不能启动Activity;
解决方法:先打日志查看为什么不能启动,找到问题根本点,handler不能启动,这不排除系统原因,可以修改成Timer线程使用。如果重新烧写系统能够成功,这说明是系统原因,该与系统组成员沟通(团队精神!)
问题:try catch
解决方法:e.printStackTrace()仅打印输出。(尽量处理异常)
崩溃问题
崩溃的原因有很多,暂时我遇到的有三种:
开机广播出现异常:
解决方法:首先是检查出现问题的语句,确定为开机广播出现异常;然后检查AndroidManifest.xml中是否已经添加权限和服务,如果没有则添加,然后测试是否运行成功,或者是调用出现了问题;
在运行重启测试的时候,需要打开重启开机广播,不然会运行失效;
ButterKnife报错:
解决方法:查看报错原因;将提示语仔细阅读,出现错误的原因有多种,可能是ID号出现错误,或者是其他原因;提示如果显示xx未找到,那么将id定位到布局查看是否正确,不正确就要改过来;
值得注意的是:需要修改的地方是生成的Generate ButterKnife Injections所属文件的ID,这样才能自动生成ButterKnife的正确方法;
开机就重启:检查是否是已经开始测试;
遇到'\ufeff'错误问题
一般原因是因为这个项目是用eclipse开发的,出现错误的原因是:Eclipse可以自动吧UTF-8+BOM文件转为普通的UTF-8文件,但Android Studio需要重新转一下;
解决方法:即可以将UTF-8转换为GBK编码格式,在转换为UTF-8格式就可以解决该问题。
接收不到底层发送过来的消息
首先检查广播是否有注册;
如果已经注册则跟系统查看接收底层的方法是否有问题:
bundle = intent.getBundleExtra("bundle");
Application
onCreate():Application创建的时候调用
onConfigurationChanged(Configuration newConfig):当配置信息改变的时候会调用,如屏幕旋转、语言切换时。
onLowMemory():Android系统整体内存较低时候调用,通常在这里释放一些不重要的资源,或者提醒用户清一下垃圾,来保证内存足够而让APP进程不被系统杀掉。它和 OnTrimMemory中的TRIM_MEMORY_COMPLETE级别相同。
onTrimMemory(int level):Android 4.0 之后提供的一个API,用于取代onLowMemory()。在系统内存不足的时会被调用,提示开发者清理部分资源来释放内存,从而避免被 Android 系统杀死。详见《Android代码内存优化建议-OnTrimMemory优化》
onTerminate():Application结束的时候会调用,由系统决定调用的时机
在IntentServer注册广播接收器
在onHandleIntent方法中注册广播接收器,
使用getApplication().registerReceiver(receiverInstance, new IntentFilter())
exported="false"的意思是防止其他应用访问该Service
item点击事件
mLvError.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ListView listView = (ListView) parent;
errorInfoValue = (ErrorInfoValue) listView.getItemAtPosition(position);
Date date = errorInfoValue.getData();
}
});
单例模式
getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成 instance 被多次实例化。
Git的使用
新增
git init
git add --all
git commit -m "xx" // -m后是对提交内容的描述
在github上创建仓库
然后将http clone
git remote add origin https://xx
git push -u origin master
Git常用命令
删除gitlab上的project:
点击要删除的project 点击Settings 翻到Advanced 往下翻:Delete project
点击Delete project会需要再次输入一次project名称才能准确删除;
Clone
从gitlab拉取到本地:
创建要拉取到的文件夹,打开右键Git Bash;
输入git clone http链接 回车;
输入gitlab用户名、密码。
上传到git
在gitlab创建project,选择private或者public;
Push an existing folder会显示:
cd existing_folder
git init
git remote add origin git@192.168.1.55:liubingmei/test.git
git add .
git commit -m "Initial commit"
git push -u origin master
回退
git reflog;
git reset --hard 号码head;
git diff 显示暂存区和工作区的差异;
git show[commit] 显示某次提交发生变化的文件;
push
如果遇到不能push的情况,需要先找到.git中config,更改url = http://名字:密码@xx.git
adb命令的使用
adb tcpip 5555给设备开端口号
adb connect ip:端口号
adb device 查看当前设备的连接状态
adb –s “设备号” shell 操作当前已连接的设备
adb 截图
adb shell screencap –p sdcard/screen.png 截图保存为文件screen.png
adb pull sdcard/screen.png ./ 将截图移动到PC端 后加地址
adb执行apk
adb install (-r -t)(apk路径)
-l 锁定该应用程序
-r替换已存在的应用程序,也就是说强制安装, 低版本还是会安装失败
-t允许测试包 -s把应用程序安装到sd卡上
-d允许进行低版本的安装,也就是安装的比手机上带的版本低
-g为应用程序授予所有运行时的权限
adb uninstall 包名 com.ss.android.ugc.aweme抖音
adb shell dumpsys window w |findstr \/ |findstr name= 这个可以看到你当前正在打开的应用的包名
adb shell am start –n (主Activity,例如: adb shell am start -n com.hollyland.hardwaretest/com.hollyland.hardwaretest.ui.MainActivity)
adb logcat 查看日志 –s 可以筛选
adb预制
adb push 文件夹 /system/app/
adb刷机
1、adb root 获取root权限
2、adb disable-verity 关闭分区检测功能
3、adb reboot 执行adb disable-verity后需要重启设备
4、adb root 设备重启后再次获取root权限
5、adb remount 使system分区为可读可写模式
adb 烧写版本
reboot edl
adb杀死进程
adb shell
$ su
# ps
#ps –ef | grep xxx 筛选xxx进程
#kill xxx 杀死进程号为xxx的进程
adb出现多设备连接
adb kill-server
adb shell
adb 杀死app
adb shell
am force-stop 包名:例如com.hollyland.hardwaretest
adb消除多设备
adb –s xxx kill-server
抓log
adb logcat > D:xxxx.txt
adb logcat -v time>>xxx.txt
adb logcat -v -t >xxx.txt
dmesg
修改屏幕分辨率
adb shell
wm size
wm size [reset|WxH|]
wm size reset
报点率
adb shellgetevent -r
获取sn
Adb shell
Getprop ro.serialno
通过Android.os.Build.serial
adb设置缓存
打开log之前 先设置一下缓冲区大小:adb logcat -G 6m设置完之后,再adb logcat -v -t即可
查内存及内存填满
查内存占用:dumpsys cpuinfo
adb shell dd if=/dev/zero of=sdcard/aa bs=1024000 count=1024
修改count大小的值,1G=1024,要填充多少自己计算
sdcard/aa 这个是填充的目录,删掉就可以清除内存
/mnt/media_rw/8462-EF5D(这个就是你的sd卡)
pull所有照片视频到本地
adb pull 相机路径 本地路径
查看当前目录下及子目录文件大小
du –sh * 查询当前目录下所有子目录总大小
INSTALL_FAILED_VERSION_DOWNGRADE
说明Android机器中已经存在了比这个应用的版本号更高的同名应用
Adb install –r –d xxx
-r replace existing application(替换存在的应用)
-d allow vwesion code downgrade(可以低于原来应用的版本号)
-t allow test packages
-s install application on sdcard
-p partial application install
结果输出
Runtime runtime = Runtime.getRuntime();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(runtime.exec("ipconfig").getInputStream()));
//StringBuffer b = new StringBuffer();
String line=null;
StringBuffer b=new StringBuffer();
while ((line=br.readLine())!=null) {
b.append(line+"\n");
}
System.out.println(b.toString());
} catch (Exception e) {
e.printStackTrace();
}
ANR与CRASH的区别
ANR:Application Not Responding,程序未响应。
原因:主线程执行了耗时操作;其他程序占用CPU导致本进程得不到CPU时间片;
CRASH:程序奔溃或闪退。
Application Crash由于java层线程因未捕获异常而终止,由系统的void uncaughtException(Thread t,Throwable e) 方法进行捕获和处理,通常会给出界面弹窗提示“***已停止运行。”。
原因:空指针异常、数据类型转换异常等。
产生ANR可以利用延时或sleep;
产生CRASH可以空指针输出toString;
(状态机FSM)
State,event,action,transition;参考Java状态机四种实现方法;
以状态类State替代boolean、int、枚举类型的分支判断参数,多少分支State将对应有多少子类;
Private interface state{ }
State子类分别给出配套的实现;
Private class childState implements State{ }
运用:private State state;
Private String State配套实现(){ }
Main函数实例化运用;
Jenkins
Jenkins是开源软件项目,基于Java开发的持续集成(CI)工具,用于监控持续重复的工作。
软件的持续构建和测试,提供了一个系统,使很容易的将改变集成到工程中。监视job的执行,分布式构建(可以将工程构建到多台机器,更好的利用硬件资源,节省时间)还可以自己编写插件
推流
69服务器开启推流服务命令行:
ssh hollyland@192.168.1.69
密码: ABC123
cd 到 test 路径
cd 到 stream 路径
sh stream-server-start.sh 启动服务
编码
Avc为H264
Format 视频格式
Bit rate:码率
相机参数
我们的项目是相机,了解相机所有参数其实是很有必要的,在编写用例的时候需要注意参数调节;
首先是光圈:光圈的大小决定进光的多少,光圈越大,进光量更多,快门时间越短,照片越不容易模糊(在拍摄人像的时候可以使用);光圈会影响景深,星芒越少。
焦距:数值越小容纳的内容就越多,适合风景,也就是距离越小。
快门:定格瞬间的快门速度。
感光度(ISO):感光度要搭配快门使用,以达到最佳效果;夜晚拍摄,没有白天那么充足的光,所以光圈固定智能调节ISO;
景深:类似于背景虚化,景深越小虚化的越多;光圈越大,景深越浅;小光圈大景深(适合拍摄风景)全部是清晰的。
白平衡:除了获得真确的颜色意外,在特殊的场景能起到渲染氛围的作用(冷暖色调)。
光学变焦和数码变焦的区别
变焦手段:光学变焦是通过物理光学手段来变焦,数码变焦是软件手段;
原理:光学变焦是通过改变焦距的大小来改变图像的大小,数码变焦是将一张已经固定的照片再进行放大。
光学变焦的照片原汁原味,数码变焦的照片是通过特殊处理的。
FOV视场角
Netty
NIO:非阻塞I/O;
channel:
可以理解为通道。 数据传入传出的载体。
可以判断当前状态;获取配置参数;支持IO操作(读、写channelRead、连接(启动器)和绑定)、处理IO事件和请求的ChannelPipeline(通过channel获取channelPipeline,例如在ClientChannelInitialize中发送心跳包)。
channelHandlerContext:
设计此上下文对象;就可以拿到channel、pipeline等对象,进行读写操作。
channelHandler:回调channelActive 当一个新的连接已经被建立时。实现服务器对从客户端接收的数据的处理。
Future,此对象可以看做一个异步操作的结果的占位符。
channelFuture:执行异步操作的时候使用,每个Netty的出站I/O都会返回一个channelFuture。
说明永远不会阻塞。
ChannelHandler和事件:使用不同的事件来通知我们状态的改变或者是操作的状态,每个事件都会被分发给ChannelHandler类中的某个用户实现的方法。类似于一种被执行的回调。
bootstrap.group(group).channel(NioSocketChannel.class).handler(new ClientChannelInitializer());
指定所使用的的NIO传输channel
添加一个handler到子channel的channelPipeline
.sync(),异步地绑定服务器,调用这个方法阻塞直到绑定完成
ChannelHandler:
channelActive()---在到服务器的连接已经建立的时候调用
channelRead0()---当从服务器接收到一条消息的时候调用
exceptionCaught()---在处理过程中引发异常时被调用
channel ---- Socket (基本I/O操作bind() connect() read() write() )
EventLoop ---- 控制流、多线程处理。并发
ChannelFuture ---- 异步通知
ChannelFuture提供操作完成时一种异步通知的方式。一般在Socket编程中,等待响应结果都是同步阻塞的,而Netty则不会造成阻塞,因为ChannelFuture是采取类似观察者模式的形式进行获取结果。
例如:在HardwareClient:
ChannelFuture = bootstrap.connect(address,port).sync();
三者关系:
创建channel 将channel注册到EventLoop 在整个生命周期内部使用EventLoop处理I/O事件
ChannelPipeline:当Channel被创建时,他会被自动地分配到它专属的ChannelPipeline
Bootstrap:引导。
onHandleIntent
一次只处理一个intent,
网络请求
只有在调用Observable的subscribe方法时,网络请求才会触发,订阅即触发。
当UI层Destroy了,不及时取消订阅,可能造成内存泄漏。
所以需要将subscribe订阅返回的Disposable对象加入管理器,在UI销毁时清空订阅对象。
Netty过程
GreenDao
DaoMaster:
使用 greenDAO 的入口点。DaoMaster 负责管理数据库对象(SQLiteDatabase)和 DAO 类(对象),我们可以通过它内部类 OpenHelper 和 DevOpenHelper SQLiteOpenHelper 创建不同模式的 SQLite 数据库。
DaoSession :
管理指定模式下的所有 DAO 对象,DaoSession提供了一些通用的持久性方法比如插入、负载、更新、更新和删除实体。
XxxDAO :
每个实体类 greenDAO 多会生成一个与之对应DAO对象,如:User 实体,则会生成一个一个UserDao 类
Entities
可持久化对象。通常, 实体对象代表一个数据库行使用标准 Java 属性(如一个POJO 或 JavaBean )。
插入数据例子:
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
ErrorInfo errorInfo = new ErrorInfo();
errorInfo.setType("Crash");
errorInfo.setData(dateFormat.format(new Date()));
errorInfo.setInfo("exceptionValue.getExceptionMessage()");
DaoSession daoSession = GreenDaoManager.*getInstance*().getDaoSession();
ErrorInfoDao errorInfoDao = daoSession.getErrorInfoDao();
errorInfoDao.insert(errorInfo);
//读取数据可以利用adb shell /data/data/(项目名)/databases/xxx.db
//全部读取:
GsonUtils.*toJson*(GreenDaoManager.getInstance().loadAll());
注意事项
当重新构建数据库的时候需要先将前一个数据库删除,才能创建新的数据库。
否则会出现错误:android.database.sqlite.SQLiteException: no such column: T._id (code 1 SQLITE_ERROR): , while compilin
通过stetho查看数据库:
implementation 'com.facebook.stetho:stetho:1.3.1'
Stetho.initializeWithDefaults(this);
查询
eq 相等noteq 不相等like 模糊搜索
">" :gt
"<" :It
">=" :ge
"<=" : le
//展示list中某一项;
List<ErrorInfoValue> list = GreenDaoManager.getInstance().queryAll();
List<Date> dateList = list.stream().map(ErrorInfoValue::getData).collect(Collectors.toList());
异常信息
java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getImportantForAccessibility()' on a null object reference
listView适配器里的getView方法return的view为空了
Retrofit
介绍:Retrofit将HTTP API接口转换为Java接口;
该类生成xxxService接口来实现;
··· Call生成的每个xxxService接口都可以向远程 Web 服务器发出同步或异步 HTTP 请求。
使用注解来描述 HTTP 请求:
URL参数替换和查询参数支持
对象转换为请求正文(例如,JSON、协议缓冲区)
多部分请求正文和文件上传
Every method must have an HTTP annotation that provides the request method and relative URL. There are eight built-in annotations: HTTP, GET, POST, PUT, PATCH, DELETE, OPTIONS and HEAD. The relative URL of the resource is specified in the annotation.
Get 安全从服务器取出资源
Post 在服务器新建一个资源
AtomicInteger
volatile关键字(基于volatile的变量在并发下不是安全的)
1、保证变量在线程间可见,对volatile变量所有的写操作都能立即反应到其他线程中,换句话说,volatile变量在各个线程中是一致的(得益于java内存模型—"先行发生原则”)
2、禁止指令的重排序优化;
java里的运算(比如自增)并不是原子性的。AtomicInteger.incrementAndGet()方法有原子性,所以并发下他是安全的。
AtomicInteger.gerAndIcrement()相当于AtomicInteger++;
Okhttp(build设计模式(生产者模式))
okhttp参数说明:
cookieJar(new CookiesManager()): 设置一个自动管理cookies的管理器
addInterceptor(new MyIntercepter()):添加拦截器
addNetworkInterceptor(new
CookiesInterceptor(MyApplication.getInstance().getApplicationContext())):添加网络连接器
connectTimeout(30, TimeUnit.SECONDS):请求超时时间
writeTimeout(30,TimeUnit.SECONDS):写入超时时间
readTimeout(30, TimeUnit.SECONDS):读取超时时间
subscribe(observer)插入观察者
study
注解配置请求;
REST状态转移
Get同步
步骤:首先创建一个接口 请求方法
传消息是通过Respons 接口.test(“消息”).execute();
消息内容用response的.body()可以获取
异步:
接口.test(“消息“).equeue(new Callback<test类型>{
@Override
Onsuccess Onfailure
})
Post方式一样,也是retrofit的功能之一( 方便)
Data
转换格式,需要用到DateFormat
例如:DateFormat dateFormat = new SimpleDateFormat(yyyy-MM-dd HH:mm:ss);
然后:dateformat.format(new Date);就可以成功转换成一个指定格式日期。
产测—图像测试
通过查看配置文件HLCameraTestAlgoini可以将MTF1_1、MTF1_2都设置好然后查看真实数据