Android(3) —— 环境配置、手机端界面设计

前言

当前,深度学习有很多框架:tensorflow、pytorch、caffe、keras等。很多场景下,需要训练好的模型在移动端运行。移动端的框架又有很多TensorFlow Lite、Core ML、NCNN、MNN等等。
其中 tensorflow 所对应的移动端移植框架 TensorFlow Lite。在自己这个系列记录使用 调用tfile进行神经网络预测的android的实现。

整个记录为:
Android(1) —— Android studio 开发环境搭建
Android(2) —— Android Studio找不到连接的手机
Android(3) —— 环境配置、手机端界面设计
Android(4) —— 图像分类的*.tfile的使用 Classify.java
Android(5) —— 安卓机通过相机或相册获取图片PhotoUtil.java
Android(6) —— 主函数的详解 MainActivity.java


该篇博客讲解的为:使用 Android 编写一个APP,来调用神经网络模型。来完成神经网络的预测,在这里以图像分类为例。整篇博客,有直接工程配置的操作,也有以下相关知识的记录,为了方便阅读,会在实际操作的章节开始注上【实际操作】

1 环境配置

1.1 新建工程

【实际操作】
在这里插入图片描述
在这里插入图片描述

1.2 工程文件介绍

在这里插入图片描述
我们以当前路径为根路径。

[1] app/libs:第三方的库文件。
[2] app/src/main/assets:应用中引用到的一些外部资源文件。图片,音频,视频等。这些资源是以原始格式保存,且只能用编程方式读取。
[3] app/src/main/java:源文件,主要 是完成java代码的编写
[4] app/src/main/res:资源文件,但与assets不同。里面的所有文件在 R.java 里面生成相应的 id,id 是该资源文件在此工程中的唯一标识符

  • ./res/drawable*:存放的是工程图片的信息(默认png)。每一张需要三个版本,高/中/低 分辨率(手机分辨率有差别)
    ./res/layout:存放的是工程的布局文件,以 .xml 的格式保存
    ./res/value:存放的是工程的数据文件,以 .xml 格式保存。主要文件种类如下
        a) strings.xml:存放的是自定义的字符串和数值,可手动修改,对应内部类名称–string
        b) arrays.xml:用来定义数组,对应内部类名称–array
        c) color.xml:用来定义颜色和颜色字符串数值,对应内部类名称–color
        d) dimens.xml:用来定义尺寸数值,对应内部类名称–dimen
        e) styles.xml:用来定义样式,对应内部类名称–style

[5] app/src/main/AndroidManifest.xml:是整个工程的配置文件(部分属性解释附在最后)
[6] app/build.gradle:工程编译的配置

  • apply plugin:声明是 Android 应用程序还是库模块;
    • com.android.application 表示这是一个应用程序模块,可直接运行
    • com.android.library 标识这是一个库模块,是依附别的应用程序运行
  • android 闭包:配置项目构建的各种属性,compileSDKVersion 用于指定项目的变异 SDK 版本, buildToolsVersion 用户指定项目构建工具的版本。
    • defaultConfig 闭包:默认配置、应用程序包名、最小sdk版本、目标sdk版本、版本号、版本名称;
    • buildTypes 闭包:指定生成安装文件的配置,是否对代码进行混淆;
    • signingConfigs 闭包:签名信息配置;
    • sourceSets 闭包:源文件路径配置;
    • lintOptions 闭包:lint 配置;
  • dependencies 闭包,指定当前项目的所有以来关系,本地以来,库依赖以及远程依赖;
  • repositories 闭包,仓库配置

1.3 环境配置

1.3.1 Android App中使用TF Lite

Tensorflow Lite旨在简化机器学习应用于终端设备的过程。(终端设备处于网络边缘,所以叫边缘计算),在终端设备而非服务器上计算。有以下优点:

  • 低延迟、隐私性更好、不需要连接网路、功耗低

在android的app上使用tensorflow lite 有以下方式

  1. 使用JCenter托管的Tensorflow Lite AAR
    在 ./app/build.gradle中添加如下内容。自己在使用这个方式时,直接就 Sync 成功了。并没有遇到其他博主说的源的问题,以及需要相应设置。(如果后期遇到,再做补充)
