GVKun编程网logo

Android异常处理最佳实践?(android 异常处理)

12

本文将带您了解关于Android异常处理最佳实践?的新内容,同时我们还将为您解释android异常处理的相关知识,另外,我们还将为您提供关于Android–MVVM中ViewModel状态的最佳实践?

本文将带您了解关于Android异常处理最佳实践?的新内容,同时我们还将为您解释android 异常处理的相关知识,另外,我们还将为您提供关于Android – MVVM中ViewModel状态的最佳实践?、android – 多个ListFragments的片段管理最佳实践、android – 选项卡导航的最佳实践?、Android 开发最佳实践的实用信息。

本文目录一览:

Android异常处理最佳实践?(android 异常处理)

Android异常处理最佳实践?(android 异常处理)

如果我的应用程序崩溃了,它会挂起几秒钟,然后Android告诉我该应用程序崩溃了,需要关闭。所以我当时想用通用的方式捕获应用程序中的所有异常:

try {    // ... } catch(Exception e) {     // ...}

并做一个新的Activity解释,说明应用程序立即崩溃(并且还使用户有机会发送包含错误详细信息的邮件),而不是由于Android而造成了延迟。是否有更好的方法来实现这一目标?

更新: 我使用的是启用了ART的Nexus
5,但我没有注意到我以前遇到的崩溃(我最初所说的“挂起”)是延迟的。我认为既然所有内容都是本机代码,那么崩溃会立即发生,并且会获取所有崩溃信息。也许Nexus
5很快就可以了:)不管怎么说,这可能不会在将来的Android版本中引起担心(假设ART将成为Android L中的默认运行时)。

答案1

小编典典

在这里,检查链接以供参考。

在这里,您创建一个类 ExceptionHandler that implementsjava.lang.Thread.UncaughtExceptionHandler..

在本课程中,您将进行一些节省生命的工作,例如创建stacktrace和准备上载错误报告等。

现在是重要的部分,
即如何捕获该异常。虽然很简单。在您的重写onCreate方法中调用super方法之后,在每个Activity中复制以下代码行。

Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this));

您的活动可能看起来像这样……

public class ForceClose extends Activity {    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this));        setContentView(R.layout.main);    }}

希望这可以帮助…

Android – MVVM中ViewModel状态的最佳实践?

Android – MVVM中ViewModel状态的最佳实践?

我正在开发一个Android应用程序,使用LiveData上的MVVM模式(可能是Transformations)和View和viewmodel之间的DataBinding.由于应用程序“正在增长”,现在viewmodels包含大量数据,后者中的大多数都保存为LiveData以使视图订阅它们(当然,UI需要这些数据,不管是双向绑定如何每个EditTexts或单向绑定).我听到(和Google搜索)关于在viewmodel中保存代表UI状态的数据.但是,我发现的结果只是简单而通用.我想知道是否有人提示或者可以就此案例分享一些关于最佳实践的知识.简单来说,考虑到LiveData和DataBinding可用,在viewmodel中存储UI(View)状态的最佳方法是什么?提前感谢您的回答!

解决方法:

我在工作中遇到同样的问题,可以分享对我们有用的东西.我们在Kotlin开发100%,所以下面的代码示例也是如此.

UI状态

为了防止viewmodel因大量LiveData属性而变得臃肿,请为要观察的视图(Activity或Fragment)公开单个ViewState.它可能包含以前由多个LiveData公开的数据以及视图可能需要正确显示的任何其他信息:

data class LoginViewState (
    val user: String = "",
    val password: String = "",
    val checking: Boolean = false
)

Note, that I’m using a Data class with immutable properties for the state and deliberately don’t use any Android resources. This is not something specific to MVVM, but an immutable view state prevents UI inconsistencies and threading problems.

在viewmodel内部创建一个LiveData属性来公开状态并初始化它:

class Loginviewmodel : viewmodel() {
    val state = mutablelivedata<LoginViewState>()

    init {
        state.value = LoginViewState()
    }
}

然后发出一个新状态,从viewmodel内的任何地方使用Kotlin的Data类提供的复制功能:

state.value = state.value!!.copy(checking = true)

在视图中,像观察任何其他LiveData一样观察状态并相应地更新布局.在View层中,您可以将状态属性转换为实际视图可见性,并使用具有对Context的完全访问权限的资源:

viewmodel.state.observe(this, Observer {
    it?.let {
        userTextView.text = it.user
        passwordTextView.text = it.password
        checkingImageView.setimageResource(
            if (it.checking) R.drawable.checking else R.drawable.waiting
        )
    }
})

合并多个数据源

由于您之前可能在viewmodel中公开了数据库或网络调用的结果和数据,因此您可以使用MediatorLiveData将这些结果和数据混合到单个状态:

val state = MediatorLiveData<LoginViewState>()

state.addSource(databaseUserLiveData, { name ->
    state.value = state.value!!.copy(user = name)
})
...

数据绑定

由于统一的,不可变的ViewState基本上破坏了数据绑定库的通知机制,因此我们使用可扩展的BindingState来扩展BaSEObservable以有选择地通知更改的布局.它提供了一个刷新函数,可以接收相应的ViewState:

更新:删除了if语句检查更改的值,因为数据绑定库已经只处理实际更改的值.感谢@CarsonH​​olzheimer

class LoginBindingState : BaSEObservable() {
    @get:Bindable
    var user = ""
        private set(value) {
            field = value
            notifyPropertyChanged(BR.user)
        }

    @get:Bindable
    var password = ""
        private set(value) {
            field = value
            notifyPropertyChanged(BR.password)
        }

    @get:Bindable
    var checkingResId = R.drawable.waiting
        private set(value) {
            field = value
            notifyPropertyChanged(BR.checking)
        }

    fun refresh(state: angryCatViewState) {
        user = state.user
        password = state.password
        checking = if (it.checking) R.drawable.checking else R.drawable.waiting
    }
}

在观察视图中为BindingState创建一个属性,并从Observer调用refresh:

private val state = LoginBindingState()

...

viewmodel.state.observe(this, Observer { it?.let { state.refresh(it) } })
binding.state = state

然后,将状态用作布局中的任何其他变量:

<layout ...>

    <data>
        <variable name="state" type=".LoginBindingState"/>
    </data>

    ...

        <TextView
            ...
            android:text="@{state.user}"/>

        <TextView
            ...
            android:text="@{state.password}"/>

        <ImageView
            ...
            app:imageResource="@{state.checkingResId}"/>
    ...

</layout>

高级信息

一些样板文件肯定会受益于扩展函数和Delegated属性,例如更新ViewState和通知BindingState中的更改.

如果您想了解使用“干净”架构的架构组件的状态和状态处理的更多信息,您可以查看Eiffel on GitHub.

它是我专门为处理不可变视图状态和与viewmodel和LiveData进行数据绑定而创建的库,以及将它与Android系统操作和业务用例粘合在一起.
文档比我在这里提供的内容更深入.

android – 多个ListFragments的片段管理最佳实践

android – 多个ListFragments的片段管理最佳实践

我计划在一个活动中包含3个片段列表.目标是从第一个列表中选择talk选项,然后根据您在talk list中单击的内容转换到运行列表,然后在运行列表中,根据您单击的内容将转换到最终的eat list.这应该发生在片段本身(就像我拥有它)或调用活动来处理来回传递数据到片段?

public class OptionsActivity extends Activity {

    protected TalkFragment talk;
    protected RunFragment run;
    protected EatFragment eat;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        talk = new TalkFragment();
        run = new RunFragment();
        eat = new EatFragment();
    } 
}


public class TalkFragment extends ListFragment {
    private Cursor mCursor;
    int mCurCheckPosition = 0;

    @Override
    public void onActivityCreated(Bundle savedState) {
        super.onActivityCreated(savedState);

    }
    @Override
    public void onListItemClick(ListView l,View v,int pos,long id) {
        mCurCheckPosition = pos;
        // We can display everything in-place with fragments.
        // Have the list highlight this item and show the data.
        getListView().setItemChecked(pos,true);

        // Check what fragment is shown,replace if needed.
        RunFragment run_frag = (RunFragment) getFragmentManager().findFragmentById(R.id.fragment_run);
        if (run_frag == null || run_frag.getShownIndex() != pos) {
            run_frag = RunFragment.newInstance(pos);
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.replace(R.id.details,details);
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
            ft.commit();
        }

    } 
}

这显然只是嗤之以鼻,但你明白了.如果我这样做,我不确定如何正确地传递某些参数片段.理想情况下,RunFragment会根据在TalkFragment中单击的项目的ID知道要显示的内容.这些应该通过活动吗?

