Android Studio,使用技巧,問題記錄和一些好用的插件

使用技巧

根據不同 buildType 使用不同包名和資源

比如在 production,development,qa 不同階段使用不同的 packageName 和 authority,在 build.gradle 中配置如下:

productFlavors {
        production {
            applicationId = "com.myapp.app"
            resValue "string", "authority", "com.非死book.app.非死bookContentProvider5435651423234"
        }
        development {
            applicationId = "com.myapp.development"
            resValue "string", "authority", "com.非死book.app.非死bookContentProvider2134564533421"
        }
        qa {
            applicationId = "com.myapp.qa"
            resValue "string", "authority", "com.非死book.app.非死bookContentProvider29831237981287319"
        }
}

通過 resValue 方法設置的資源會在 R 文件生成對應的 id。

在 AndroidManifest.xml 中使用 authority 字符串

<provider
    android:name="com.非死book.非死bookContentProvider"
    android:authorities="@string/authority"
    android:exported="true" />

替換 AndroidManifest.xml 中的占位符

使用 manifestPlaceholders 可以定義相關字段替換 AndroidManifest.xml 中的占位符。

格式:manifestPlaceholders = [ key1:"value1", key2:"value2", ... ]

下面是一個示例:

android {

defaultConfig {
    def authorityName = "com.linchaolong.android.app.droidplugin_stub"
    manifestPlaceholders = [
        authorityName:"${authorityName}",
        key:"value",
    ]
}

}</code></pre>

說明:manifestPlaceholders 是一個 map。

在 AndroidManifest.xml 中通過 ${key} 引用相關字段。

自定義 BuildConfig 字段

通過 buildConfigField 可以添加自定義的字段到 BuildConfig 中。

格式:buildConfigField "type", "key", "value"

android {
    defaultConfig{
        def authority = "com.linchaolong.android.app"
        buildConfigField "String", "AUTHORITY", "\"${authority }\""
        buildConfigField "int", "FOO", "42"
        buildConfigField "String", "FOO_STRING", "\"foo\""
        buildConfigField "boolean", "LOG", "true"
    }
}

def 操作符可用于定義變量和函數。

在 java 代碼中你可以通過 BuildConfig.key 訪問對應的字段,比如: BuildConfig.AUTHORITY 訪問 AUTHORITY 常量。