dependencies {
   implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly'
   } 
  1. 使用本地的TensorFlow Lite AAR
    把AAR放到工程的libs目录内,然后在 ./app/build.gradle中添加如下内容。
// 添加 libs 路径
repositories{
   flatDir{
       dirs 'libs'
   }
}
dependencies {
   implementation (name:'tensorflowlitenightly',ext:'aar')//添加tensorflow依赖
   } 

1.3.2 三方库的配置

【实际操作】
该工程是使用基于tensorflow框架的神经网络模型,进行图像分类。所以我们需要2个三方库:(1) tensorflow:用作模型预测;(2) Glide:用作图像显示等操作。流程如下(使用本地的aar文件为例):

  • 备好文件tensorflowlitenightly.aar、model.tfile
  • 将 tensorflow.aar 放置 ./app/libs 路径下
  • 将 model.tfile 放置 ./app/src/main/assets 路径下
  • 打开 ./app/build.gradle,需要修改:
    • (1) 添加 libs 路径;(2) 添加三方库名;(3) 指定 model.tfile 模型不压缩
android {
   ......
   //指定不压缩的文件格式
   aaptOptions {
       noCompress "tflite"
   }
}

// 添加 libs 路径
repositories{
   flatDir{
       dirs 'libs'
   }
}

dependencies {
   implementation fileTree(dir: 'libs', include: ['*.jar'])
   implementation 'androidx.appcompat:appcompat:1.0.2'
   implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
   testImplementation 'junit:junit:4.12'
   androidTestImplementation 'androidx.test.ext:junit:1.1.0'
   androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
   // 添加 tensorflow、Glide的依赖
   implementation 'com.github.bumptech.glide:glide:4.3.1'
   implementation (name:'tensorflowlitenightly',ext:'aar')//添加tensorflow依赖
}


1.3.3 AndroidManifest.xml 中的配置

【实际操作】

  1. 该应用中会使用到相机或者相册,涉及的权限有:相机权限、对SD卡读写权限。所以需要在 AndroidManifest.xml 中对相应的权限进行声明。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.example.classify">
   <uses-permission android:name="android.permission.CAMERA" />
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
   ......
   
  1. 另外,由于工程中会用到 FileProvider,所以需要在 AndroidManifest.xml 文件中进行声明。
    <application
       ......
       <provider
           android:name="androidx.core.content.FileProvider"
           android:authorities="${applicationId}.provider"
           android:exported="false"
           android:grantUriPermissions="true">
           <meta-data
               android:name="android.support.FILE_PROVIDER_PATHS"
               android:resource="@xml/file_paths" />
       </provider>
   </application>
    
  1. 上面的android:resource="@xml/file_paths",表示可以对外提供共享的路径(用于存放相机拍照后,照片的保存路径)。所以编写相关信息。
    在 ./app/src/main/res 路径下创建文件 ./xml/file_paths.xml。脚本内容为:
<?xml version="1.0" encoding="utf-8"?>
<resources>
   <external-path
       name="images"
       path="lite_mobile/" />
</resources>

2 界面设计

2.1 界面展示

打开文件 ./app/src/res/layout/activity_main.xml。编辑该脚本,完成应用的界面设计。

这里做一个简单展示的界面,如下图
在这里插入图片描述
手机端APP打开界面如下图:
在这里插入图片描述

2.2 脚本编写

【实际操作】

  • wrap_content:wrap 翻译过来是包裹,conten是内容。那么这个就是包裹内容的意思,也就是说你的控件里面的内容有多大,这个控件就有多大。
  • android:id:给控件添加一个id 这个新的id会自动生成在 R.java文件里面,就能在你的Activity里面通过这个id来引用对象了 。如果你写成是@id/aaa则是代表引用id列表里面的aaa的值。

