Android测试基础知识

一、 Android基础知识

Android生命周期

1、完整生命周期

Activity的基本生命周期如下所示:

  public  class MyActivity extends Activity {

  protected   void onCreate(BundlesavedInstanceState);

  protected   void onStart();

  protected   void onResume(); 

  protected   void onPause();

  protected   void onStop();

   protected   void onDestroy();

}

 

你自己写的Activity会按需要重载这些方法,onCreate是免不了的:

  • 在一个Activity正常启动的过程中,他们被调用的顺序是

onCreate -> onStart -> onResume

  • 在Activity被干掉的时候顺序是

onPause-> onStop -> onDestroy

这就是一个完整的生命周期

但如果程序正运行着呢来电话了,这个程序咋办?中止!具体分两种情况:

  • 如果中止的时候新出的一个Activity是全屏的那么:onPause->onStop,恢复的时候onRestart->onStart->onResume
  • 如果打断这个应用程序的是一个Theme为Translucent(半透明)或者Dialog的Activity那么只是:onPause,恢复的时候onResume.

2、具体方法介绍

onCreate:创建界面,做一些数据的初始化工作

onStart:可见不可交互

onResume:可交互的,(在activity栈系统通过栈的方式管理这些个

        Activity的最上面,运行完弹出栈,则回到上一个Activity)

onPause:可见不可交互,系统会停止动画等消耗CPU的事情从上文的描述已经知道,应该在这里保存你的一些数据,因为这个时候你的程序的优先级降低,有可能被系统收回.在这里保存的数据,应该在onResume里读出来,注意:这个方法里做的事情时间要短,因为下一个activity不会等到这个方法完成才启动

onStop: 变得不可见,被下一个activity覆盖了

onRestart:当处于停止状态的活动需要再次展现给用户的时候,触发该方法

onDestroy: 这是activity被干掉前最后一个被调用方法了,可能是外面类调用finish方法或者是系统为了节省空间将它暂时性的干掉,可以用isFinishing()来判断它,如果你有一个ProgressDialog在线程中转动,请在onDestroy里把他cancel掉,不然等线程结束的时候,调用Dialog的cancel方法会抛异常的.

onPause,onStop, onDestroy,三种状态 下activity都有可能被系统干掉

3. 内存回收

1、概念

Android 之所以采用特殊的资源管理机制,原因在于其设计之初就是面向移动终端,所有可用的内存仅限于系统 RAM,必须针对这种限制设计相应的优化方案.

当 Android 应用程序退出时,并不清理其所占用的内存;Linux 内核进程也相应的继续存在,所谓“退出但不关闭”.从而使得用户调用程序时能够在第一时间得到响应.

当系统内存不足时,系统将激活内存回收

2、回收过程

一个Android 程序的进程是何时被系统结束的呢?通俗地说,一个即将被系统关闭的程序是系统在内存不足(low memory)时,根据“重要性层次”选出来的“牺牲品”.一个进程的重要性是根据其中运行的部件和部件的状态决定的.各种进程按照重要性从高到低排列如下(回收顺序相反):

  1. 前台进程——这样的进程拥有一个在屏幕上显示并和用户交互的activity或者它的一个 IntentReciver正在运行.这样的程序重要性最高,只有在系统内存非常低,万不得已时才会被结束.
  2. 可见进程——在屏幕上显示,但是不在前台的程序.比如一个前台进程以对话框的形式显示在该进程前面.这样的进程也很重要,它们只有在系统没有足够内存运行所有前台进程时,才会被结束.
  3. 服务进程——这样的进程在后台持续运行,比如后台音乐播放、后台数据上传下载等.这样的进程对用户来说一般很有用,所以只有当系统没有足够内存来维持所有的前台和可见进程时,才会被结束.
  4. 后台进程——这样的程序拥有一个用户不可见的activity.这样的程序在系统内存不足时,按照LRU(Least Recently Used)的顺序被结束.
  5. 空进程——这样的进程不包含任何活动的程序部件.系统可能随时关闭这类进程.

