Android Studio,使用技巧,问题记录和一些好用的插件

使用技巧

1. 根据不同 buildType 使用不同包名和资源

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

productFlavors {
        production {
            applicationId = "com.myapp.app"
            resValue "string", "authority", "com.facebook.app.FacebookContentProvider5435651423234"
        }
        development {
            applicationId = "com.myapp.development"
            resValue "string", "authority", "com.facebook.app.FacebookContentProvider2134564533421"
        }
        qa {
            applicationId = "com.myapp.qa"
            resValue "string", "authority", "com.facebook.app.FacebookContentProvider29831237981287319"
        }
}

通过 resValue 方法设置的资源会在 R 文件生成对应的 id。

在 AndroidManifest.xml 中使用 authority 字符串

<provider
    android:name="com.facebook.FacebookContentProvider"
    android:authorities="@string/authority"
    android:exported="true" />

2. 替换 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",
        ]
    }
}

说明:manifestPlaceholders 是一个 map。

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

3. 自定义 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 常量。

4. 统一管理不同 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'
  }
}
  1. 然后在 project-level 下的 build.gradle 添加如下配置应用 config.gradle:
apply from: rootProject.file('config.gradle')
  1. 在各 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}"]
    }
}
  • 在 dependencies 块下引用 ext 中的字段
dependencies {
    compile "com.android.support:appcompat-v7:$support"
    // Debug
    compile "com.facebook.stetho:stetho:$stetho"
    compile "com.facebook.stetho:stetho-okhttp3:$stetho"
    debugCompile "com.facebook.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

5. 建立各 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')

6. 自定义 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)
        }
      }
    }
  }
}

7. 手动 build 工程

我们应该都或多或少遇到过这种情况,当我们第一次打开一个项目时,该项目会先下载相关的依赖项,如果很多的话,将会等很久,而且又不能做其他操作,这样太浪费时间了。

Image

下面说说如何在命令行中手动 build 工程:

每个 android studio 工程下应该都会有 gradlew.bat(Windows) 和 gradlew(Mac) 两个脚本文件,我们可以打开命令行,cd 到工程目录下,通过执行 gradlew.bat build 命令,手动去构建工程。

Image

通过在命令行构建工程可以不影响当前工作,而且构建完成后再使用 android studio 打开该工程将会比较快。

8. 手动下载和替换本地 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 搜索一下文件名。

9. 构建一个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

翻译自这里

10. 引用 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')
  }
}

多个目录使用 “,” 分隔

11. 快捷键

由于 Android Studio 是基于 IDEA 的,所以很多快捷键是通用的,这里可以参考这篇文章

12. 全局替换

Edit —> Find —> Replace in Path

Replace in Path

13. 动态调试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... 选择插件安装包,安装完成后重启生效。

1. GsonFormat

GsonFormat 是一个可以快速将 JSON 字符串转换为 Entity 类的插件。

GsonFormat
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

2. Android ButterKnife Zelezny

Android ButterKnife Zelezny 是 Android 下的注解框架 ButterKnife 的辅助插件,用于一键生成 Butterknife 视图注入代码。

Android ButterKnife Zelezny
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

3. ECTranslation

Android Studio 翻译插件,可以将英文翻译为中文。

ECTranslation
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

问题记录

1. 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'
}

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

2. 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">
  1. values\strings.xml 或出问题的 strings.xml 中添加如下配置:
<resources  xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation" >

缺失的本地化字符串资源会使用默认字符串资源。

点击查看 tools 属性文档

3. 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.

4. 修改 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"

点击这里查看该解释的原文

相关文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容