安卓开发需要了解的二三事(自译)

来源:互联网 发布:dj音乐制作软件 编辑:程序博客网 时间:2024/05/09 04:15

translate from:

https://github.com/futurice/android-best-practices#networklibs


Android SDK

不要将你的SDK置于和IDE同个目录下面(在你安装IDE的时候有时候会按这样的路径自带安装),因为在你升级IDE的时候,很有可能会丢失SDK,从而导致又一次漫长的重新下载。

同样的也避免将SDK置于需要申请超级用户权限下面的目录,因为这样可能会导致申请用户权限的操作(特别当你的IDE是在无超级权限下运行的时候)


Build system

默认应该选择Gradle,因为(这里用原味比较好…):

  • Build different flavours or variants of your app
  • Make simple script-like tasks
  • Manage and download dependencies
  • Customize keystores
  • And more

Ant在2015年已经被弃用了。

应用编译的过程应该是基于Gradle文件,而非是IDE的特定设置。

This allows for consistent builds between tools and better support for continuous integration systems.


Project structure

如果不是因为什么不可抗力的因素,应该遵循Gradle 默认的项目结构来搭建你的项目。default structure


Gradle configuration

General structure

遵循Google的指导文档:Google’s guide on Gradle for Android

Small tasks

可以使用Gradle来替代比如shell, Python, Perl, etc来完成一些事项。查看文档来获取更多信息:Gradle’s documentation

Passwords

在你应用的build.gradle文件中,你需要为release版本定义signingConfigs参数,下面是一种你应该避免的方式:

如此将导致其信息出现在你的版本控制中

signingConfigs {    release {        storeFile file("myapp.keystore")        storePassword "password123"        keyAlias "thekey"        keyPassword "password789"    }}

应该在gradle.properties文件中设置:

KEYSTORE_PASSWORD=password123KEY_PASSWORD=password789

然后在build.gradle中如此:

signingConfigs {    release {        try {            storeFile file("myapp.keystore")            storePassword KEYSTORE_PASSWORD            keyAlias "thekey"            keyPassword KEY_PASSWORD        }        catch (ex) {            throw new InvalidUserDataException("You should define KEYSTORE_PASSWORD and KEY_PASSWORD in gradle.properties.")        }    }}

Prefer Maven dependency resolution instead of importing jar files

如果你使用jar的方式,那将导致其固定在特定的版本,因为下载jar和维护它的更新是相当笨重而累赘的事情。Maven就是在Android Gradle中解决这个问题的一个相当不错的方式:

dependencies {    compile 'com.squareup.okhttp:okhttp:2.2.0'    compile 'com.squareup.okhttp:okhttp-urlconnection:2.2.0'}

Avoid Maven dynamic dependency resolution

避免使用Maven的动态版本依赖,比如2.1.+,这将导致不同且不稳定的构建或是在不同构建中存在细微、难以追踪的不同行为。使用静态的特定版本比如2.1.1能够构建一个更稳定、可预期、可重用的开发环境。

Use different package name for non-release builds

为了在同一设备上同时安装debugrelease版本,需要设置applicationIdSuffix参数(如果你自定义这两者之外的版本,也推荐如此设置)。当你的应用在商店发布以后,这一工作将会在应用的生命周期中体现出相当的价值。