統一管理不同 module 依賴庫的版本

  1. 新建一個 config.gradle 在工程根目錄下,并添加一些全局的配置:

    allprojects {
    repositories {
     jcenter()
    }

    ext{ compileSdkVersion = 25 buildToolsVersion = "25.0.0" minSdkVersion = 14 targetSdkVersion = 25

    support = '25.0.0' play_services = '9.8.0'

    rxjava = '2.0.1'

    // Json gson = '2.8.0'

    // HTTP okhttp = '3.4.1' retrofit = '2.1.0' glide = '3.7.0'

    // DEPS INJECTION dagger = '2.6'

    // VIEW INJECTION butterknife = '8.4.0'

    // DEBUG stetho = '1.4.1' } }</code></pre> </li>

  2. 然后在 project-level 下的 build.gradle 添加如下配置應用 config.gradle :

    apply from: rootProject.file('config.gradle')
  3. 在各 module 的 build.gradle 引用 ext 中的字段

    • 在 android 塊中引用 ext 中的字段

      android {
      compileSdkVersion project.ext.compileSdkVersion
      buildToolsVersion project.ext.buildToolsVersion
      defaultConfig {
         applicationId "linchaolong.demo"
         minSdkVersion project.ext.minSdkVersion
         targetSdkVersion project.ext.targetSdkVersion

      def QQ_APPID = rootProject.ext.QQ_APPID manifestPlaceholders = [QQ_APPID:"${QQ_APPID}"] } }</code></pre> </li>

    • 在 dependencies 塊下引用 ext 中的字段

      dependencies {
      compile "com.android.support:appcompat-v7:$support"
      // Debug
      compile "com.非死book.stetho:stetho:$stetho"
      compile "com.非死book.stetho:stetho-okhttp3:$stetho"
      debugCompile "com.非死book.stetho:stetho-js-rhino:$stetho"
      // Json
      compile "com.google.code.gson:gson:$gson"
      // Butterknife
      compile "com.jakewharton:butterknife:$butterknife"
      annotationProcessor "com.jakewharton:butterknife-compiler:$butterknife"
      // RxJava
      compile "io.reactivex.rxjava2:rxjava:$rxjava"
      compile "io.reactivex.rxjava2:rxandroid:$rxjava"
      }

      嚴重注意:引用 ext 中字段時要使用雙引號,不能是單引號。格式為 ${key} 或 $key

    • </ul> </li> </ol>

      建立各 Module 共享的配置

      比如,這里想統一設置各 Module 支持的 so 庫架構,可以在工程目錄下新建一個 module.gradle 存放共享的配置,配置如下:

      // Module 共享的配置
      android {
        defaultConfig {
          ndk {
            //設置支持的SO庫架構
            abiFilters 'armeabi-v7a' //, 'armeabi' , 'x86', 'x86_64', 'arm64-v8a'
          }
        }
      }

      然后,在各 Module 下的 build.gradle 配置中應用 module.gradle,示例如下:

      apply plugin: 'com.android.application'
      apply from: rootProject.file('module.gradle')

      自定義 release apk 名稱

      修改 build.gradle 配置如下:

      android {
        buildTypes {
          release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
            // 自定義 release apk 名稱
            applicationVariants.all { variant ->
              variant.outputs.each { output ->
                def releaseTime = new Date().format('yyyyMMddHHmmss')
                // 修改 release apk 名稱,app_1.0_20170108224145.apk
                def fileName = output.outputFile.name.replace("-release", "_${defaultConfig.versionName}_"+releaseTime)
                output.outputFile = new File(output.outputFile.parent, fileName)
              }
            }
          }
        }
      }

      手動 build 工程

      我們應該都或多或少遇到過這種情況,當我們第一次打開一個項目時,該項目會先下載相關的依賴項,如果很多的話,將會等很久,而且又不能做其他操作,這樣太浪費時間了。

      Image

      下面說說如何在命令行中手動 build 工程:

      每個 android studio 工程下應該都會有 gradlew.bat (Windows) 和 gradlew (Mac) 兩個腳本文件,我們可以打開命令行,cd 到工程目錄下,通過執行 gradlew.bat build 命令,手動去構建工程。

      Image

      通過在命令行構建工程可以不影響當前工作,而且構建完成后再使用 android studio 打開該工程將會比較快。

      手動下載和替換本地 gradle/jar

      build 過程很慢?這個多數是由于個別依賴項下載速度過慢引起的,有時還會卡在某個點,但我們可以通過手動下載替換解決該問題。

      這里分為兩個部分,一個是 gradle 的下載替換,一個是依賴庫的下載替換。

      我們通過在命令行執行 gradlew.bat build 命令可以看到相關依賴的下載地址:

      Paste_Image.png

      正常下載速度可能只有幾十KB(可能更低...),但是如果我們把下載鏈接 copy 到迅雷下載,它是這樣的:

      Paste_Image.png

      在 windows 下,gradle 存放目錄就在 C:\Users\用戶名\.gradle\wrapper\dists 下。下載完成后,把 *.lck 和 *.zip.part 文件刪掉,替換為我們剛下載的 .zip 。

      Paste_Image.png

      重新執行 gradlew.bat build 命令可以看到它將會自動解壓該 *.zip 文件。

      Paste_Image.png

      在 windows 下,依賴庫的存放目錄就在 C:\Users\用戶名\.gradle\caches 。jar文件的下載替換也是同理,比如我這里下載一個 common-25.3.0-alpha2.jar ,下載完成后把它放在 common-25.3.0-alpha2.pom 同級目錄下,重新執行 build 命令即可。

      Paste_Image.png

      這里的目錄路徑可能和你的不太一樣,可以使用 Everything 搜索一下文件名。

      構建一個aar文件

      如果你的 module 聲明為 android library(即在 build.gradle 文件中使用 apply plugin:'com.android.library' ),它將在構建時輸出 .aar 文件,在 module 的 build/outputs/aar 目錄下。

      你可以選擇該 module ,然后 Build —> Make Module * 構建該 module。或者使用 gradlew.bat build 命令構建工程。然后就可以在輸出目錄下找到 .aar 文件了。

      Paste_Image.png

      引用 aar 文件

      假設把 aar 文件放在 module 下的 libs 目錄。

      Paste_Image.png

      引用本 module 的 aar 文件 build.gradle 配置如下:

      repositories{
        flatDir{
          dirs 'libs'
        }
      }
      dependencies {
        compile(name:'stetho_realm-release', ext:'aar')
      }

      如果是引用其他 module 的 aar 文件,還要在本 module 的 build.gradle 中配置被引用 module 的 aar 目錄,否則會找不到文件。

      repositories {
        flatDir {
          dirs project(':Library').file('libs')
        }
      }

      多個目錄使用 “,” 分隔

      快捷鍵

      由于 Android Studio 是基于 IDEA 的,所以很多快捷鍵是通用的。

      全局替換

      Edit —&gt; Find —&gt; Replace in Path

      Replace in Path

      動態調試app

      1.在源碼先打斷點,點擊掛接 Android 進程按鈕。

      Paste_Image.png

      2.選擇 app 進程,點OK,開始調試。

      Paste_Image.png

      一些好用的插件

      插件安裝說明:

      • 在線安裝
        打開 File ——> Settings ——> Plugins ——> Browse repositories... 搜索插件名,點 Install 下載安裝,安裝完成后重啟生效。
      • 離線安裝
        下載插件安裝包,打開 File ——> Settings ——> Plugins ——> Install plugin from disk... 選擇插件安裝包,安裝完成后重啟生效。

      GsonFormat

      GsonFormat 是一個可以快速將 JSON 字符串轉換為 Entity 類的插件。

      GsonFormat

      使用說明: Alt + S 調出 GsonFormat,或者 Alt Insert + GsonFormat 。

      在 Settings 中選擇 filed(public) ,Enter 保存修改,可以只生成 public 字段,不生成一大堆的 getter 和 setter,代碼會更簡潔些。

      插件地址: https://plugins.jetbrains.com/idea/plugin/7654-gsonformat

      Github地址: https://github.com/zzz40500/GsonFormat

      Android ButterKnife Zelezny

      Android ButterKnife Zelezny 是 Android 下的注解框架 ButterKnife 的輔助插件,用于一鍵生成 Butterknife 視圖注入代碼。

      Android ButterKnife Zelezny

      使用說明:把光標停在 setContentView(R.layout.activity_settings) 那行中的 activity_settings
      上右鍵選擇 Generate ( alt + insert )→ Generate Butterknife Injections

      注意:需要把光標停在 layout 的名稱上才能調出 ButterKnife Zelezny 。

      ButterKnife: https://github.com/JakeWharton/butterknife

      插件地址: https://plugins.jetbrains.com/idea/plugin/7369-android-butterknife-zelezny

      Github地址: https://github.com/avast/android-butterknife-zelezny

      ECTranslation

      Android Studio 翻譯插件,可以將英文翻譯為中文。

      ECTranslation

      使用說明:選中要翻譯的內容,選擇 Edit ——> Translate 或者按下 command + I (我這里設置為 Shift + I )。

      修改快捷鍵: Preferences -> Keymap -> 搜索Translate - > 右鍵 add Keyboard Shortcut . 輸入你想要的快捷鍵即可。

      插件地址: https://plugins.jetbrains.com/idea/plugin/8469-ectranslation

      Github地址: https://github.com/Skykai521/ECTranslation

      問題記錄

      Error:The number of method references in a .dex file cannot exceed 64K.

      這是錯誤是因為應用的方法數已經超過了64K了,在 class 轉換 dex 文件時報錯了。一個 dex 文件的最大方法數是65536,所以這時候要啟用 Multidex。

      1.app 的 build.gradle 添加如下配置

      android {
          defaultConfig {
              // 啟用 multidex 支持.
              multiDexEnabled true
          }
      }

      dependencies { compile 'com.android.support:multidex:1.0.1' }</code></pre>

      2.在 AndroidManifest.xml 下配置 MultiDexApplication

      <?xml version="1.0" encoding="utf-8"?>
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.android.multidex.myapplication">
          <application
              ...
              android:name="android.support.multidex.MultiDexApplication">
              ...
          </application>
      </manifest>

      如果是自定義了 Application 則讓其繼承 MultiDexApplication。

      官方文檔: https://developer.android.com/tools/building/multidex.html

      Error: "*" is not translated in "en" (English) [MissingTranslation]

      這種錯誤一般出現在打包的時候,表示 strings.xml 中缺失本地化的字符串資源。

      這個錯誤有兩個解決方案:

      1. 在 values\strings.xml 或出問題的 strings.xml 中添加如下配置:
        <resources xmlns:tools="http://schemas.android.com/tools" tools:locale="en">
      2. 在 values\strings.xml 或出問題的 strings.xml 中添加如下配置:
        <resources  xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation" >

      缺失的本地化字符串資源會使用默認字符串資源。

      Could not find Library

      日志如下:

      Error:A problem occurred configuring project ':app'.
      > Could not resolve all dependencies for configuration ':app:_debugCompile'.
         > Could not find com.android.support:appcompat-v7:22.2.0.
           Searched in the following locations:
               https://jcenter.bintray.com/com/android/support/appcompat-v7/22.2.0/appcompat-v7-22.2.0.pom
               https://jcenter.bintray.com/com/android/support/appcompat-v7/22.2.0/appcompat-v7-22.2.0.jar
               file:/D:/AndroidDeveloper/adt-bundle-windows-x86-20130917/sdk/extras/google/m2repository/com/android/support/appcompat-v7/22.2.0/appcompat-v7-22.2.0.pom
               file:/D:/AndroidDeveloper/adt-bundle-windows-x86-20130917/sdk/extras/google/m2repository/com/android/support/appcompat-v7/22.2.0/appcompat-v7-22.2.0.jar
           Required by:
               HelloWorld:app:unspecified

      解決辦法:更新你的 Android Support Library 和 Android Support Repository.

      修改 applicationId 后啟動出現ClassNotFoundException

      日志如下:

      E/AndroidRuntime: FATAL EXCEPTION: main
         Process: com.linchaolong.android.app, PID: 10690
         java.lang.RuntimeException: Unable to instantiate application com.android.tools.fd.runtime.BootstrapApplication: java.lang.IllegalStateException: java.lang.ClassNotFoundException: com.linchaolong.android.app.MyApplication
             at android.app.LoadedApk.makeApplication(LoadedApk.java:565)
             at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4545)
             at android.app.ActivityThread.access$1500(ActivityThread.java:154)
             at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1369)
             at android.os.Handler.dispatchMessage(Handler.java:102)
             at android.os.Looper.loop(Looper.java:135)
             at android.app.ActivityThread.main(ActivityThread.java:5275)
             at java.lang.reflect.Method.invoke(Native Method)
             at java.lang.reflect.Method.invoke(Method.java:372)
             at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:909)
             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:704)
          Caused by: java.lang.IllegalStateException: java.lang.ClassNotFoundException: com.linchaolong.demo.App
             at com.android.tools.fd.runtime.BootstrapApplication.createRealApplication(BootstrapApplication.java:220)
             at com.android.tools.fd.runtime.BootstrapApplication.attachBaseContext(BootstrapApplication.java:239)
             at android.app.Application.attach(Application.java:185)
             at android.app.Instrumentation.newApplication(Instrumentation.java:996)
             at android.app.Instrumentation.newApplication(Instrumentation.java:980)
             at android.app.LoadedApk.makeApplication(LoadedApk.java:560)
             at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4545) 
             at android.app.ActivityThread.access$1500(ActivityThread.java:154) 
             at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1369) 
             at android.os.Handler.dispatchMessage(Handler.java:102) 
             at android.os.Looper.loop(Looper.java:135) 
             at android.app.ActivityThread.main(ActivityThread.java:5275) 
             at java.lang.reflect.Method.invoke(Native Method) 
             at java.lang.reflect.Method.invoke(Method.java:372) 
             at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:909) 
             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:704) 
          Caused by: java.lang.ClassNotFoundException: com.linchaolong.android.app.MyApplication
             at java.lang.Class.classForName(Native Method)
             at java.lang.Class.forName(Class.java:306)
             at java.lang.Class.forName(Class.java:270)
             at com.android.tools.fd.runtime.BootstrapApplication.createRealApplication(BootstrapApplication.java:209)
             at com.android.tools.fd.runtime.BootstrapApplication.attachBaseContext(BootstrapApplication.java:239) 
             at android.app.Application.attach(Application.java:185) 
             at android.app.Instrumentation.newApplication(Instrumentation.java:996) 
             at android.app.Instrumentation.newApplication(Instrumentation.java:980) 
             at android.app.LoadedApk.makeApplication(LoadedApk.java:560) 
             at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4545) 
             at android.app.ActivityThread.access$1500(ActivityThread.java:154) 
             at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1369) 
             at android.os.Handler.dispatchMessage(Handler.java:102) 
             at android.os.Looper.loop(Looper.java:135) 
             at android.app.ActivityThread.main(ActivityThread.java:5275) 
             at java.lang.reflect.Method.invoke(Native Method) 
             at java.lang.reflect.Method.invoke(Method.java:372) 
             at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:909) 
             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:704) 
          Caused by: java.lang.ClassNotFoundException: Didn't find class "com.linchaolong.android.app.MyApplication" on path: DexPathList[[zip file

      原因是 Android Studio 的 Instant Run 嘗試對你的代碼執行熱交換,導致 Application 類被移除所以出現 ClassNotFoundException。

      停用 Instant Run, File --> Settings--> Build,Execution,Deployment -->Instant Run ---> 取消勾選 "Enable instant run"

      相關文章

       

      來自:https://juejin.im/entry/58bfd80ea22b9d00588c3444

       

 本文由用戶 DomCedeno 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!