Android Tips

一、Know Your Tools

Android Studio

  • Code faster by using keyboard shortcuts
    Some useful keyboard shortcuts:Android Studio 快捷键集
    Complete Keymap Guide : MacOSX | Linux/Win

  • Use plugins to become more efficient

    1. KeyPromoter

      The plugin basically will annoy the hell out of you by showing you a big screen overlay with the key combination you should have used, if you used your mouse to execute some command to a level when you basically would start using the key combination just to avoid KeyPromoter annoying you all the time. It also has some useful features, like it will prompt you to create a key binding for a command whenever an action does not have a key binding and you have used it 3 times using your cursor.

    2. String Manipulation

      Provides actions for text manipulation such as Toggle case, encode/decode, sorting,

    3. Lines Sorter

      Add Sort Lines action in Edit menu to sort selected lines or whole file if the selection is empty.

    4. Findbugs

      Provides static byte code analysis to look for bugs in Java code from within Android Studio

    5. Sonar Lint

      The plugin that provides on-the-fly feedback to developers on new bugs and quality issues injected into Java, JavaScript and PHP code.

    6. Checkstyles

      The plugin provides both real-time and on-demand scanning of Java files from within Android Studio.

    7. ADB Idea

      The plugin that adds ADB commands to Android Studio and IntelliJ such as ADB Uninstall App, ADB Kill App, ADB Restart App, etc

    8. Exynap

      The plugin which helps you find and implement the code you require in an instant.

    9. Dagger IntelliJ Plugin

      The Dagger IntelliJ plugin creates visual connections between a @Inject object and the @Provides method that creates it.

    10. JVM Debugger Memory View

      This plugin extends the built-in JVM debugger with capabilities to explore objects in the JVM heap during a debug session.

  • Use Live Templates in Android Studio

    • newInstance - Generates the static newInstance function inside a Fragment
    • Toast - Generates Toast.makeText(context, "", Toast.LENGTH_SHORT).show();
    • fbc - findViewById with cast
    • const - Define a android style int constant
    • logd - Generates Log.d(TAG, "");
    • logm - Log current method name and its arguments.
    • logr - Log result of the current method
    • logt - static logtaf with current classname
    • psf - public static final
    • sout - Prints a string to System.out
    • soutm - Prints current class and method names to System.out
    • soutp - Prints method parameter names and values to System.out
    • visible - Set view visibility to VISIBLE
    • gone - Set view visibility to GONE
    • noInstance - private empty constructor to prohibit instance creation

Comprehensive list of all Live Templates in Android Studio

  • Postfix code completion in Android Studio

    Android Studio/IntelliJ havea special kind of code completion which allows you to write code specific to a field

    • <expr>.null will auto complete to if(<expr> == null)
    • <expr>.nootnull will auto complete to if(<expr> != null)
    • <expr>.var will auto complete to T name = <expr>
    • <expr>.field will auto complete to create a global field variable field = <expr>
    • <ArrayExpr>.for will auto complete to for(T item : <Arrayexpr>)
    • <ArrayExpr>.fori will auto complete to for(int i = 0; i < <Arrayexpr>.length; i++)
    • <ArrayExpr>.forr will auto complete to for(int i = <Arrayexpr>.length - 1; i > 0 ; i--)

    Complete list of available postfix code completion can be found at Settings → Editor → Postfix Templates

  • Use the Darcula Theme in Android Studio

    Ok, I know its more like a preference, but trust me using that keeps your eyes less strained as they would be if you used the Default Light theme.

  • Don't use a small font

    Preferably use a font in Android Studio that's easy to read and is at a font size which does not forces you to strain your eyes. I use Menlo font.

  • Use a code style

    You should use a standard codestyle, so possible contenders can be

  • Use the Embedded Terminal inside Android Studio

  • Use the Memory/Network/CPU Monitor inside Android Studio to profile your code/app

  • Configure Android Studio

Emulator

Apart from using physical devices, one should use emulators as they are as of now easy to manage and equivalently powerful.

Vysor

This one needs special mention due to how useful it is. It basically is a window to your device i.e it streams and allows you to interact with your physical device on your laptop. Very useful when you are demoing your app during a presentation. You can interact with your physical device and it will be shown right in your laptop screen. It has a paid/free version, paid version is totally worth buying.

