Android项目目录结构:
sign-android:
.gradle------------使用studio打开会生成
.idea-------------- 基于idea的ide都会有的目录
app---------------具体的项目源文件(需要上传git)
build-----------构建文件
src
main
AndroidManifest.xml-----主要是配置app图标,定义权限,配置<activity>,<receiver>,<provider>,<service>这android中的四大组件
java--------------此目录主要是处理逻辑代码
res---------------此目录主要是放置各种资源文件和布局文件(这里的文件均可以通过R.文件夹主名称.文件名称进行资源获取)
drawable-anydpi-----------主要是存放各个尺寸的资源图片(各种背景,箭头,按钮... 资源文件)
layout--------------------各种activity,fragment,item布局文件
mipmap-anydpi-------------存放各个尺寸的资源图片(一般是app Icon)
values---------各种资源值
colors--------定义各种颜色
strings-------定义各种字符串
styles--------各种style
themes--------定义全局的各种主题
xml------------各种xml配置文件
anim-----------动画
animator-------属性动画
navigation-----Jectpack导航图对应文件夹,与Navigation库协同使用,一种新的方式管理fragment
build.gradle----------------主工程的构建脚本文件
proguard-rules.pro-----------混淆配置文件,如果在app/build.gradle minifyEnabled 设置为了true,需要配置该文件,比如需要序列化的实体,需要禁止混淆。
build-------------构建文件
gradle------------gradle的版本信息(需要上传git)
build.gradle------root的gradle构建文件(需要上传git)
repositories 节点:
repositories{
配置依赖的拉取地址
例如mavenCentral()
maven{url 'https://jitpack.io'}
}
gradle.properties--定义堆栈内存,第三方库是否迁移到Androidx(需要上传git)
gradlew------------gradlew在linux下的脚本文件(需要上传git)
gradlew.bat--------gradlew.bat 在windows下的脚本文件(需要上传git)
local.properties----配置sdk和ndk的路径(需要上传git)
settings.gradle-----配置项目包含的源文件目录和依赖目录(需要上传git)
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.cowain.sign">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<application
android:name="com.cowain.App" 继承自android.app.Application 类的自定义类(需要自定义初始化功能的时候需要自定义此类,进行初始化操作,一般情况下都需要自定义)
android:allowBackup="true" 每次运行是否保存用户数据
android:icon="@drawable/cowain" app图标
android:label="@string/app_name"app名称
android:networkSecurityConfig="@xml/net_security_config"配置开启http明文传输
android:roundIcon="@drawable/cowain"app圆形图标
android:supportsRtl="true" 是否支持Right to Left
android:theme="@style/AppTheme" app主题
tools:targetApi="n">
<activity
android:name=".ui.login.LoginActivity" 自定义的activity
android:exported="true">
<intent-filter> 代表是启动页面
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ui.main.MainActivity" />
<activity android:name=".ui.camera.CameraActivity" />
<!-- <activity-->
<!-- android:name="com.yalantis.ucrop.UCropActivity"-->
<!-- android:screenOrientation="portrait"-->
<!-- android:theme="@style/Theme.AppCompat.Light.NoActionBar" />-->
<activity android:name="com.soundcloud.android.crop.CropImageActivity" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.cowain.sign.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>
app的build.gradle
//说明文档:https://www.csdn.net/tags/MtzaggzsNDY1NzAtYmxvZwO0O0OO0O0O.html
plugins {
id 'com.android.application' 代表该module是一个应用
id 'com.android.library' 代表该module是一个library
}
apply plugin: 'kotlin-android'
android {
// 指定编译的SDK版本号 如29表示Android 10 编译
compileSdk 32
defaultConfig {
// 指定该模块的应用编号,即App的包名。该参数为自动生成,无需修改
applicationId "com.cowain.sign"
// 指定App适合运行的最小SDK版本号。如16表示至少要在Android4.1上运行
minSdk 21
// 指定目标设备的SDK版本号。即该App最希望在哪个版本的Android上运行
targetSdk 29
// 指定App的应用版本号
versionCode 1
// 指定App的应用版本名称
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildFeatures {
viewBinding true 代表启用viewBinding 使用xml书写布局,Android官方推荐的控件获取方案
}
签名配置
signingConfigs {
release {
storeFile file("../key/sign.jks") 签名文件的路径
storePassword "cowain" 签名文件密码
keyPassword "cowain" 签名文件key别名密码
keyAlias "cowain" 签名文件key别名
}
}
buildTypes {
release {
// 指定是否开启代码混淆功能。true表示开启混淆,false表示无需混淆。
minifyEnabled false
// 指定代码混淆规则的文件名
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release 构建release使用的签名文件
}
debug {
signingConfig signingConfigs.release 构建debug使用的签名文件
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 源码编译使用java8特性
targetCompatibility JavaVersion.VERSION_1_8
}
}
// 指定App编译的依赖信息
dependencies {
// 指定引用jar包的路径
// implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation files("libs/core-3.2.1.jar")
implementation files("libs/printsdk1015-v2.2.jar")
implementation files("libs/PrintUtils1114.jar")
// UsbDriver应该依赖此jar , 但是无法编译通过 , 因此新建了com.printsdk.usbsdk.UsbDriver , 后续解决编译问题后可以依赖该jar
// implementation files("libs/usbprintsdk-v2.11.jar")引入jar或者aar依赖
//滚动选择组件
implementation project(':wheelview') 引入library依赖
}
Android 6.0 之后危险权限申请步骤:
Android 6.0 之后引入了动态权限申请,目的在于更好的保护用户隐私权限,可以做到危险权限在需要的时候在申请,而不是每次进入app一次性申请大量危险权限
常用危险权限
Camera,Bluetooth,WRITE_EXTERNAL_STOREGE,READ_EXTERNAL_STOREGE
需要动态申请危险权限列表
private val permissions = listOf(Manifest.permission.CAMERA)
申请权限
ActivityCompat.requestPermissions(
this,
permissions.toTypedArray(),
permissionsRequestCode
)
申请结果回调
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
这里的requestCode就是上面申请方法最后一个参数对应的值
if (requestCode == permissionsRequestCode && hasPermissions(this)) {
bindCameraUseCases()
} else {
finish() // If we don't have the required permissions, we can't run
}
}
Android 控件绑定演进之路
最基础的方法是使用findViewById(R.id.控件ID) 后来出现了一个基于反射实现的一个控件绑定框架 ButterKnife,跟findVIewById对比稍微简介了一些,但是 需要定义很多@BindView(R.id.控件ID) val TextView tvName;这样类似的代码 后来jetbrains 推出了
Activity 启动模式
Standard 每次startActivity都会创建一个新的实例
SingleTop 栈顶复用
SingleTask 栈内复用
SingleInstance 全局复用
Intent (意图)
主要是用来实现Activity 跳转,启动广播,启动Service,调用系统已有的拍照,裁剪,图库,图片选择......功能。
传值
接受值
回传值
一年前使用的API
startActivityForResult API 和 onActivityResult API
目前使用的API
第三方框架 Arouter(阿里的路由框架,这个路由跟前端的路由是一个意思)
线程相关
Android主线程就是UI线程,所以,目前只要需要执行耗时操作(例如,数据库读写,网络请求.....),需要为耗时任务提供一个新的线程,即java中的new Thread 对应的runnable中的代码块,如果在主线程进行网络请求,系统会直接抛出NetworkOnMainThreadException 异常,当子线程执行完毕之后,通过android.os.Handler 类对象的postXXX 方法传递结果,在Handler回调中的handleMessage处理code对应的事件。如果使用了协程,该场景将大大简化。
64k方法数目问题
默认情况下,Android默认不采取分包方式,当方法(包含自己定义的方法和引入依赖的方法)数目超过65535的时候,需要进行分包处理 步骤:后续补充
ANR(Appliction Not Response)
这个错误一般都是在主线程执行了耗时操作,解决方案:不要在主线程中执行耗时操作。
ClassNotFoundException
Android中一般情况下出现这个异常一般是依赖没有引入成功,或者是开启了混淆并没有在pro文件中进行排除(最常见的就是网络请求对应的实体类没有在pro文件中进行排除)
doing too much work on its main thread
一般情况下造成此问题的原因是app启动后,启动的页面有较大的图片需要渲染到界面,导致App主线程任务繁重,可以考虑将大分辨率图片从drawable-低dpi 迁移到drawable-高dpi,mipmap文件夹也是一样的处理方式。
startActivity 导致app崩溃
一般情况下是没有在AndroidManifest.xml 文件中进行activity的声明。