相关api的使用这里就不做介绍了,直接记录代码内容。


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">

   <LinearLayout
       android:id="@+id/btn1_ll"
       android:layout_width="match_parent"
       android:layout_height="wrap_content" 
       android:layout_alignParentBottom="true"
       android:orientation="horizontal"> <!--下面两个按键横向摆放-->

       <Button
           android:id="@+id/use_photo"
           android:layout_width="0dp"
           android:layout_height="wrap_content"
           android:layout_weight="1"
           android:text="相册" />

       <Button
           android:id="@+id/start_camera"
           android:layout_width="0dp"
           android:layout_height="wrap_content"
           android:layout_weight="1"
           android:text="拍照" />
   </LinearLayout>

   <LinearLayout
       android:id="@+id/btn2_ll"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_above="@id/btn1_ll"
       android:orientation="horizontal">

       <Button
           android:id="@+id/load_model"
           android:layout_width="0dp"
           android:layout_height="wrap_content"
           android:layout_weight="1"
           android:text="加载模型" />

   </LinearLayout>

   <TextView
       android:id="@+id/result_text"
       android:layout_width="match_parent"
       android:layout_height="150dp"
       android:layout_above="@id/btn2_ll"
       android:hint="预测结果会在这里显示"
       android:inputType="textMultiLine"
       android:textSize="16sp"
       tools:ignore="TextViewEdits" />

   <ImageView
       android:id="@+id/show_image"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:layout_above="@id/result_text"
       android:layout_alignParentTop="true" />

</RelativeLayout>

3 附件

AndroidManifest.xml 部分属性介绍

  • 1 manifest -> package=“com.android.helloworld”
    表示整个java应用程序的主要包名,而且是一个默认的程序名称
  • 2 manifest -> android:versionCode=“1”
    表示该工程生成的apk版本号,主要是用于版本升级所用,代表着app更新的次数,是int类型,以1开始,而后2、3、4…依次 往后递增,只要判断该值就能确定是否需要升级。
  • 3 manifest -> android:versionName=“1.0”
    这个是我们常说的版本号,其实就是显示给用户的版本名称,由三部分组成..,该值是个字符串,可以显示给用户,由1.0开始,而后可以1.1、2.0等往后递增。
  • 4 manifest -> android:installLocation=""
    此属性是设置apk文件的安装位置,有三个选项,解释如下:
    • android:installLocation=“auto”:若将此属性值设置为auto则表示让apk自动寻找安装的地方,ROM或者SDcard任意选择,适用于小型apk文件,此值为默认值
    • android:installLocation=“internalOnly”:若将此属性值设置为internalOnly则表示此apk仅仅只能安装在ROM上
    • android:installLocation=“preferExternal”:若将此属性值设置为preferExternal则表示此apk会直接安装在SDcard上,适用于大型apk文件,如:大型游戏
  • 5 manifest -> application -> android:icon="@drawable/ic_launcher"
    此属性表示应用程序的一个图片,即安装完成后所展示的图标,即logo图片
  • 6 manifest -> application -> android:label="@string/app_name"
    此属性表示应用程序的工程的文字说明,即安装完成后所显示的名称,即程序的应用名称
  • 7 manifest -> application -> activity -> android:name=“com.android.helloworld.MainActivity”
    此属性表示整个应用程序的主程序的名称
  • 8 manifest -> application -> activity -> intent-filter
    意图过滤器,用来过滤用户的一些动作和操作
    • <action android:name=“android.intent.action.MAIN” />:表示过滤的动作,设置此条信息(主要是设置字符串android.intent.action.MAIN)表示当前的程序是工程的入口程序
    • <category android:name=“android.intent.category.LAUNCHER” />:表示决定应用程序是否在程序列表中显示
  • 9 manifest -> uses-sdk -> android:minSdkVersion=“8”
    此属性表示最小的 SDK 版本,这个值是对应 Android 不同版本的 API Level , 如 Android 1.5 对应 3,Android 1.6 对应 4,Android 2.1 对应7,Android2.2对应8 ,Android 2.3.3 对应10等等。当用户指定这个值后,Android 系统会用这个指定的值对应的 SDK 版本去编译你的应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值