解决方法

我通常这样做的方法是让Activity成为处理碎片的交通警察.您的onListItemClick实现可以告诉Activity它想要做什么:

public class OptionsActivity extends Activity {

    protected TalkFragment talk;
    protected RunFragment run;
    protected EatFragment eat;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        talk = new TalkFragment();
        run = new RunFragment();
        eat = new EatFragment();
    }

    public void showRunFragment() {
        showFragment(R.id.fragment_run);
    }

    public void showEatFragment() {
        showFragment(R.id.fragment_eat);
    }

    public void showFragment(int fragmentId) {
        // Check what fragment is shown,replace if needed.

        ...
    }
}


public class TalkFragment extends ListFragment {
    private Cursor mCursor;
    int mCurCheckPosition = 0;

    @Override
    public void onActivityCreated(Bundle savedState) {
        super.onActivityCreated(savedState);

    }

    @Override
    public void onListItemClick(ListView l,true);

        getActivity().showRunFragment()
    } 
}

android – 选项卡导航的最佳实践?

android – 选项卡导航的最佳实践?

我正在寻找使用sherlock操作栏的标签导航的最佳做法.
更改片段的正确方法是什么,并在选择另一个选项卡时将片段添加到backstack并清除后栈.

是否有任何好的示例或开源项目显示如何正确执行?

解决方法

我不会直接使用ABS来做到这一点.一旦您的标签需要片段切换等,您将遇到麻烦.我认为正确的方法是使用与ABS兼容的ViewPagerIndicator.作为奖励,您还可以在标签之间左右滑动.
您需要compat包(例如ABS),您可以在中找到示例用法
samples folder.

Android 开发最佳实践

Android 开发最佳实践

Android 开发最佳实践

构建系统

默认编译环境应该是Gradle. Ant 有很多限制,用起来也很不方便,并且现在Github上的开源项目都是采用的Gradle。使用Gradle,完成以下工作会很方便:

  • 构建APP不同版本的变种,方便于向不同市场发布App
  • 很方便的管理和下载依赖,这个是最显而易见的,依赖第三方的库一句话搞定
  • 制作简单类似脚本的任务
  • 自定义秘钥

同时,Android Gradle是Google推荐的作为新标准的构建系统,并还在不断的完善中。

工程结构

现阶段有两种流行的结构:老的Ant & Eclipse ADT 工程结构,和新的Gradle & Android Studio 工程结构,我们开发推荐的应选择新的工程结构,并且会发现将我们的工程从老的结构移植到新的结构后,我们的开发效率和质量都将会得到质的提升。下面是两种结构:

老的结构:

old-structure
├─ assets
├─ libs
├─ res
├─ src
│  └─ com/futurice/project
├─ AndroidManifest.xml
├─ build.gradle
├─ project.properties
└─ proguard-rules.pro

新的结构

new-structure
├─ library-foobar
├─ app
│  ├─ libs
│  ├─ src
│  │  ├─ androidTest
│  │  │  └─ java
│  │  │     └─ com/futurice/project
│  │  └─ main
│  │     ├─ java
│  │     │  └─ com/futurice/project
│  │     ├─ res
│  │     └─ AndroidManifest.xml
│  ├─ build.gradle
│  └─ proguard-rules.pro
├─ build.gradle
└─ settings.gradle

这两种结构主要的区别在于,新的结构明确的分开了''source sets'' (main,androidTest),这是Gradle的一个理念。我们的项目引用第三方项目库时(例如,library-foobar),拥有一个顶级包名app从第三方库项目区分你的应用程序是非常有用的。然后settings.gradle不断引用这些库项目,其中app/build.gradle可以引用。

Gradle 配置

常用结构 参考Google''s guide on Gradle for Android

密码 在做版本release时我们app的 build.gradle需要定义 signingConfigs.此时应该避免以下内容:

不要做这个 . 这会出现在版本控制中。

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

而是,建立一个不加入版本控制系统的gradle.properties文件。

KEYSTORE_PASSWORD=password123
KEY_PASSWORD=password789

那个文件是gradle自动引入的,你可以在buld.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.")
		}
	}
}

使用 Maven 依赖方案代替使用导入jar包方案 如果在我们的项目依赖工程使用的是jar文件,那么它们可能成为永久的版本,如2.1.1.下载jar包更新他们是很繁琐的,这个问题Maven很好的解决了,这也是Android Gradle构建中推荐的方法。我们可以指定版本的一个范围,如2.1.+,然后Maven会自动升级到制定的最新版本,例如:

dependencies {
	compile ''com.netflix.rxjava:rxjava-core:0.19.+''
	compile ''com.netflix.rxjava:rxjava-android:0.19.+''
	compile ''com.fasterxml.jackson.core:jackson-databind:2.4.+''
	compile ''com.fasterxml.jackson.core:jackson-core:2.4.+''
	compile ''com.fasterxml.jackson.core:jackson-annotations:2.4.+''
	compile ''com.squareup.okhttp:okhttp:2.0.+''
	compile ''com.squareup.okhttp:okhttp-urlconnection:2.0.+''
}

IDE集成开发环境和文本编辑器

无论使用什么编辑器,一定要构建一个良好的工程结构 当下首推Android Studio,因为他是由谷歌开发,最接近Gradle,默认使用最新的工程结构,已经到1.3的稳定版本,它就是为Android开发定制的。

我们也可以使用Eclipse ADT ,但是需要对它进行配置,因为它使用了旧的工程结构和Ant作为构建系统

无论使用何种开发工具,只要确保Gradle和新的项目结构保持官方的方式构建应用程序,避免编辑器配置文件加入到版本控制。例如,避免加入Ant build.xml文件。 特别如果需要改变Ant的配置,不要忘记保持build.gradle是最新和起作用的。同时,善待其他开发者,不要强制改变他们的开发工具和偏好。

开源类库推荐

Jackson 是一个将java对象转换成JSON与JSON转化java类的类库。Gson是解决这个问题的流行方案,然而Jackson更高效,因为它支持替代的方法处理JSON:流、内存树模型,和传统JSON-POJO数据绑定。不过,Jsonkson库比起GSON更大,所以根据我们的情况选择,你可能选择GSON来避免APP 65k个方法限制。其它选择: Json-smart and Boon JSON

网络请求,缓存,图片 执行请求后端服务器,有几种交互的解决方案,我们可以使用Volley或者Retrofit来实现自己的网络客户端。Volley同时提供图片缓存类。若果我们选择使用Retrofit,那么可以考虑使用Picasso来加载图片和缓存,同时使用OkHttp作为高效的网络请求。Retrofit,Picasso和OkHttp都是有同一家公司开发(注:是由Square公司开发),所以它们能很好的在一起运行。OkHttp 同样可以和Volley在一起使用 Volley.

当心dex方法数限制,同时避免使用过多的类库 Android apps,当打包成一个dex文件时,有一个65535个应用方法强硬限制 [1] https://medium.com/@rotxed/dex-skys-the-limit-no-65k-methods-is-28e6cb40cf71 [2] http://blog.persistent.info/2014/05/per-package-method-counts-for-androids.html [3] http://jakewharton.com/play-services-is-a-monolith/。 当我们突破65k限制之后又会看到一个致命错误。因此,使用一个正常范围的类库文件,同时使用dex-method-counts工具来决定哪些类库可以再65k限制之下使用,特别的避免使用Guava类库,因为它包含超过13k个方法。

Activities and Fragments

Fragments应该作为你实现UI界面默认选择。可以重复使用Fragments接口来组合成我们的应用。并强烈推荐使用Fragments而不是activity来呈现UI界面,理由如下:

  • 提供多窗格布局解决方案 Fragments 的引入主要将手机应用延伸到平板电脑,所以在平板电脑上你可能有A、B两个窗格,但是在手机应用上A、B可能分别充满整个屏幕。如果你的应用在最初就使用了fragments,那么以后将你的应用适配到其他不同尺寸屏幕就会非常简单。

  • 屏幕间数据通信 从一个Activity发送复杂数据(例如Java对象)到另外一个Activity,Android的API并没有提供合适的方法。不过使用Fragment,你可以使用一个activity实例作为这个activity子fragments的通信通道。即使这样比Activity与Activity间的通信好,当然也可以使用Event Bus架构,不过这个不推荐过多的使用,因为这个过多的使用会造成很高的维护成本。

  • Fragments 一般通用的不只有UI 可以有一个没有界面的fragment作为Activity提供后台工作。进一步可以使用这个特性来创建一个fragment包含改变其它fragment的逻辑而不是把这个逻辑放在activity中。

  • 甚至ActionBar 都可以使用内部fragment来管理 可以选择使用一个没有UI界面的fragment来专门管理ActionBar,或者你可以选择使用在每个Fragment中添加它自己的actionBar 来作为父Activity的ActionBar.参考.