4. 响应能力(ANR

应用程序无响应——Application No Response

何时会ANR:

  • 点击事件或按键事件5秒钟无响应;
  • onReceive()到Broadcast消息后10秒钟没有处理返回

5. 较典型Crash场景

  • 无法解析intent导致crash——卸载自带浏览器,激活程序网络访问功能,如分享、点赞、搜索、打开链接
  • 小内存手机,扫描大体量SD卡——如包含5G以上各种垃圾,执行扫描,可能出现OOM(Out Of Memory)类型crash
  • 某些场景下的扫描数字快速跳动crash——同样是小内存手机OOM
  • 点击程序图标,启动过程中连续点击back键crash——某些方法初始化失败导致crash
  • 空指针导致crash

二、 自动化测试——Monkey

1. Monkey测试简介

Monkey测试是Android平台自动化测试的一种手段,通过Monkey程序模拟用户触摸屏幕、滑动Trackball、按键等随机操作来对设备上的程序进行压力测试,检测程序多久的时间会发生异常

1. Monkey程序介绍

  • Monkey程序由Android系统自带,使用Java语言写成,在Android文件系统中的存放路径是:/system/framework/monkey.jar
  • jar程序是由一个名为“monkey”的Shell脚本来启动执行,shell脚本在Android文件系统中的存放路径是:/system/bin/monkey

然后通过在cmd中执行: adb shell monkey +command来进行Monkey测试

也可以先adb shell进入系统,之后只需执行monkey+command,如图:

 

注意:Monkey测试是推送命令到手机执行!

即一旦开始执行命令,手机将不受PC端控制,只能待命令运行结束或重启手机!adb reboot

2. Monkey命令参数介绍

先给大家展示一个我比较常用的:

adb shell monkey -p com.x.x   --ignore-crashes --ignore-timeouts --ignore-security-exceptions --ignore-native-crashes --pct-touch 35 --pct-motion 40 --pct-syskeys 5 --pct-anyevent 10  -vv --throttle 300 100000>G:\Monkey.txt,如图:

 

  • 参数:-p

指定一个或多个package. 若待测应用会访问到其他包的活动,也需列出其他包名,否则monkey会阻止待测应用打开这些活动.

指定包之后,Monkey将只允许系统启动指定的APP.如果不指定包,Monkey将允许系统启动设备中的所有APP.

* 指定一个包执行100次随机操作: adb shell monkey -p com.x.x  100

说明:com.qihoo.security为包名,100为事件计数(即让Monkey程序模拟100次随机用户事件)

* 指定多个包:adb shell monkey -p com.x.x–p com.x.x1-p com.qihoo.appstore 300

* 不指定包:adb shell monkey 100

 说明:Monkey随机启动任意APP并发送100个随机事件.

  • 参数:  -v

用于指定反馈信息级别(verbose,即日志的详细程度),总共分3个日志级别:

Level0

示例:adb shellmonkey -p com.x.x–v 100

说明:缺省值,仅提供启动提示、测试完成和最终结果等少量信息

Level 1

示例 adb shellmonkey -p com.x.x–vv 100

说明:提供较为详细的日志,包括每个发送到Activity的事件信息

Level 2

示例 adb shellmonkey -p com.x.x–vvv 100

说明:最详细的日志,包括了测试中选中/未选中的Activity信息

  • 参数:-s

用于指定伪随机数生成器的seed值.

如果seed相同,则两次Monkey测试所产生的事件序列也完全相同——适用于复现crash

* 示例:

 Monkey test 1:adb shell monkey -p com.x.x–s 10 100

  Monkey test 2:adb shell monkey -p com.x.x–s 10 100

两次测试效果是相同的!因为我们指定了相同seed值,就可以保证两次测试产生的随机操作序列是完全相同的(每次操作按照一定的先后顺序所组成的一系列操作,即一个序列).

  • 参数:--throttle

用于指定用户两次操作(即事件)间的时延,单位是毫秒.

* 示例:adb shell monkey -p com.x.x–throttle 3000 100

适用场景:

程序需要长时间后台运行 或 连续快速点击

  • 参数:--ignore-crashes

用于指定当应用程序崩溃时(Force&Close错误),Monkey是否停止运行.

如果使用此参数,即使应用程序崩溃,Monkey依然会发送事件,直到事件计数完成.

* 示例1:adb shellmonkey -p com.x.x--ignore-crashes 1000

测试过程中即使security程序崩溃,Monkey依然会继续发送事件直到事件数目达到1000为止;

* 示例2:adb shellmonkey -p com.x.x1000

测试过程中,如果security程序崩溃,Monkey将会停止运行

  • 参数:--ignore-timeouts

用于指定当应用程序发生ANR(Application No Responding)错误时,Monkey是否停止运行.

如果使用此参数,即使应用程序发生ANR错误,Monkey依然会发送事件,直到事件计数完成

  • 参数:--ignore-security-exceptions

用于指定当应用程序发生许可错误时(如证书许可,网络许可等),Monkey是否停止运行.如果使用此参数,即使应用程序发生许可错误

  • 参数:--kill-process-after-error

用于指定当应用程序发生错误时,是否停止其运行.如果指定此参数,当应用程序发生错误时,应用程序停止运行并保持在当前状态(系统并不会结束该应用程序的进程).

  • 参数:--monitor-native-crashes

用于指定是否监视并报告应用程序发生崩溃的本地代码.

如果同时设置了--kill-process-after-error,系统将停止运行

  • 参数:--pct-{+事件类别}{+事件类别百分比}

用于指定每种类别事件的数目百分比(在Monkey事件序列中,该类事件数目占总事件数目的百分比)

参数:--pct-touch + percent

说明:调整触摸事件的百分比(触摸事件是一个down-up事件,它发生在屏幕上的某单一位置)

示例:adb shell monkey -p com.x.x--pct-touch 10 1000

参数:--pct-motion + percent

说明:调整动作事件的百分比(动作事件由屏幕上某处的一个down事件、一系列的伪随机事件和一个up事件组成)

示例:adb shell monkey –p com.x.x --pct-motion 20 1000

参数:--pct-trackball + percent

说明:调整轨迹事件的百分比(轨迹事件由一个或几个随机的移动组成,有时还伴随有点击)

示例:adb shell monkey -p com.x.x   --pct-trackball 30 1000

参数:--pct-nav + percent

说明: 调整“基本”导航事件的百分比(导航事件由来自方向输入设备的up/down/left/right组成)

示例:adb shell monkey -p com.x.x--pct-nav 40 1000

参数:--pct-majornav + percent

说明:调整“主要”导航事件的百分比(这些导航事件通常引发图形界面中的动作,如:5-way键盘的中间按键、回退按键、菜单按键)

示例:adb shell monkey -p com.x.x --pct-majornav 50 1000

参数:--pct-syskeys + percent

说明:调整“系统”按键事件的百分比(这些按键通常被保留,由系统使用,如Home、Back、Start Call、End Call及音量控制键)

示例:adb shell monkey -p com.x.x  --pct-syskeys 60 1000

参数:--pct-appswitch + percent

说明:调整启动Activity的百分比.在随机间隔里,Monkey将执行一个startActivity()调用,作为最大程度覆盖包中全部Activity的一种方法

示例:adb shell monkey -p com.qihoo.security --pct-appswitch 70 1000

参数:--pct-anyevent + percent

说明:调整其它类型事件的百分比.它包罗了所有其它类型的事件,如:按键、其它不常用的设备按钮、等等

示例:adb shell monkey -p com.qihoo.security --pct -anyevent 100 1000

说明:指定多个类型事件的百分比:

示例:adb shell monkey -p com.qihoo.security --pct-anyevent 50 --pct-appswitch 50 1000

注意:各事件类型的百分比总数不能超过100%;

  

3. Monkey测试策略

  • 分类
    Monkey测试针对不同的对象和不同的目的采用不同的测试方案,首先测试的对象、目的及类型如下:

测试的类型分为:应用程序的稳定性测试和压力测试

测试对象分为:单apk /多apks

测试的目的分为:解决问题的测试(忽略异常的测试) /验收测试(不忽略异常的测试)

  • 应用程序的稳定性测试:
    针对单个apk

(1) 不忽略异常

在进行单个apk的验收测试时,则使用单一apk且不忽略异常的命令执行.

例如:

monkey -p com.qihoo.security --throttle 1000 -s 100 -vvv 15000 >

/data/local/monkey_test.txt

 

(2) 忽略异常

在进行单个apk的解决问题的测试时,则使用单一apk且忽略异常的命令执行,这样可以在一次执行的过程中发现应用程序中的多个问题.

例如:

monkey -p com.qihoo.security --throttle 1000 -s 100 --ignore-crashes

--ignore-timeouts --ignore-security-exceptions --ignore-native-carshes

--monitor-native-crashes -vvv 15000 >/data/local/monkey_test.txt

  1. 针对多个apk(--pkg-whitelist-file)

(1) 不忽略异常

例如:

monkey --pkg-whitelist-file /data/whitelist.txt--throttle 1000 -s 100 -vvv 15000 > /data/local/monkey_test.txt

(2) 忽略异常

例如:

monkey --pkg-whitelist-file /data/whitelist.txt--throttle 1000 -s 100

--ignore-crashes --ignore-timeouts --ignore-security-exceptions

--ignore-native-carshes --monitor-native-crashes -vvv 15000 > /data/local /monkey_test.txt

  • 应用程序的压力/健壮性测试
    应用程序的压力/健壮性测试,其主要是缩短monkey测试中事件与事件之间的延迟时间,验证在快速的事件响应的过程中,程序是否能正常运行.这种压力/健壮性测试主要是针对单一apk来执行;我们可以将--throttle的值设定为500或者更小,一般都使用500毫秒的延迟事件.

在进行apk的集合测试时,对于高频率使用的apk、长时间使用的apk都要包含在执行的应用程序中间

APK分类具体:

高频率使用的apk如: Phone、Contacts、Message、Settings、File Manager、Gallery、Input Method

长时间使用的apk如:Phone、Browser、Music player、Camera、Video player、Email、Chat

其他的apk如:Calendar、Notepad、Calculator、FM Radio、Google Search

4. Monkey测试结果分析

  • 初步分析方法
    Monkey测试出现错误后,一般的差错步骤为以下几步:

1、 找到是monkey里面的哪个地方出错

2、 查看Monkey里面出错前的一些事件动作,并手动执行该动作

3、 若以上步骤还不能找出,可以使用之前执行的monkey命令再执行一遍,注意seed值要一样

一般的测试结果分析:

1、 ANR(Application No Responding)问题:在日志中搜索“ANR”

2、 Crash问题:在日志中搜索“fatal”

  • 详细分析monkey日志:
    将执行Monkey生成的log,从手机中导出并打开查看该log;在log的最开始都会显示Monkey执行的seed值、执行次数和测试的包名.

首先我们需要查看Monkey测试中是否出现了ANR或者异常,具体方法如上述.

然后我们要分析log中的具体信息,方法如下:

 

查看log中第一个Switch,主要是查看Monkey执行的是那一个Activity,譬如下面的lo中,执行的是com.tencent.smtt.SplashActivity,在下一个swtich之间的,如果出现了崩溃或其他异常,可以在该Activity中查找问题的所在.

 

:Switch:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10000000;component=com.tencent.smtt/.SplashActivity;end

  // Allowing start of Intent {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER]cmp=com.tencent.smtt/.SplashActivity } in package com.tencent.smtt

 

在下面的log中,Sending Pointer ACTION_DOWN和Sending Pointer ACTION_UP代表当前执行了一个单击的操作;

Sleeping for 500 milliseconds这句log是执行Monkey测试时,throttle设定的间隔时间,每出现一次,就代表一个事件.

SendKey(ACTION_DOWN) //KEYCODE_DPAD_DOWN   代表当前执行了一个点击下导航键的操作;

Sending Pointer ACTION_MOVE     代表当前执行了一个滑动界面的操作.

:Sending Pointer ACTION_DOWN x=47.0 y=438.0

:Sending Pointer ACTION_UP x=47.0 y=438.0

Sleeping for 500 milliseconds

:SendKey (ACTION_DOWN): 20   //KEYCODE_DPAD_DOWN

:SendKey (ACTION_UP): 20   //KEYCODE_DPAD_DOWN

Sleeping for 500 milliseconds

:Sending Pointer ACTION_MOVE x=-2.0 y=3.0

:Sending Pointer ACTION_MOVE x=4.0 y=-3.0

:Sending Pointer ACTION_MOVE x=-5.0 y=-3.0

:Sending Pointer ACTION_MOVE x=3.0 y=4.0

:Sending Pointer ACTION_MOVE x=-4.0 y=1.0

:Sending Pointer ACTION_MOVE x=-1.0 y=-1.0

:Sending Pointer ACTION_MOVE x=-2.0 y=-4.0

如果Monkey测试顺利执行完成,在log的最后,会打印出当前执行事件的次数和所花费的时间;// Monkey finished代表执行完成.Monkey执行中断,在log的最后也能查看到当前已执行的次数.Monkey执行完成的log具体如下:

Events injected: 6000

:Dropped: keys=0 pointers=9 trackballs=0 flips=0

## Network stats: elapsed time=808384ms (0ms mobile, 808384ms wifi, 0msnot connected)

// Monkey finished                   

三、 Android测试常用命令

1. 台设备的操作

如果有多个模拟器/设备实例在运行,在发布adb命令时必须指定一个目标实例. 这样做,请使用-s选项的命令:

adb -s <serialNumber> <command>

adb devices 命令来获得运行着的模拟器/设备实例的serialNumber

示例如下:

1)adb devices,发现有2个device

 