android {    buildTypes {        debug {            applicationIdSuffix '.debug'            versionNameSuffix '-DEBUG'        }        release {            // ...        }    }}

使用不同的应用图标来区分不同的版本——比如使用不同的颜色并打上“debug”的标签。Gradle让这项工作更加简便:

在默认目录结构中,只需简单的将debug版本的图标置于app/src/debug/res,并且将release版本的图标置于app/src/release/res中即可。

同样就像上面所展示的设置不同的versionName一样,同样也可以为不同版本设置不同的应用名称。(即在两个路径下的strings.xml文件中设置不同的应用名)

change app name


IDEs and text editors

用什么IDE因人而异, 但是也需要遵循适应项目结构这一原则.

推荐使用 Android Studio, 因为它由谷歌进行维护和开发, 更新频繁, 对Gradle的适应性好, 包含了一系列的模拟和分析工具, 是普遍意义上为安卓开发者量身定做的IDE.

当然, 你也可以选择文本编辑器, 诸如Vim/SublimeText/Emacs等等, 同时你也需要通过命令行来使用Gradle和adb.

使用Eclipse ADT已经不再是一个好的选择. Google ended ADT support at the end of 2015 谷歌已经停止维护并主动推荐开发者将项目迁移到AS中去: migrate to Android Studio

无论你的选择为何, 注意避免添加一些特定的编辑设置文件, 类似AS里面的.iml文件, 版本控制工具往往都具备这些根据你本地设备而特定的设置文件. 盲目添加这些文件往往会使你无法与同事进行协作.

最后, 请善待其他的开发者, 不要强迫别人改变他们所使用的工具, 如果那些工具对他们来说是最有生产力的话(PS: eclipse完全没有生产力, 只有习惯问题而已吧)


Libraries

Jackson是一个用于Object和JSON之间互相转化的类库, Gson同样也是可选的解决方案之一. 然而发现Jackson在支持多种可替代的JSON转化方式中具有相当高的性能, 例如streaming, in-memory tree model, traditional JSON-POJO data binding. 不过也因此, Jackson是一个比Gson更大的类库. 所以最后的选择还是在于你自己. 同样可替代的方案还有Json-smart 和 Boon JSON


网络, 缓存, 图片. 与后台服务器进行交互的解决方案也有多种, 结合你的客户端进行考虑选用. 推荐是Volley 或者 Retrofit.

Volley同时还提供了图片的读取与缓存. 如果你选择的是Retrofit, 可以考虑采用Picasso来进行图片的读取与缓存, OkHttp来进行有效的HTTP请求. 同时, Retrofit, Picasso, OkHttp这三者同属于一家公司开发, 所以这三者之间的协作体验是优异的. OkHttp也可以与Volley一起用于网络连接(实现方式).

Glide 是加载图片的另一种选择, 虽然有更多的方法数, 但是表现优于Picasso, 支持GIF和圆形图片.


RxJava是一个用于响应式编程(Reactive Programming)的类库, 换句话说, 也即处理异步事件. 它是如此强力而又具有前景, 同时也因为如此不同容易造成困扰.

建议在采用这个库进行应用的开发前, 需要做些准备. 已经有一些项目采用RxJava进行开发, 如果有需要的话, 你可以看一看这几位的博客:

Timo Tuominen, Olli Salonen, Andre Medeiros, Mark Voit, Antti Lammi, Vera Izrailit, Juha Ristolainen. We have written some blog posts on it: [1], [2], [3], [4].

如果你之前并没有使用Rx的开发经验, 可以从API上的应用开始你的实践. 同样, 也可以在一些简单的UI事件上进行实践, 例如点击事件或者搜索时的输入改变响应. 如果你对你的Rx技能充满信心并想要应用到整个项目中, 那么请写文档(Javadoc), 记录下每一个棘手的地方(tricky parts). 请牢记这么做是因为在你之后维护这个项目的人可能对于Rx并不熟悉, 如果没有文档的帮助, 将会带给他一段非常…的时光(你懂的). 尽你最大努力帮助后来的人去理解你的代码和Rx.


Retrolambda 是一个为了在Android和其他pre-JDK8平台使用lambda表达式语法而产生的Java类库. 它致力于使代码更简洁, 并提高可读性, 特别是在你使用类似RxJava的函数式编程风格时.

AS提供了对于Jave8的lambda特性的代码支持, 如果你是一个新手, 可以遵循下面的步骤来开始:

  • Any interface with just one method is “lambda friendly” and can be folded into the more tight syntax
  • If in doubt about parameters and such, write a normal anon inner class and then let Android Studio fold it into a lambda for you.

注意dex的方法数限制, 并避免使用太多的类库. Android应用, 当打包为dex文件的时候, 对于引用方法数有硬性的65536限制[1] [2] [3]. 如果你超过了这个限制, 将会在编译过程中看到一个fatal error. 基于此, 尽量采用少的类库, 同时使用dex-method-counts 工具来帮助检测哪些类库可以在方法数限制内被使用. 尤其避免使用Guava库, 这个库中包含了超过13K个方法.


Activities and Fragments

在Android应用的构建过程中, 对于怎样才是组织Fragments和Activities的最好方式, 依然没有一个一致的意见. Square公司甚至出了一个类库, a library for building architectures mostly with Views, 绕过避开了对于Fragments的需求. 但这仍然不被认为是一个考虑周全的解决方式.

因为在Android的API历史进程中, 你可以将Fragment简单的认为是UI部分; 而Activity是控制器, 特别是它的生命周期和状态维护是如此重要. 然而, 你也可能见识过如下的各式变种用法: activities同时扮演了UI角色(delivering transitions between screens), fragments仅仅用于扮演控制器角色(fragments might be used solely as controllers).

We suggest you sail carefully, making informed decisions since there are drawbacks for choosing a fragments-only architecture, or activities-only, or views-only.

下面是一些你可能需要认真对待的建议, 但它们也只是沧海一粟而已:

  • 避免广泛使用nested fragments, 因为这会引起 matryoshka bugs. 仅仅在必要的时候使用nested fragments(例如在Fragment内需要一个水平滑动的ViewPager来展现多个页面), 或者这是一个被大家认可接受的决定.
  • 避免在Activities中放置太多代码. 无论何时只要可能, 就尽量保持它们的轻量级, 存在于应用程序中, 主要用于生命周期和其他重要的Android界面API. 比起单纯的Activity, 采用单fragment的Activity是一个更好的选择. 将UI代码置于fragment当中. 这样做的好处是当你需要将这个页面转入一个多标签页, 或者是多fragments的平板电脑界面时, 这些代码是可重用的. 避免使用一个单独的不包含fragment的Activity, 除非这是一个被大家认可接受的决定.
  • 不要滥用那些和进程间通信相关的Android-level APIs(国内我看难). 这可能会对Android OS和其他应用造成影响. 例如, 如果应用使用了Intents进行了包之间的内部通信, 在OS启动之后马上打开应用, 可能会对用户体验造成多秒的滞后.


Java packages architecture

Android应用的Java架构大体来说就是MVC架构(Model-View-Controller). 在Android中, Activity和Fragment实际上就是控制器类(Fragment and Activity are actually controller classes). 另一方面, 它们显而易见又是与用户交互的界面, 因此它们也是视图(view).

基于上述原因, 很难为Fragments(或Activities)作明确的定义, 它们到底是C还是V. 让它们都位于fragments目录内是个好选择. 基于上一节的内容让Activities位于目录顶层. 如果你有多个Activity, 那么可以创建一个activities目录来收纳它们.

除此之外, 你还需要一个models目录来存放那些响应API返回的JSON数据的POJOs实体类; 一个views目录来存放那些你的自定义视图, 通知, 动作栏视图, 控件视图, 等等. Adapters处于data和view之间的灰色地带. 然而, 你仍然可以选择将其放入views目录中, 因为一般adapter都会有个getView()方法来导入视图.

有一些控制器横贯整个应用, 更贴近于Android系统. 它们可以置于managers目录内. 数据处理类, 类似DateUtils, 应该置于utils目录内. 和后端进行网络交互的那些类应该置于network目录内.

综上所述, 项目内应该具有如下的目录结构:

com.futurice.project├─ network├─ models├─ managers├─ utils├─ fragments└─ views   ├─ adapters   ├─ actionbar   ├─ widgets   └─ notifications


Resources

命名. 遵循前缀的命名惯例, 如type_foo_bar.xml. 例子: fragment_contact_details.xml, view_primary_button.xml, activity_main.xml.

xml书写规范. 如果你对此并没有明确的思路, 参考如下:

  • 一个属性占一行, 前面需要四格缩进
  • android:id是第一项属性(如果有的话)
  • android:layout_****属性置于上方
  • style属性置于底部
  • 关闭标签/>单独占据一行, 便于以后添加新的属性
  • 对于android:text属性考虑使用string.xml内引用而非字符串硬编码
<?xml version="1.0" encoding="utf-8"?><LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    >    <TextView        android:id="@+id/name"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_alignParentRight="true"        android:text="@string/name"        style="@style/FancyText"        />    <include layout="@layout/reusable_part" /></LinearLayout>

根据经验, android:layout_****属性应该定义在XML中, 而另外的android:****属性应该定义在style.xml中. 这项经验也有例外的时候, 但在大多数情况下都是适用的. 关键在于仅仅让布局 (positioning, margin, sizing)与内容属性定义在布局文件中, 而将其余的外观属性(colors, padding, font)定义到样式文件中.

例外的情况如下:

  • android:id这个明显应该定义在布局文件中
  • android:orientation这项为LinearLayout设置的属性定义在布局文件中可能更具有意义
  • android:text属性定义在布局文件中因为它是内容
  • 有些时候设置通用的android:layout_widthandroid:layout_height也是个好主意, 但是默认来说它们应该设置在布局文件中.


使用style.xml. 基本每个应用都会用到style.xml, 因为重复利用某个view是家常便饭的事情. 最起码你可能也会需要对于文本框有一个style, 例如:

<style name="ContentText">    <item name="android:textSize">@dimen/font_normal</item>    <item name="android:textColor">@color/basic_black</item></style>

应用于TextView:

<TextView    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="@string/price"    style="@style/ContentText"    />

你可能也会需要为按钮做这样的设置, 但不要仅止于此. 在将重复属性通过style来管理这条路上走的更远.

将style文件从大化小. 不必仅仅只含有一个单独的style.xml文件. AndroidSDK 支持在这个文件之外的style, 这和文件名无关, 关键在于文件内容中的<style>标签. 因此你可以有如下的文件styles.xml, styles_home.xml, styles_item_details.xml, styles_forms.xml. 不像资源目录名在系统编译过程中具有其意义, 在res/values内的文件名字是可以很随意的~


color.xml是一个调色板. 在你的这个文件中, 不应存在除了将一个RGBA值对应给一个颜色名这样的键值对之外的数据内容. 切记不要在这里定义诸如多种button的颜色这样的属性, 如下:

<resources>    <color name="button_foreground">#FFFFFF</color>    <color name="button_background">#2A91BD</color>    <color name="comment_background_inactive">#5F5F5F</color>    <color name="comment_background_active">#939393</color>    <color name="comment_foreground">#FFFFFF</color>    <color name="comment_foreground_important">#FF9D2F</color>    ...    <color name="comment_shadow">#323232</color>

这很容易发生, 并使得当想要改变基础颜色的时候非常困难. 而且, 这些属性的定义往往和一些上下文有所联系, 像是button或是comment, 那么他们就应该定义在button style中, 而不是color.xml里面.

正确的范例是这样:

<resources>    <!-- grayscale -->    <color name="white"     >#FFFFFF</color>    <color name="gray_light">#DBDBDB</color>    <color name="gray"      >#939393</color>    <color name="gray_dark" >#5F5F5F</color>    <color name="black"     >#323232</color>    <!-- basic colors -->    <color name="green">#27D34D</color>    <color name="blue">#2A91BD</color>    <color name="orange">#FF9D2F</color>    <color name="red">#FF432F</color></resources>

从应用的设计者那里获取关于应用内颜色的调色盘. 命名不一定非要是颜色名, 也可以是类似 “brand_primary”, “brand_secondary”, “brand_negative”这样的方式. 进行这样的颜色设定规范不仅有利于改变和重构颜色, 也有助于明确多少种颜色被使用. 基于通常的UI审美设计来说, 颜色的种类是越少越好.


像对待color.xml一样对待dimens.xml. 基于上述的理由, 对待dimens.xml文件应该和对待color.xml一样, 定义间距和字体大小的”调色盘”. 下面是一个好例子:

<resources>    <!-- font sizes -->    <dimen name="font_larger">22sp</dimen>    <dimen name="font_large">18sp</dimen>    <dimen name="font_normal">15sp</dimen>    <dimen name="font_small">12sp</dimen>    <!-- typical spacing between two views -->    <dimen name="spacing_huge">40dp</dimen>    <dimen name="spacing_large">24dp</dimen>    <dimen name="spacing_normal">14dp</dimen>    <dimen name="spacing_small">10dp</dimen>    <dimen name="spacing_tiny">4dp</dimen>    <!-- typical sizes of views -->    <dimen name="button_height_tall">60dp</dimen>    <dimen name="button_height_normal">40dp</dimen>    <dimen name="button_height_short">32dp</dimen></resources>

在布局中对margins和paddings用定义的属性名spacing_****而非硬编码, 就像string内容一样. 这将给人以一致的体验, 并且使其更容易组织和改变.


strings.xml

类似命名空间的方式为你的strings进行命名, 不要担忧存在几个重复的词. 语言是复杂的, 所以命名空间有携带上下文和打破歧义的必要.

Languages are complex, so namespaces are necessary to bring context and break ambiguity.

Bad:

<string name="network_error">Network error</string><string name="call_failed">Call failed</string><string name="map_failed">Map loading failed</string>

Good:

<string name="error_message_network">Network error</string><string name="error_message_call">Call failed</string><string name="error_message_map">Map loading failed</string>

不要将string值设置成全大写, 应该遵循通常的约定(例如首字母大写), 如果你必须要展示全大写的string, 也只是在textview内设置textAllCaps属性.

Bad:

<string name="error_message_call">CALL FAILED</string>

Good:

<string name="error_message_call">Call failed</string>


避免view的多层嵌套. 有些时候你为了完成view上面的一些改变而临时添加了一个LinearLayout. 往往会演变成如下的情况:

<LinearLayout    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    >    <RelativeLayout        ...        >        <LinearLayout            ...            >            <LinearLayout                ...                >                <LinearLayout                    ...                    >                </LinearLayout>            </LinearLayout>        </LinearLayout>    </RelativeLayout></LinearLayout>

哪怕你没有在布局文件中明显地看到这样的情况, 如果你(在Java中)将一个视图inflating到另一个视图中, 也依然最终可能出现这样的结果.

这将导致很多问题. 你也许因为进程需要处理一个过于复杂的视图树从而遇到性能问题. 另一个更加严重的问题可能就是 StackOverflowError.

因此, 学习如何让视图的嵌套关系尽可能扁平是非常重要的. 学习如何使用 RelativeLayout, 以及 optimize your layouts and to use the <merge> tag.


注意与WebView相关的问题. 当你必须要展示一个网页页面的时候, 例如一篇新闻文章, 避免在客户端进行HTML的清理, 而是应该要求后端程序员提供纯粹的HTML. 如果WebViews不是绑定到ApplicationContext而是保留了Activities的引用, 那么WebViews 也会导致内存泄漏. 避免用WebView仅仅展示一段简单的文本或是按钮, 请使用控件…


Text frameworks

AndroidSDK的测试框架依然处于婴儿期, 尤其是UI测试部分. Android Gradle目前通过实现一个名为connectedAndroidTest的测试任务来进行测试, 它运行JUnit测试, 使用JUnit的扩展程序与Android的帮助程序(见此). 这意味着你需要连接设备或者模拟器. 请参考官方指南 [1] [2]

仅仅使用Robolectric进行单元测试, 而非view的测试. 它是一个旨在为通过提供“与设备断开连接”的测试来提高开发速度的测试框架, 特别适用于modles和view models的单元测试. 然而, 在UI测试方面表现就很不理想. 特别是在动画和对话框等相关元素的测试上面, 问题很多, 而且这个过程像是漫步在黑夜中, 因为你无法看到测试屏幕.

Robotium使得UI测试更轻松. 你不需要用其来进行连接到设备的UI方面测试, 但是基于其诸多的获取与分析视图以及控制屏幕的辅助功能, 可能会对你有所帮助. 测试样例如下:

solo.sendKey(Solo.MENU);solo.clickOnText("More"); // searches for the first occurrence of "More" and clicks on itsolo.clickOnText("Preferences");solo.clickOnText("Edit File Extensions");Assert.assertTrue(solo.searchText("rtf"));

AssertJ-Android是一个AssertJ扩展库, 使得断言在Android测试中更容易, 同时你还可以使用Robolectric or Robotium. Assert-J提供了大量额外的库使得测试一些特定组件更加容易, 例如android-support, play-services, appcomat-libraries. 样例如下:

// Example assertion on an intent with AssertJ-AndroidIntent nextStartedServiceIntent = shadowOf(activity).getNextStartedService();assertThat(nextStartedServiceIntent)    .isNotNull()    .hasAction("org.example.action.YOUR_ACTION")    .hasExtra("yourExtra", "expectedValue")    ... so on


Emulators

AndroidSDK的模拟器, 特别是x86版本, 近年来性能上有了显著提升, 已经可以应付大多数日常开发的需要. 然而, 你仍然需要确保你的应用在真实设备上的运行体验一切正常. 测试所有的真实设备是不实际的, 所以需要集中力量在那些市场份额更大的设备和与你应用最相关的设备上.


Proguard configuration

ProGuard 普遍用于android收缩和混淆封装代码.

是否使用取决于你项目的设置. 通常通过配置你的Gradle来在构建一个发布版apk的时候使用Proguard:

buildTypes {    debug {        minifyEnabled false    }    release {        signingConfig signingConfigs.release        minifyEnabled true        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'    }}

为了确定哪些代码必须保留, 哪些代码是可以被丢弃或混淆的, 你必须为代码指定一个或多个入口点. 这些入口点通常是含有主要方法, applets, midlets, activities等的类文件. Android框架使用一个默认的配置, 可以从如下位置找到: SDK_HOME/tools/proguard/proguard-android.txt. 使用上述配置, 在my-project/app/proguard-rules.pro处自定义的规则将会被添加到默认配置中.

通常遇到问题会是在应用程序启动时崩溃, 问题是ClassNotFoundExceptionNoSuchFieldException 或者其他类似的, 尽管在构建过程中(assembleRelease)是毫无警告提示的. 这意味着如下两者之一:

  1. 考虑到不需要,ProGuard已经删除了类,枚举,方法,字段或注释
  2. ProGuard已经混淆(重命名)类,枚举或字段名称,但是它被间接使用其原始名称,即通过Java反射

检查 app/build/outputs/proguard/release/usage.txt 中是否问题所在的内容被移除了. 检查app/build/outputs/proguard/release/mapping.txt 中是否问题所在的内容被混淆了.

为了避免移除所需的内容, 可以通过在你的配置文件中添加keep关键字的属性:

-keep class com.futurice.project.MyClass { *; }

为了避免混淆所需的内容, 可以通过如下配置:

-keepnames class com.futurice.project.MyClass { *; }

通过这里了解更多: Proguard


在你项目的早期, 就做一个发布版本, 用以检查Proguard是否保护了重要内容. 同时当你引入新的类库以后, 也做一个发布版本并在真机上进行测试以确保一切无误. 不要直到你的应用到了1.0版本才想起来做这事, 等待你的可能是无数惊吓和短的可怜的修复时间.

Tip. 每次向你的用户推送了新的发布版后, 都应该保存你的 mapping.txt 文件. 这样才能保证当用户遇到了一个bug并提交了模糊的堆栈跟踪时你不会一脸懵逼…

DexGuard.

If you need hard-core tools for optimizing, and specially obfuscating release code, consider DexGuard, a commercial software made by the same team that built ProGuard. It can also easily split Dex files to solve the 65k methods limitation.


Data storage

SharedPreferences

如果只需要持久化一些简单的标识符数据, 并且应用在单个进程中运行, SharedPreferences可能就足够了. 这是一个很好的默认选择.

这里有两个你可能不想使用sp的理由:

  • 性能: 你需要持久化的数据比较复杂或者是数据量庞大
  • 多进程访问数据: 你的控件或远端服务运行在各自的进程中并且需要同步数据

ContentProviders

在sp无法满足你的情况下, 你应该使用平台自带的ContentProviders, 它快速的同时也是进程安全的.

唯一的问题在于设置它们所需的样板代码量以及低质量的教程. 然而, 或许你可以通过使用例如 Schematic 这样的库来生成并显著减少工作量.

你仍然需要自己编写一些解析代码以从Sqlite列读取数据对象, 反之亦然. 可以将数据对象序列化, 例如使用Gson, 并且只能持续生成字符串. 以这种方式你的性能会下降; 但另一方面, 您不需要为数据类的所有字段声明数据类型.

Using an ORM

通常不建议使用对象关系映射库(ORM), 除非你有非常复杂的数据, 并且你非常需要它. 它们非常复杂并且需要时间去学习. 如果你确定要使用, 请一定注意在你的应用使用过程中是否是进程安全的, 因为现有的许多关于ORM的解决方案上看来这个问题是颇为严峻的.


Use Stetho

Stetho 是来自于Facebook的android应用程序调试桥, 它与Chrome的开发工具集成在一起. 使用Stetho可以轻松检查你的应用, 特别是网络流量. 对于检查和编辑SQLite数据库和应用的sp文件也是提供了优秀便利的支持. 但是你需要确保只在debug版本中启用它, 在发布版本中应该禁用.

另外, 可以替换的选择比如 Chuck . 尽管它提供的功能稍微有些简化, 但对于测试人员来说依然是优秀的, 因为它的日志显示在设备上而非Stetho的需要通过复杂的连接到Chrome中设置.


Use LeakCanary

LeakCanary 是一个使得运行时检查内存泄漏变得更为普遍易用的库. 参看 wiki 来了解更多详情以及用法. 你仅需要谨记在发布版中只配置”no-op”依赖项.


Thanks to

Antti Lammi, Joni Karppinen, Peter Tackage, Timo Tuominen, Vera Izrailit, Vihtori Mäntylä, Mark Voit, Andre Medeiros, Paul Houghton and other Futurice developers for sharing their knowledge on Android development.

License

Futurice Oy Creative Commons Attribution 4.0 International (CC BY 4.0)

原创粉丝点击