0%

场景问题

发送消息

现在我们要实现这样一个功能:发送消息。从业务上看,消息又分成普通消息、加急消息和特急消息多种,不同的消息类型,业务功能处理是不一样的,比如加急消息是在消息上添加“加急”字样,而特急消息除了添加特急外,还会做一条催促的记录,多久不完成会继续催促。从发送消息的手段上看,又有系统内短消息、手机短消息、邮件等等。现在要实现这样的发送提示消息的功能,该如何实现呢?

阅读全文 »

概述

我们执行一个功能的函数时,经常需要在其中写入与功能不是直接相关但很有必要的代码,如日志记录、信息发送、安全和事务支持等,这些枝节性代码虽然是必要的,但它会带来以下麻烦:

  • 枝节性代码游离在功能性代码之外,它下是函数的目的
  • 枝节性代码会造成功能性代码对其它类的依赖,加深类之间的耦合
  • 枝节性代码带来的耦合度会造成功能性代码移植困难,可重用性降低

毫无疑问,枝节性代码和功能性代码需要分开来才能降低耦合程度,我们可以使用代理模式(委托模式)完成这个要求。代理模式的作用是:为其它对象提供一种代理以控制对这个对象的访问。在某些情况下,一 个客户不想直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介作用。

代理模式一般涉及到三个角色:

  • 抽象角色:声明真实对象和代理对象的共同接口
  • 代理角色:代理对象内部包含有真实角色的引用,从而可以操作真实角色,同时代理对象 与真实对象有相同的接口,能在任何时候代替真实对象,代理对象可以在执行真实对 象前后加入特定的逻辑以实现功能的扩展。
  • 真实角色:代理角色所代表的真实对象,是我们最终要引用的对象

常见的代理应用场景有:

  • 远程代理:对一个位于不同的地址空间对象提供一个局域代表对象,如RMI中的stub
  • 虚拟代理:根据需要将一个资源消耗很大或者比较复杂的对象,延迟加载,在真正需要的时候才创建
  • 保护代理:控制对一个对象的访问权限
  • 智能引用:提供比目标对象额外的服务和功能

接下来,我们用代码来说明什么是代理模式

阅读全文 »

概述

在开发过程中,为了实现解耦,我们经常使用依赖注入,常见的依赖注入方式有:

  • 构造方法注入:在构造方法中把依赖作为参数传递进去
  • setter方法注入:添加setter方法,把依赖传递进去
  • 接口注入:把注入方法抽到一个接口中,然后实现该接口,把依赖传递进去

下面用一个小栗子来说明三种方式的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class PersonService implements DependencyInjecter {

private PersonDao personDao;

// 构造方法注入
public PersonService(PersonDao personDao) {
this.personDao = personDao;
}

// setter方法注入
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}

// 接口注入:实现DependencyInjecter接口
@Override
public void injectPersonDao(PersonDao personDao) {
this.personDao = personDao;
}

... ...
}
阅读全文 »

概述

Android的单元测试可以分为两部分:

  1. Local unit tests:运行于本地JVM
  2. Instrumented test:运行于真机或者模拟器

如果使用Local测试,需要保证测试过程中不会调用Android系统API,否则会抛出RuntimeException异常,因为Local测试是直接跑在本机JVM的,而之所以我们能使用Android系统API,是因为编译的时候,我们依赖了一个名为“android.jar”的jar包,但是jar包里所有方法都是直接抛出了一个RuntimeException,是没有任何任何实现的,这只是Android为了我们能通过编译提供的一个Stub!当APP运行在真实的Android系统的时候,由于类加载机制,会加载位于framework的具有真正实现的类。由于我们的Local是直接在PC上运行的,所以调用这些系统API便会出错。
那么问题来了,我们既要使用Local测试,但测试过程又难免遇到调用系统API那怎么办?其中一个方法就是mock objects,比如借助Mockito,另外一种方式就是使用Robolectric, Robolectric就是为解决这个问题而生的。它实现一套JVM能运行的Android代码,然后在unit test运行的时候去截取android相关的代码调用,然后转到他们的他们实现的Shadow代码去执行这个调用的过程

阅读全文 »

概述

我们知道,OOP三个基本特征是:封装、继承、多态。通过继承,我们可以基于差异编程,也就是说,对于一个满足我们大部分需求的类,可以创建它的一个子类并只改变我们不期望的那部分。但是在实际使用中,继承很容易被过度使用,并且过度使用的代价是比较高的,所以我们减少了继承的使用,使用组合或委托代替

优先使用对象组合而不是类继承

在本文中,我们会分别介绍模板方法模式策略模式,这两个模式分别使用了继承和委托两种方式。这两种模式解决的问题是类似的,经常可以互换使用,它们都可以分离通用的算法和具体的上下文。比如我们有一个通用的算法,算法有不同的实现方式,为了遵循依赖倒置原则,我们希望算法不依赖于具体实现。

阅读全文 »

概述

根据依赖倒置原则,我们知道,我们应优先依赖抽象类而不是具体类。在应用开发过程中,有很多实体类都是非常易变的,依赖它们会带来问题,所以我们更应该依赖于抽象接口,已使我们免受大多数变化的影响。
工厂模式(Factory)允许我们只依赖于抽象接口就能创建出具体对象的实例,所以在开发中,如果具体类是高度易变的,那么该模式就非常有用。

接下来我们就通过代码举例说明什么是工厂模式

阅读全文 »

概述

Fragment表示 Activity 中的行为或用户界面部分。您可以将多个 Fragment 组合在一个 Activity 中来构建多窗格 UI,以及在多个 Activity 中重复使用某个 Fragment。您可以将 Fragment 视为 Activity 的模块化组成部分,它具有自己的生命周期,能接收自己的输入事件,并且您可以在 Activity 运行时添加或移除 Fragment。
Fragment 必须始终嵌入在 Activity 中,其生命周期直接受宿主 Activity 生命周期的影响。 例如,当 Activity 暂停时,其中的所有 Fragment 也会暂停;当 Activity 被销毁时,所有 Fragment 也会被销毁。 不过,当 Activity 正在运行(处于已恢复生命周期状态)时,您可以独立操纵每个 Fragment,如添加或移除它们。 当您执行此类 Fragment 事务时,您也可以将其添加到由 Activity 管理的返回栈 — Activity 中的每个返回栈条目都是一条已发生 Fragment 事务的记录。 返回栈让用户可以通过按返回按钮撤消 Fragment 事务(后退)。

当您将 Fragment 作为 Activity 布局的一部分添加时,它存在于 Activity 视图层次结构的某个 ViewGroup 内部,并且 Fragment 会定义其自己的视图布局。您可以通过在 Activity 的布局文件中声明Fragment,将其作为 <fragment> 元素插入您的 Activity 布局中,或者通过将其添加到某个现有 ViewGroup,利用应用代码进行插入。不过,Fragment 并非必须成为 Activity 布局的一部分;您还可以将没有自己 UI 的 Fragment 用作 Activity 的不可见工作线程。

本文将通过分析源码,对 Fragment 的创建、销毁以及生命周期做一个更深入的认识。

建议读者在看这篇文章的时候,先看下Fragment事务管理源码分析,对Fragment管理类先有一个比较清楚的认识。

阅读全文 »

概述

在Fragment使用中,有时候需要对Fragment进行addremoveshowhidereplace等操作来进行Fragment的显示隐藏等管理,这些管理是通过FragmentTransaction进行事务管理的。事务管理是对于一系列操作进行管理,一个事务包含一个或多个操作命令,是逻辑管理的工作单元。一个事务开始于第一次执行操作语句,结束于Commit。通俗地将,就是把多个操作缓存起来,等调用commit的时候,统一批处理。下面会对Fragmeng的事务管理做一个代码分析

阅读全文 »

概述

动态代理是java的一大特性,动态代理的优势就是实现无侵入式的代码扩展。它可以增强我们原有的方法,比如常用的日志监控,添加缓存等,也可以实现方法拦截,通过代理方法修改原方法的参数和返回值等。
要了解动态代理,我们需要先看看什么是静态代理

阅读全文 »

概述

Android开发者应该都遇到了64K最大方法数限制的问题,针对这个问题,google也推出了multidex分包机制,在生成apk的时候,把整个应用拆成n个dex包(classes.dex、classes2.dex、classes3.dex),每个dex不超过64k个方法。使用multidex,在5.0以前的系统,应用安装时只安装main dex(包含了应用启动需要的必要class),在应用启动之后,需在Application的attachBaseContext中调用MultiDex.install(base)方法,在这时候才加载第二、第三…个dex文件,从而规避了64k问题。
当然,在attachBaseContext方法中直接install启动second dex会有一些问题,比如install方法是一个同步方法,当在主线程中加载的dex太大的时候,耗时会比较长,可能会触发ANR。不过这是另外一个问题了,解决方法可以参考:Android最大方法数和解决方案 http://blog.csdn.net/shensky711/article/details/52329035。

本文主要分析的是MultiDex.install()到底做了什么,如何把secondary dexes中的类动态加载进来。

阅读全文 »