DeskDock

Yes, vysor was great, but if you want to share your keyboard and mouse directly to your Android device, then this app is for you. It enables you to control your Android device as if it was part of your desktop computer. The FREE version includes the use of computer mouse, while the PRO version includes features such as use of keyboard. This is useful where you can test your app without your hands ever leaving your keyboard.

二、Make better choices while coding

  • Reference local aar files as below [Stackoverflow Ref]

      dependencies {
         compile(name:'nameOfYourAARFileWithoutExtension', ext:'aar')
       }
      repositories{
            flatDir{
                    dirs 'libs'
             }
       }
    
    
  • Use Pidcat for a better log reading experience

  • Use some Version Control System(VCS) like Git

  • Use ClassyShark

    It is a standalone tool for Android Devs used to browse any Android executable and show important info such as class interfaces and members, dex counts and dependencies

  • Use Stetho

    Debug your android apps using Chrome Dev Tools. Includes tools like Network Monitor, Shared Preference explorer etc.

  • Use Battery Historian

    A tool to analyze battery consumers using Android "bugreport" files.

  • Always use a constant version value like "1.2.0"

    Avoid using + when specifying the version of dependencies.

    • Keeps one secured from unexpected API changes in the dependency.
    • Avoids doing an extra network call for the checking latest version of each dependency on every build.
  • Use Handler instead of a TimerTask

  • Do not use your own personal email for Google Play Developer Account

  • Use Vectors instead of PNG

    If you do have to use png, compress them. Take a look at TinyPNG.

  • Use proguard

    android {
      ...
      buildTypes {
          release {
              minifyEnabled true
              proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
          }
      }
    }
    
  • Use shrinkResources

    android {
      ...
      buildTypes {
          release {
              shrinkResources true
              minifyEnabled true
              ...
          }
      }
    }
    
  • Simulating Android killing your app in the background, run in terminal
    adb shell am kill

  • Follow the below rule to have faster gradle builds

    Gradle memory >= Dex memory + 1Gb
    
  • Split your apk using gradle when using Native code, do not bundle all of em together and ship!.. coz that will make you evil

    defaultConfig {
        ...
    
        ndk {
          abiFilters "armeabi", "armeabi-v7a", "mips", "x86"
        }
      }
    
    //Split into platform dependent APK
    splits {
      abi {
        enable true
        reset()
        include 'armeabi', 'armeabi-v7a', 'mips', 'x86' //select ABIs to build APKs for
        universalApk false //generate an additional APK that contains all the ABIs
      }
    }
    
    // map for the version code
    project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'mips': 5, 'x86': 8]
    
    // Rename with proper versioning
    android.applicationVariants.all { variant ->
      // assign different version code for each output
      variant.outputs.each { output ->
        output.versionCodeOverride =
            project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) *
                1000000 +
                android.defaultConfig.versionCode
      }
    }
    
  • Learn about some architecture such as MVP or Clean

  • Try to understand and follow TDD (Test Driven Development)

  • To force re-download of dependencies

    ./gradlew --refresh-dependencies
    
  • To exclude a certain task from being run by gradle

    Suppose you want to exclude the task javaDoc then use -x option followed by the task name, i.e javaDoc in this case.

    ./gradlew clean build -x javaDoc
    
  • To have the each subproject script name match that of the project name

    Then add this line in settings.gradle

    rootProject.children.each{
      it.buildFileName = it.name + '.gradle'
    }
    

    Checkout more gradle tips here

  • Follow the DRY principle
    DRY = Do not Repeat Yourself

  • Package by Feature, not layers

  • Learn about Dependency Resolution

    With the speed android dependencies update, sooner or later you are going to encounter some sort of dependency conflict. The solution is making use of Dependency Resolution. Official Reference

  • Use different package name for non-release builds

      android {
          buildTypes {
              debug {
                  applicationIdSuffix '.debug'
                  versionNameSuffix '-DEBUG'
              }
    
              release {
                  // ...
              }
          }
      }
    
  • Find and STOP leaking memory in your android app

  • If you’re creating a gradient in xml with a part being completely transparent, be really careful when using @android:color/transparent

  • Follow a standard naming convention for your resources

  • Make use of custom gradle tasks in your build.gradle files

    Android uses Gradle as its build system, which actually allows one to make a lot of things easy by creating tasks to automate things.
    This reddit post enlists a lot of such useful gradle scripts

  • Use a proper .gitignore in your Android Projects, Check it here

  • Use LeakCanary to detect memory leaks in your app - Its a memory leak detection library for Android and Java.

  • Speed up your gradle builds in Android Studio 2.3+

    • Switch to gradle 3.4.1

      Run this inside your project folder to update your gradle wrapper

      ./gradlew wrapper --gradle-version 3.4.1 --distribution-type all
      
    • Set the below property in your global gradle.properties file

      android.enableBuildCache=true
      
  • Stop a running gradle build process

    ./gradlew -stop
    
  • Enable gradle to automatically download missing platforms in android sdk

    Set the below property in your global gradle.properties file

    android.builder.sdkDownload=true
    

    This is an experimental option and it only downloads build tools and platforms, but doesn't actually update Google or Support repository [Bug Ref]

  • Donot include both jcenter() & mavenCentral() in your build.gradle file

    JCenter is a superset of MavenCentral. [Ref tweet]

  • Clear your gradle cache if you think that bundled support and google play services lib in android sdk are inconsistent

    • Goto ~/.gradle/caches/ and delete everything inside the cache folder.
    • Open SDK Manager and resync all support libs and google play services
    • Next re-sync your project
    • Everything should become consistent and functional.
  • Setup handy adb aliases for your terminal [Ref Link]

    Append the below Aliases to your ~/.bashrc or ~/.zshrc file, save and restart the terminal. Once saved, use them as show in Usage column

    Alias Usage
    alias screenshot="adb exec-out screencap -p > screen-$(date -j "+%s").png" screenshot
    `alias startintent="adb devices tail -n +2 cut -sf 1 xargs -I X adb -s X shell am start $1"` startintent https://twitter.com/nisrulz
    `alias apkinstall="adb devices tail -n +2 cut -sf 1 xargs -I X adb -s X install -r $1"` apkinstall ~/Desktop/DemoApp.apk
    `alias rmapp="adb devices tail -n +2 cut -sf 1 xargs -I X adb -s X uninstall $1"` rmapp com.example.demoapp
    `alias clearapp="adb devices tail -n +2 cut -sf 1 xargs -I X adb -s X shell pm clear $1"` clearapp com.example.demoapp
  • Setup Android Studio to fail build if code contains //STOPSHIP [Ref Link]

    To enable the //STOPSHIP lint check, in your build.gradle

    android {
    ...
        lintOptions {
            abortOnError true
            fatal 'StopShip'
        }
    }
    

    If you have a //STOPSHIP comment in your code, this will cause an error to be thrown when a release apk is generated.

    You can turn on //STOPSHIP highlighting in Android Studio (isn't enabled by default) in

    Preferences > Editor > Code Style > Inspections.

    Search for STOPSHIP to find the correct setting.

  • Use adb install -g to grant all permissions listed in the manifest [More Info]

  • Use alfi to find the gradle dependency statement for a library

    Its basically the command line version of Gradle, Please which is a web hosted.

    • Run

      alfi name_of_library
      
    • Copy the desired library

    • Paste in your build.gradle

  • Use dryrun to test a library directly

    • Just Run

      dryrun REMOTE_GIT_URL
      
  • Output unit tests directly to the console [Ref Link]

    A small neat trick to see Android unit tests logging results as they happen in the terminal.

    android {
        ...
        testOptions.unitTests.all {
          testLogging {
            events 'passed', 'skipped', 'failed', 'standardOut', 'standardError'
            outputs.upToDateWhen { false }
            showStandardStreams = true
          }
        }
      }
    
  • Make your builds faster by building offline [Ref Link]

    The --offline flag tells gradle to always use dependency modules from the cache, regardless if they are due to be checked again. When running offline, gradle will never attempt to access the network to perform dependency resolution. If required modules are not present in the dependency cache, build execution will fail.

    • Assembling develop debug at full speed:

      ./gradlew assembleDevelopDebug --offline
      
    • Running your unit tests at full speed:

      ./gradlew test --offline
      
  • Use an abtracted Logger class

  • If you want to automatically initialize your library, use a Content Provider [Read how Firebase does it - Ref Link]

  • Reduce installed app size with "android:extractNativeLibs:false" in <application> [Ref Link]

    This will essentially prevent the system from creating a second copy of the .so files and fix the System.loadLibrary call so it’s able to find and open native libs straight from the APK, no code changes on your part required.

  • Selectivily execute a specific method in Android Studio [Ref Link]

  • Did you get one of these Google Play Developer Policy Violation Emails? Worry not, generate a Privacy Policy for your android app [Ref ink]

  • Define a variable at build time
    In your build.gradle

    android{
      defaultConfig {
        ...
        buildConfigField "String", "SERVER_ENDPOINT", '"http://www.myendpoint.com"'
        buildConfigField "int", "FOO", "52"
        buildConfigField "boolean", "LOG", "false"
        ...
      }
    }
    

    and then use it in code as BuildConfig.SERVER_ENDPOINT, BuildConfig.FOO,BuildConfig.LOG

  • Calculate the version code and version name in your build.gradle manually, based of version values*
    In your app's build.gradle

    versionMajor = 0
    versionMinor = 0
    versionPatch = 0
    versionBuild = 1
    
    
    verCode = versionMajor * 1000000 + versionMinor * 10000 + versionPatch * 100 + versionBuild
    verName = "${versionMajor}.${versionMinor}.${versionPatch}"
    
    // Use
    android{
      defaultConfig {
        ...
        versionCode verCode
        versionName verName
        ...
      }
    }
    
  • Calculate the version code and version name in your build.gradle automatically, based on git information*

    Note: These functions go specifically inside the app's build.gradle and cannot be used with ext.

    In your app's build.gradle

    // Version code is calculated as the number of commits from last commit on master
    def getVersionCode = { ->
      try {
        def code = new ByteArrayOutputStream()
        exec {
          commandLine 'git', 'rev-list', 'HEAD', '--count'
          standardOutput = code
        }
        return Integer.parseInt(code.toString().trim())
      } catch (exception) {
        return "1";
      }
    }
    
    // Version name is Last Tag Name + No. of commits form last Tag +  short git sha
    def getVersionName = { ->
      try {
        def stdout = new ByteArrayOutputStream()
        exec {
          commandLine 'git', 'describe', '--tags', '--dirty'
          standardOutput = stdout
        }
        return stdout.toString().trim()
      } catch (exception) {
        return "0.0.0.1";
      }
    }
    
    // Use
    android{
      defaultConfig {
        ...
        versionCode getVersionCode()
        versionName getVersionName()
        ...
      }
    }
    
  • Get the date of build as a variable*
    In your app's build.gradle

    // Get the date of build
    def getDateOfBuild = { -> // ISO 8601 time format
      return new Date().format("yyyy-MM-dd'T'HH:mm'Z'").toString().trim()
    }
    
    // then use it as a variable in BuildConfig
    android{
      defaultConfig {
        ...
        buildConfigField "String", "DATE_OF_BUILD", "\"${getDateOfBuild()}\""
      }
    }
    
  • Get the Git SHA as a variable*
    In your app's build.gradle

    // Get the last Git Short Hash
    def getGitHash = { ->
      def stdout = new ByteArrayOutputStream()
      exec {
        commandLine 'git', 'rev-parse', '--short', 'HEAD'
        standardOutput = stdout
      }
      return stdout.toString().trim()
    }
    
    // then use it as a variable in BuildConfig
    android{
      defaultConfig {
        ...
        buildConfigField "String", "GIT_SHA", "\"${getGitHash()}\""
      }
    }
    
  • Activity LifeCycle [Ref Link]

  • Tip about onSaveInstanceState()
    onSaveInstanceState() is called only when the OS decides to kill the Activity instance. It will not be called when Activity is explicitly killed i.e User pressed back button or finish() is called from code.

  • If you are into building Android Libraries, then read here for more tips

  • Read about whats in an APK here

  • Learn about various techniques involved when using ADB

  • Input some text in an editfield in a running emulator from your keyboard

    adb shell input text "keyboard text"
    