主要事项:不建议广泛的使用嵌套的fragments,因为有时会引起matryoshkabugs。我们只有当它有意义(例如,在水平滑动的ViewPager在像屏幕一样fragment中)或者他的确是一个明智的选择的时候才广泛的使用fragment。

在一个架构级别,APP应该有一个顶级的activity来包含绝大部分业务相关的fragment。我们也可能还有一些辅助的activity ,这些辅助的activity与主activity通信一般采用这两种方法Intent.setData()Intent.setAction()或类似的方法。

Java 包结构

Android 应用程序在架构上大致是Java中的Model-View-Controller结构。在Android 中Fragment和Activity通常上是控制器类(http://www.informit.com/articles/article.aspx?p=2126865).换句话说,他们是用户接口的部分,同样也是Views视图的部分。

正是因为如此,才很难严格的将fragments (或者 activities) 划分成控制器controlloers还是视图 views。最好还是将它们放在自己单独的 fragments 包中。只要遵循之前提到的建议,Activities 则可以放在顶级目录下。若果规划有2到3个以上的activity,那么还是同样新建一个activities包吧。

这种架构可以看做是另一种形式的MVC,包含要被解析API响应的JSON数据,来填充的POJO的models包中。 和一个views包来包含自定义视图、通知、导航视图,widgets等等。适配器Adapter是在数据和视图之间。然而他们通常需要通过getView()方法来导出一些视图,所以可以将adapters包放在views包里面。

一些控制器角色的类是应用程序级别的,同时是接近系统的。这些类放在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.

组织布局文件 若不确定如何排版好一个布局文件,遵循统一的规则会很好的提高效率。

  • 每一个属性一行,缩进4个空格
  • android:id 总是作为第一个属性
  • android:layout_**** 属性在上边
  • style 属性在底部
  • 关闭标签/>单独起一行,有助于调整和添加新的属性
<?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"/>

	<include layout="@layout/reusable_part" />

</LinearLayout>

作为一个经验法则,android:layout_****属性应该在 layout XML 中定义,同时其它属性android:**** 应放在 styler XML中。这个规则也有例外,不过大部分情况下都是很好的。这个思想整体是保持layout属性(positioning, margin, sizing) 和content属性在布局文件中,同时将所有的外观细节属性(colors, padding, font)放在style文件中。

例外有以下这些:

  • android:id 明显应该在layout文件中
  • layout文件中android:orientation对于一个LinearLayout布局通常更有意义
  • android:text 由于是定义内容,应该放在layout文件中
  • 有时候将android:layout_widthandroid:layout_height属性放到一个style中作为一个通用的风格中更有意义,但是默认情况下这些应该放到layout文件中。

使用styles 几乎每个项目都需要适当的使用style文件,因为对于一个视图来说有一个重复的外观是很常见的。 在应用中对于大多数文本内容,最起码应该有一个通用的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,对于一组相关的和重复android:****的属性都应该放到一个通用的style中。

将一个大的style文件分割成多个文件 为了不去维护一个很大的styles.xml,我们可以有多个styles.xml 文件。需要注意的是styles这个文件名称并没有作用,起作用的是在文件里xml的<style>标签。因此我们项目中可以有多个style文件styles.xml,style_home.xml,style_item_details.xml,styles_forms.xml

colors.xml是一个调色板 在我们的colors.xml文件中应该只是映射颜色的名称一个RGBA值,而没有其它的。不要使用它为不同的按钮来定义RGBA值。

不要这样做

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

使用这种格式,会很容易的造成重复定义RGBA值的情况,这样如果需要改变一些基本色就会变的很复杂。同时,这些定义是跟一些环境关联起来的,如button或者comment,但这些属性应该放到一个按钮风格中,而不是在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>

调色板可以从美工那里得到,名称不需要跟"green", "blue"等等相同。"brand_primary", "brand_secondary", "brand_negative" 这样的名字也是完全可以接受的。像这样规范的颜色很容易修改或重构,会使应用一共使用了多少种不同的颜色变得非常清晰。通常一个具有审美价值的UI来说,减少使用颜色的种类是非常重要的。

像对待colors.xml一样对待dimens.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字符串一样直接写值。这样写会非常有感觉,会使组织和改变风格或布局是非常容易。

避免深层次的视图结构 有时候为了摆放一个视图,我们可能尝试添加另一个LinearLayout。也可能使用这种方法解决:

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

	<RelativeLayout
		...
		>

		<LinearLayout
			...
			>

			<LinearLayout
				...
				>

				<LinearLayout
					...
					>
				</LinearLayout>

			</LinearLayout>

		</LinearLayout>

	</RelativeLayout>

</LinearLayout>

这种多层次的嵌套结构就很可能会导致一系列的问题。最主要的会是遇到性能问题,因为这就需要处理一个复杂的UI树结构,系统在测量和绘制界面就会花费很长的时间,如果这一系列的操作(网络请求,界面测量,布局,绘制等等)不能在16ms中完成,最终结果就会出现界面掉帧及卡顿的情况,这也是系统卡顿出现的最主要的原因之一。因此我们尽量是用RelativeLayout来替代LinearLayout,维护一个简洁的视图tree

小心关于WebViews的问题. 如果必须显示一个web视图,比如说对于一个新闻文章,要避免做客户端处理HTML的工作,最好让后端工程师协助,让他返回一个 "" HTML。WebViews 也能导致内存泄露,当使用简单的文字或按钮时,应避免使用WebView,这时使用TextView或Buttons更好。

测试框架

Android SDK的测试框架还处于初级阶段,特别是关于UI测试方面。Android Gradle 目前实现了一个叫connectedAndroidTest的测试,它使用一个JUnit 为Android提供的扩展插件 extension of JUnit with helpers for Android.可以跑生成的JUnit测试,

模拟器

毫无疑问的会推荐Genymotion 模拟器,他的运行速度比起典型的AVD模拟器会有质的提升。他可以高质量的模拟网络连接,GPS位置,等等。它同时还有理想的连接测试。若涉及适配使用很多不同的设备,买一个Genymotion版权是比买很多真设备便宜多的。

注意:Genymotion模拟器没有装载所有的Google服务,如Google Play Store和Maps(这个可以通过第三方的方法来给我们的模拟器装上Google的GSM)。

混淆配置

ProGuard是一个在Android项目中广泛使用的压缩和混淆打包的源码的工具。

是否使用ProGuard取决我们项目的配置,当构建一个release版本的apk时,通常应该配置gradle文件。

buildTypes {
	debug {
		minifyEnabled false
	}
	release {
		signingConfig signingConfigs.release
		minifyEnabled true
		proguardFiles ''proguard-rules.pro''
	}
}

Android framework 使用一个默认的配置文件,可以在SDK_HOME/tools/proguard/proguard-android.txt目录下找到。自定义的工程在project-specific中指定混淆规则,如在my-project/app/proguard-rules.pro中定义,会被添加到默认的配置中。

关于 ProGuard 一个普遍的问题,是看应用程序是否崩溃并报ClassNotFoundException或者NoSuchFieldException 或类似的异常,即使编译是没有警告并运行成功。这意味着以下两种可能:

  1. ProGuard 已经移除了类,枚举,方法,成员变量或注解。
  2. ProGuard 混淆了类,枚举,成员变量的名称,但是这些名字又被原始名称使用了,比如通过Java的反射。

检查app/build/outputs/proguard/release/usage.txt文件看有问题的对象是否被移除了。 检查 app/build/outputs/proguard/release/mapping.txt 文件看有问题的对象是否被混淆了。

以防 ProGuard 剥离 需要的类和类成员,添加一个 keep选项在proguard 配置文件中:

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

防止 ProGuard 混淆 一些类和成员,添加 keepnames:

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

可以查看this template''s ProGuard config 中的一些例子。 更多例子请参考Proguard。

在构建项目之初,发布一个版本 来检查ProGuard规则是否正确的保持了重要的部分。同时无论何时当添加了新的类库,做一个发布版本,同时apk在设备上跑起来测试一下。不要等到app要发布"1.0"版本了才做版本发布,那时候可能会碰到好多意想不到的异常,需要一些时间去修复他们。

关于Android异常处理最佳实践?android 异常处理的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于Android – MVVM中ViewModel状态的最佳实践?、android – 多个ListFragments的片段管理最佳实践、android – 选项卡导航的最佳实践?、Android 开发最佳实践等相关内容,可以在本站寻找。

本文标签: