Android 知识分享

316 阅读6分钟

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的声明。