2)安装软件到第一台设备

 

注意:adb –s必须相邻,中间不得插入任何其他参数,包括shell!

此格式适用于所有adb命令!

2. 本地手机文件互传

1、adb push <本地文件> <手机目录>

 

有时会有fail提示,Is a directory,此时需在设备目录结尾加 /,如:

 

2adb pull <手机文件> <本地目录>

 

注意:

1)手机目录是左斜杠“/”,windows目录是右斜杠“\”

2)所有目录及文件名不可含空格!

3)若目标目录以文件名结尾,可实现重命名功能,如第二条命令

3、push文件夹

 

注意:

1)文件夹目录后不加“\”

2)此命令会将ISO文件及子文件夹所有文件全部push到手机

3)pull命令格式相同

4、push命令构造系统空间不足

前提:Root

adb push 本地文件 /data/local/tmp

将会填充系统空间直至0!可轻松构造系统空间不足!

适用场景:

1)某些手机系统空间到一定占比时无法copy文件或安装软件

2)构造系统空间临界点,如占比到88%时通知栏提醒

3. 安装与卸载软件

1、安装:install xx.apk如:

adb install D:\x.apk  ——默认安装在手机内存,且apk文件名不可带中文和空格

adb install –s D:\x.apk  —— -s(SD)将apk安装到外置SD卡

