Toptal Developers的Android最佳实践和技巧

Share

此资源包含由Toptal网络成员提供的Android最佳实践和Android提示的集合.

本资源包含由Toptal网络成员提供的Android开发最佳实践和Android技巧的集合. As such, 本页将定期更新,包括更多的信息,并涵盖新兴的Android技术. 这是一个社区驱动的项目, 所以我们也鼓励你们做出贡献, 我们期待着你们的反馈.

查看Toptal资源页面,了解更多关于Android的信息 common mistakes, Android job description and Android interview questions.

使用Retrolambda和RxJava编写更少的代码

Retrolambda 允许你在Android上使用lambda函数,如果你使用的是旧的Java版本(在Java 8之前). 让我们来看看它们的区别:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        handleClick(v));
    }
});

使用Retrolambda的相同代码:

button.setOnClickListener(view -> handleClick(v));

RxJava 是轻量级Java虚拟机实现的 ReactiveX(Reactive Extensions). 它是一个单独的JAR库,支持Java 6或更高版本和基于jvm的语言. RxJava使用了一种不同于经典编程的方法,通过使用可观察序列来组合异步和基于事件的程序. 让我们来看看如何实现以下行为:

  1. 每隔10秒,向后端发出一个请求并获取汇率信息.
  2. 在出现错误的情况下,重试三次,每次尝试之间的延迟为三秒.

The code using RxJava:

mService = ServiceFactory.createRetrofitService (RatesService.class,
    RatesService.SERVICE_ENDPOINT);

mRatesObservable = Observable.interval(0, 10, TimeUnit.SECONDS)
    .flatMap(n ->
        mService.getRates()
            .retryWhen(new RetryWithDelay(3,3000))
            .subscribeOn(Schedulers.io()));

mRatesObservable = mRatesUpdater.getRates().doOnNext(rates -> updateRates(rates));

// Stop requests
mRatesObservable.unsibscribe();

在不到十行代码中,我们实现了带有网络响应的自定义行为. 试着想象一下,使用经典Java代码需要多少行代码, using callbacks, services, and loaders.

Jack and Jill and Java 8

但是,对于Retrolambda,请记住它可能很快就会被弃用,因为 Jack and Jill,这是一个用于Android的实验性工具,可以在N开发人员预览版中获得 Java 8 features out-of-the-box. 密切关注谷歌关于杰克和吉尔的最新消息, 并在准备好后立即切换到本机实现.

Contributors

Dmitry Ryazantsev

Freelance Android Developer

Montenegro

Dmitry是一名有六年多经验的Android开发人员,他善于沟通,总是试图找到最适合项目的技术. 他在Git、Lua (Corona SDK)、RxJava、Dagger等方面经验丰富. 他与一个大型团队合作开发了Yandex浏览器,安装量超过1000万. 他还开发了自己的项目:一款250人的游戏,000个安装,并发布了其他几个应用程序.

Show More

从Toptal获取最新的开发人员更新.

订阅意味着同意我们的 privacy policy

在Android中使用REST架构

Why and When to Use REST

在Google I/O 2010大会上,Virgil Dobjanschi做了一个关于实现的精彩演讲 REST (代表性状态转移)客户端在Android,标题 开发Android REST客户端应用程序. 他的前提是Android应用程序应该在状态同步和状态表示之间进行分离, 而REST使这更容易实现.

Virgil提出的REST架构使得用户可以开始下载内容, 不管他们对客户端做了什么(比如在下载完成之前退出),这些内容都会在他们返回时准备好. Furthermore, 因为REST架构假设每个唯一的URL代表一个唯一的状态, 用户可以确保下载的数据是最新的. 在内容经常被修改或需要实时修改的情况下, 服务器应该明确地阻止缓存结果(拍卖网站和带有购物车的网络商店使用的方法).

当客户机应用程序呈现的信息具有半永久性时,REST是理想的, 例如社交网络时间轴的内容或聊天室的历史记录. 这是因为它很有可能在几个小时或几天内仍然是最新的.

Nowadays, 为用户呈现在线内容的大多数应用程序都是REST客户机, 还有大量的服务和初创公司使用REST开发他们产品的移动版本. 然而,并非所有在线应用程序都需要是REST客户机. As with all technologies, 了解何时需要开发REST客户机应用程序是很重要的.

In order to be RESTful, 应用程序必须满足提高规模和性能的两个要求, 但如果应用程序违反了这些限制中的任何一个,它就不能被认为是RESTful.

What It Means to Be RESTful

Have Unique URIs

RESTful应用程序必须向使用者呈现不同的状态, 每一种状态都必须有一个唯一的统一资源标识符(URI)来描述它.

例如,考虑一个目录,每个产品都有一个唯一的页面. 如果URL公式类似于 server.com/catalogue/?item=XX,烤面包机的页面url可能为 server.com/catalogue/?item=toaster9000. 同样,如果需要帐户屏幕,则如下所示 server.com/account 存在,并且配置文件页可能存在 server.com/profile, and so on.

使用无状态服务器端数据存储

RESTful应用程序中的所有数据都应该存储在服务器端. 当客户端需要使用该数据定义其状态时, 它用足够的信息查询服务器以获得所需的信息, 而服务器仅仅提供一个响应. 它对用户的上下文一无所知.

这可能比听起来更棘手. 考虑一个聊天应用程序,其中每个聊天消息都有一个对话ID,将其链接到它所属的对话. 标准的聊天室行为是跟踪对话的当前状态,并且只传递最近的聊天消息, once, to the user. 如果对话框的当前状态存储在客户端, that’s RESTful, 但是如果它存储在服务器上(例如, 服务器知道当前用户所在的聊天室, 发送新消息的唯一必要信息是用户的文本, 但不是全部信息(chatid+message), 应用程序违反了REST规则.

REST Patterns

使REST变得简单的库

While one could 实现Virgil在他的Google I/O演示中描述的每个模式, 或者自己创建遵循REST规则的自定义逻辑, 重新发明轮子是不值得的. 有许多库解决了REST的主要用途, 我特别推荐两个库:RoboSpice和Retrofit.

RoboSpice 提供灵活的开箱即用缓存, 因此,您只需要配置响应应该缓存多长时间, 在此期间,您将收到保存的响应. 除了应用程序的业务逻辑之外,您不需要考虑网络魔法. 这个库的主要缺点, from my point of view, 您是否需要在不同的类中描述应用程序的所有请求. 如果需要不同的返回类型,同样需要一个新类. 如果您需要在预先存在的请求中使用不同的参数,则需要一个新类,依此类推. This can get messy.

我推荐的另一个图书馆, Retrofit, 通过允许您将后端url描述为接口方法来封装对web服务的调用. 它将HTTP API转换为Java接口, 因此,您可以将数据从您的模型返回到web服务端点.

例如,在Java中,通常您可能会:

getSomeData(ParamType参数);

而在Retrofit中,该方法用后端URL注释:

@GET("/rest_path/")

试试这些库和其他库, 找到你喜欢的解决问题的方法, 也许你会受到启发去实现你自己的库!

Contributors

Dmitry Ryazantsev

Freelance Android Developer

Montenegro

Dmitry是一名有六年多经验的Android开发人员,他善于沟通,总是试图找到最适合项目的技术. 他在Git、Lua (Corona SDK)、RxJava、Dagger等方面经验丰富. 他与一个大型团队合作开发了Yandex浏览器,安装量超过1000万. 他还开发了自己的项目:一款250人的游戏,000个安装,并发布了其他几个应用程序.

Show More

关于Android安全的一些话

而我相信一切 can be hacked, 作为开发者,你有责任定义破坏应用安全性的代价. 恶意方很容易通过Google Play商店发布的应用来破坏请求和响应, 没有任何逆向工程, 因此,保护服务器和客户机之间的通信是至关重要的.

似乎有些开发者认为他们的用户都是诚实的, 因此,他们没有实现任何安全措施来保护服务器和客户端之间的通信. Sure, 有混淆和签名检查的方法, 但是,如果在线请求和响应从一开始就没有得到保护, 他们不能阻止黑客攻击或作弊 MITM attacks.

假设您正在创建一个在线聊天应用程序,并且对安全性有所了解. Before each message is sent, a CAPTCHA must be cleared, obfuscation is used, 并进行校验和的计算. 客户端是安全的,因此只有来自此特定APK的消息才能通过您的服务发送. 但另一边发生了什么? 如果对方接收到一个普通的消息怎么办? 对于普通消息,不能保证有人在传输过程中没有更改消息. 你还不如根本没有安全保障.

即使没有昂贵的证书和HTTPS, 以下是提高网上通讯安全性的几种有效方法:

  • 通过组合数据为每个请求和响应制作签名, a timestamp, salt(只有服务器和应用知道的密钥), 然后用MD5哈希函数对其进行哈希. 当然,这并非万无一失, 钥匙可以在你的APK中找到, 但是现在要欺骗信息内容要复杂得多.
  • In addition to MD5, 你可以将密钥存储在不同的地方,并在运行时将其合并,从而使从应用程序中提取密钥的过程复杂化. 密钥的片段可以存储在常量中,硬编码在源代码中,并存储在资源中. 结合自定义算法或排序将碎片重新组合在一起, 即使黑客从前一个点获得了密钥, 他们仍然不明白签名是如何产生的.
  • 不依赖于客户端计算. 如果您需要检查订单状态或确认权限, 在服务器端执行此操作并返回签名响应. 如果你正在开发一个在线商店, 检查用户是否通过他们在服务器上的交易购买了你的商品, 不要相信客户会关心订单状态. 如果你的应用是一款游戏, 确认用户在服务器端可用的操作(构建新建筑物), 有多少资金可用于购买新物品, etc).

如果安全性对您的应用程序至关重要, 当你处理现实世界的钱时,情况是怎样的, 最好在隧道中实施额外的安全措施, http, and certificates. However, 对于不处理敏感信息的应用程序,上述建议已经足够了.

Contributors

Dmitry Ryazantsev

Freelance Android Developer

Montenegro

Dmitry是一名有六年多经验的Android开发人员,他善于沟通,总是试图找到最适合项目的技术. 他在Git、Lua (Corona SDK)、RxJava、Dagger等方面经验丰富. 他与一个大型团队合作开发了Yandex浏览器,安装量超过1000万. 他还开发了自己的项目:一款250人的游戏,000个安装,并发布了其他几个应用程序.

Show More

如何在更新UI时正确运行后台任务

Applications often need to perform a lot of time-consuming tasks; these are best performed in the background. The usual way of doing this in Java is by using the Thread class; spawn a new thread, do all the necessary tasks, and you are done. 但是,如果我们需要通知UI会怎样呢? 当后台任务需要向UI线程提交定期更新时, 我们面临一个问题,因为后台任务不能与UI线程上运行的任何东西交互.

Android有一个叫做AsyncTask的方便构造,它允许你执行后台任务并向UI线程发布更新. 用AsyncTask扩展你的类, override the proper methods, call the execute function, and you’re done. A first timer, however, will find it a bit tough to grasp at first; there are a couple of rules to follow and constraints to be aware of.

让我们来看看多线程在Android世界中是如何工作的. 应用程序从一个线程开始, 也称为主线程或应用程序线程或UI线程. 这个线程包含处理应用程序各种“事件”的循环, 其中一些是视觉更新, 比如点击按钮的视觉变化, TextView display changes, drawing, and the like. 生成一个新线程来执行后台任务会导致你的应用程序拥有两个线程, 一个用于UI,一个用于任务. 如何从后台任务访问UI线程? Well, you don’t. What you do is request that Android add an event to the main loop; it announces to your app that something needs to happen on the main thread and it is providing the “something.事件最终将被处理(这不是优先级),UI将被更新.

现在,我们如何提出这个请求?

您需要两样东西:处理程序(android.os.Handler) and a Runnable (java.lang.Runnable). Handler是播音员,Runnable是事件. Create a new handler (new Handler())在你的后台线程之外, 在活动的某个地方,并使其对线程可用, 这是重要的,因为你只能在主线程内创建一个线程. 接下来,创建Runnable和override的实例 run() 方法使用您希望在主线程中发生的事情(例如通过setText方法更新TextView). 剩下要做的就是打电话 handler.post() 并将Runnable作为参数传递. 通常,这三个步骤可以被压缩成一行(尽管看起来很讨厌):

new Handler().post(new Runnable() {
	@Override
	public void run() {
		// UI update code here
	}
});

以这种方式运行后台任务和更新UI比实现AsyncTask类更简单、更快. 然而,如果你发现自己不得不打不止几个电话给 handler.post, 并且你的线程经常长时间更新UI线程, 使用AsyncTask可能是可行的方法.

Contributors

Faye-Lino Agli

Freelance Android Developer

Canada

Faye-Lino是一位以结果为导向的IT专业人士,在实施技术以推动业务绩效方面有着良好的记录, productivity, and creativity. 他精通英语和法语. 他有丰富的经验,可以接受客户的想法,制作一个完整的项目,并将其完成. 他善于沟通,既能在团队中工作,也能单独工作.

Show More

Use Android Studio 2.0+开发您的Android应用程序

ide可以提高开发速度,您可以使用许多选项,如Eclipse或IntelliJ IDEA. 然而,最好的选择是使用Android Studio 2.0+. Android Studio是专为Android项目制作的,它是由Google在IntelliJ IDEA之上制作的. 此外,以下是一些如何更好地利用Android Studio的建议:

  • Use hotkeys. 有很多可用的,它们将帮助简化你的生活,提高你的效率. 欲了解更多信息,请查看 你不能错过的键盘快捷键, productivity guide and the keypromoter plugin.
  • Use Instant run. Instant Run, 在Android Studio 2中引入, 显著减少应用更新之间的时间间隔, 因为它将后续更新推送到您的应用程序而无需构建新的APK, 所以变化可以更快地显现出来.
  • 使用多窗口特性. 如果使用多个显示器并将IDE UI的不同部分放在不同的显示器上,则可以节省在面板之间切换的时间.

Contributors

Dmitry Ryazantsev

Freelance Android Developer

Montenegro

Dmitry是一名有六年多经验的Android开发人员,他善于沟通,总是试图找到最适合项目的技术. 他在Git、Lua (Corona SDK)、RxJava、Dagger等方面经验丰富. 他与一个大型团队合作开发了Yandex浏览器,安装量超过1000万. 他还开发了自己的项目:一款250人的游戏,000个安装,并发布了其他几个应用程序.

Show More

如何在活动和服务之间传递数据

在几乎所有Android应用中, activity(一组允许用户与应用交互的UI元素)和Services(一个操作系统管理的后台线程)在它们之间传递数据. 开发人员的任务是决定使用哪种方法来完成这项任务.

当学习Android SDK的方法, Google建议将数据从一个Activity或Service发送到另一个Activity或Service的正确方式是使用Intent Extras, 它允许您轻松地传递和检索原始数据类型. The putExtra and getExtra方法及其变体都是单行调用,便于传递简单数据. 但是,当您需要发送复杂对象时,就会出现问题.

通过Intent传递一个对象, it needs to be Parcelable, Bundle, or Serializable, 对于初学者来说,这不是一个简单的过程, 即使是经验丰富的开发者也不喜欢它们.

这时,单身人士就来帮忙了.

Singletons are, as the name suggests, 被设计为仅生成单个对象实例的类, 哪一个允许多个对象访问相同的数据, 无论何时或如何访问单例. In Android, 一个常见的做法是在项目的Application类中创建并放置一个Singleton. 这样做可以通过对Activity或Service的简单调用创建一个应用范围内可访问的单例 getApplication() function.

单例方法比必须为Intent传输配置一个类更简单,并且使数据更容易访问. 值得注意的是,singleton并不局限于Android, 这个选项被Java开发人员广泛使用.

然而,还有另外一种传递数据的方式,尽管存在偏差. 谷歌鼓励使用Intent Extras. 它们提供了一种有组织的方式来设置和获取数据,因为单例遵循面向对象的编程方法. 唯一的问题是,他们需要一些准备才能开始.

我更喜欢的第三种方法很简单. 我创建了一个名为 AppData and only create public static 我希望在多个活动和服务中使用的变量. 这种方法的美妙之处在于它是 not 仅限于活动和服务. Intent extra和singleton需要的访问方法只在这两个Android类中可用. The AppData 但是,任何Java类都可以通过调用 AppData.variableName.

Still, there is an issue with the AppData class approach; it breaks the laws of object-oriented programming. There is a reason Singletons are the preferred approach to passing data in a project; Singletons are classes that can be instantiated as objects. 因为它们是OOP兼容的, 它们可以作为接口的实现传递,甚至可以作为其他类的扩展传递. However, 使用AppData类方法,你可以直接访问属性, no code for instantiation, no code for prep, no code for management; the AppData 类允许您简单地访问应用程序范围内的数据.

这里的经验法则是只将AppData与项目中广泛使用的变量一起使用, 例如在活动和web请求类中调用的API令牌.

Contributors

Faye-Lino Agli

Freelance Android Developer

Canada

Faye-Lino是一位以结果为导向的IT专业人士,在实施技术以推动业务绩效方面有着良好的记录, productivity, and creativity. 他精通英语和法语. 他有丰富的经验,可以接受客户的想法,制作一个完整的项目,并将其完成. 他善于沟通,既能在团队中工作,也能单独工作.

Show More

如何知道你的应用程序是在后台还是前台

Android的Activity生命周期回调为你提供了关于Activity状态的充足信息. 但是应用程序本身呢? Aren’t there onAppResume or onAppPaused functions? 当你的应用程序在后台运行时,Android是如何告诉你的?

Android does not 提供一种方法来清楚地告诉你,如果你的应用程序不再在前台(即, 你的一个活动对用户是可见的).

So, what is the workaround? Surprisingly, there are several; it’s a hot topic for Android. 我已经用这个很多年了,它对我很有效. 它包括两个简单的步骤:

First, 创建一个自定义基Activity类,您将使用它来覆盖项目中的所有活动. 其次,在该基本活动中,创建一个公共静态布尔标志(类似于 isAppInBackground). Next, override the onResume and onPause 函数并简单地适当更新标志: onResume → isAppInBackground = false; onPause → isAppInBackground = true;

现在,您可以在项目的任何地方进行检查 BaseActivity.isAppInBackground 检查应用程序的状态.

Contributors

Faye-Lino Agli

Freelance Android Developer

Canada

Faye-Lino是一位以结果为导向的IT专业人士,在实施技术以推动业务绩效方面有着良好的记录, productivity, and creativity. 他精通英语和法语. 他有丰富的经验,可以接受客户的想法,制作一个完整的项目,并将其完成. 他善于沟通,既能在团队中工作,也能单独工作.

Show More

Submit a tip

提交的问题和答案将被审查和编辑, 并可能会或可能不会选择张贴, 由Toptal全权决定, LLC.

* All fields are required

Toptal Connects the Top 3% 世界各地的自由职业人才.

Join the Toptal community.