Tips regarding UI/UX

  • Motion

    • Material Design uses real-world metaphors as its foundation. Objects in the real world don't move linearly, they move in curved paths and accelerate and decelerate according to the motion's properties.
    • As such, motion should also use such properties and animate objects so that the motion feels natural rather than forced
    • For example, a car leaving the screen in a movie starts off slowly, then accelerates till it's out of the frame. Similarly, views should be interpolated using classes like AccelerateInterpolator, FastOutSlowInInterpolator, etc. [More Info]
  • Typography

    • While custom typefaces can be used for branding, it is essential to stick to Roboto and Noto if possible, especially for body text, due to their clarity and optimistic nature.
    • Roboto covers Latin, Greek and Cyrillic extended scripts, with Noto filling in for other language scripts [More Info]
    • Weight balancing is an important aspect of typography, the fundamental concept of which is that the larger a typeface is, the less its weight should be so that it doesn't appear too thick and balances its weight with smaller typefaces of higher weights
    • Typography should align to a 4dp baseline grid, and maintain a minimum contrast ratio of 4.5:1 based on luminance values, with a recommended ratio being 7:1.
    • The ideal reading length for large blocks of text is 40 to 60 characters per line. Anything less is too narrow and anything more is too wide.
  • Icons

    • Icons should be designed at 48dp, with 1dp edges, which equates to
      • 48px by 48px at mdpi
      • 72px by 72px at hdpi
      • 96px by 96px at xhdpi
      • 144px by 144px at xxhdpi
      • 192px by 192px at xxxhdpi
    • An additional icon of 512px by 512px should be designed for use on Google Play
    • Material icons, in addition to the base icon, should contain the following important elements
      • 1dp tinted edge at the top
      • 1dp shaded edge at the bottom
      • Contact shadow - a soft shadow around all edges of raised elements
      • Finish - a soft tint to provide surface lighting, fading from upper life to lower right [More Info]
  • Ripples

    • When implementing Ripple Effect use ?attr/selectableItemBackground instead of ?android:attr (Ref)

    • When implementing Ripples contained within the view like Button, use (Ref)

      android:background="?attr/selectableItemBackground"
      
    • When implementing Ripples that extend beyond the view's bounds like ImageView: (Ref)

      ?attr/selectableItemBackgroundBorderless
      
  • Other Points to Note
    • Views should be aligned to Material Design's 8dp baseline grid and the keylines when possible. This gives the UI a sense of structure and hierarchy. [More Info]
    • If you plan on keeping a reference to any ViewGroup (LinearLayout, FrameLayout, RelativeLayout, etc.), and you don’t want to use any methods specific to this particular type of Layout, keep it as a ViewGroup object. [More Info]
    • While picking an accent color (if the brand already has one), pick a color complementary to the primary color so that the contrast is high enough

Tips if you use Kotlin

  • Checkout From Java to Kotlin

    Cheatsheet when you come from Java to Kotlin. Very nice resource to compare the two languages.

Other Resources

Extra : Android Libraries built by me

  • EasyDeviceInfo - Enabling device information to be at android developers hand like a piece of cake!
  • Sensey - Android library to make detecting gestures easy
  • PackageHunter - Android library to hunt down package information
  • Zentone - Easily generate audio tone in android
  • RecyclerViewHelper - RecyclerViewHelper provides the most common functions around recycler view like Swipe to dismiss, Drag and Drop, Divider in the ui, events for when item selected and when not selected, on-click listener for items.
  • StackedHorizontalProgressbar - Android Library to implement stacked horizontal progressbar
  • QREader - A library that uses google's mobile vision api and simplifies the QR code reading process
  • ScreenShott - Simple library to take a screenshot of the device screen, programmatically!
  • EvTrack - Android library to make event and exception tracking easy
  • OptimusHTTP - Android library that simplifies networking in android via an async http client
  • ShoutOut - Android library for logging information in android

此篇文章来自GitHub,其中有遗漏和错误之处

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

推荐阅读更多精彩内容