adb install -r D:\x.apk—— -r(reinstall)表示重装该apk,即覆盖安装 

注:

使用install命令,apk包会在应用安装完成后自动删除!

常用install错误提示含义:

INSTALL_FAILED_ALREADY_EXISTS

程序已经存在

INSTALL_FAILED_INVALID_APK

无效的APK

INSTALL_FAILED_INVALID_URI

无效的链接

INSTALL_FAILED_INSUFFICIENT_STORAGE

没有足够的存储空间

INSTALL_FAILED_DUPLICATE_PACKAGE

已存在同名程序

INSTALL_FAILED_NO_SHARED_USER

要求的共享用户不存在

INSTALL_FAILED_UPDATE_INCOMPATIBLE

版本不能共存

INSTALL_FAILED_SHARED_USER_INCOMPATIBLE

需求的共享用户签名错误

INSTALL_FAILED_MISSING_SHARED_LIBRARY

需求的共享库已丢失

INSTALL_FAILED_REPLACE_COULDNT_DELETE

需求的共享库无效

INSTALL_FAILED_DEXOPT

dex优化验证失败

INSTALL_FAILED_OLDER_SDK

系统版本过旧

INSTALL_FAILED_CONFLICTING_PROVIDER

存在同名的内容提供者

INSTALL_FAILED_NEWER_SDK

系统版本过新

INSTALL_FAILED_TEST_ONLY

调用者不被允许测试的测试程序

INSTALL_FAILED_CPU_ABI_INCOMPATIBLE

包含的本机代码不兼容

CPU_ABIINSTALL_FAILED_MISSING_FEATURE

使用了一个无效的特性

INSTALL_FAILED_CONTAINER_ERROR

SD卡访问失败

INSTALL_FAILED_INVALID_INSTALL_LOCATION

无效的安装路径

INSTALL_FAILED_MEDIA_UNAVAILABLE

SD卡不存在

INSTALL_FAILED_INTERNAL_ERROR

系统问题导致安装失败

DEFAULT

未知错误

 

1、设备所有已安装包都在/data/data目录下,查看需要管权限

 

2、也可使用pm命令(package manager)

1.查看当前连接设备或者虚拟机的所有包

abd shell pm list packages

2.只输出系统的包

adb shell pm list packages -s

3.输出所有第三方包

adb shell pm list packages -3

4.输出包和包相关联的文件(安装路径)

adb shell pm list packages -f

5.输出包和安装信息(安装来源)

adb shell pm list packages -i

6.输出包含过滤条件的包

adb shell pm list packages “lzy”

7.只输出启用的包

adb shell pm list packages -e

8.只输出禁用的包

adb shell pm list packages -d

9.只输出包和未安装包信息(安装来源)

adb shell pm list packages -u

10. 定位apk所在系统路径

adb shell pm path packages 

11.从手机把apk pull下来

 adb pull <remote> [<local>] 

3、也可使用包名查看器”查看,请自行so.com~

4. 生成Log日志

adb logcat常用命令

1)清除当前操作之前所有log:adb logcat –c —— -c(clean)

2)保存log到本地:adb logcat -d > D:\123.log ——此命令在时间上倒过来用,即先操作,再敲此命令;打出来的log就是你刚操作那段时间的log,而且自动退出log模式

3)显示某一tag的log:adb logcat -s tag —— 在测试产品是否关闭某些打印log时很有效

4)过滤自定义字段的log:adb logcat |findstr –i crash—— -i(ignore),过滤关键字为qihoo的log,忽略qihoo大小写(关键字可不加引号)

5)以某种格式保存log:adb logcat –v time –d >D:\123.log —— log显示time.

还有其他参数可选:

brief — 显示优先级/标记和原始进程的PID (默认格式)

process — 仅显示进程PID

tag — 仅显示优先级/标记

thread — 仅显示进程:线程和优先级/标记

raw — 显示原始的日志信息,没有其他的元数据字段

time — 显示日期,调用时间,优先级/标记,PID

long —显示所有的元数据字段并且用空行分隔消息内容

5. 查看内存与进程

1. 查看系统内存

adb shell cat /proc/meminfo

 

2. 查看进程内存

使用adb shell dumpsys meminfo <package name>

 

Naitve Heap Size: 从mallinfo usmblks获得,代表最大总共分配空间

Native Heap Alloc: 从mallinfo uorblks获得,总共分配空间

Native Heap Free: 从mallinfo fordblks获得,代表总共剩余空间

Native Heap Size 约等于Native Heap Alloc + Native Heap Free

mallinfo是一个C库, mallinfo函数提供了各种各样的通过C的malloc()函数分配的内存的统计信息

Dalvik Heap Size:从Runtime totalMemory()获得,Dalvik Heap总共的内存大小.

Dalvik Heap Alloc: Runtime totalMemory()-freeMemory() ,Dalvik Heap分配的内存大小.

Dalvik Heap Free:从Runtime freeMemory()获得,Dalvik Heap剩余的内存大小.

Dalvik Heap Size 约等于Dalvik  Heap Alloc + Dalvik  Heap Free

 

其他类型               smap 路径名称          描述

Cursor                  /dev/ashmem/Cursor   Cursor消耗的内存(KB)

Ashmem               /dev/ashmem          匿名共享内存用来提供共享内存通过分配一个多个进程可以共享的带名称的内存块

Other dev             /dev/                    内部driver占用的在 “Other dev”                                                 

.so mmap             .so                       C 库代码占用的内存

.jar mmap            .jar                       Java 文件代码占用的内存

.apk mmap           .apk                      apk代码占用的内存

.ttf mmap              .ttf                      ttf 文件代码占用的内存

.dex mmap             .dex                      Dex 文件代码占用的内存

Other mmap                                     其他文件占用的内存

3. 查看进程是否被kill

cat /proc/kmsg |grep <package name>

 

1. 其他查看命令

ps r ——显示运行中的进程

ps |grep <keyword> ——显示包含关键字的进程

adb shell dumpsys cpuinfo <package name>——查看package 关联的cpu占用情况

2. 查看系统信息

adb shell cat /system/build.prop

build.prop 是一个属性文件,在Android系统中.prop文件很重要,记录了系统的设置和改变,类似於/etc中的文件

部分信息如图所示:

 

需要时可加findstr过滤

 

 

上一篇:Android- 各种常用命令,杂乱记忆


下一篇:[图像识别]Pytorch搭建预训练VGG16实现10 Monkey Species Classification