Johnny Shieh

人如果没有梦想,跟咸鱼有什么分别


  • 首页

  • 分类

  • 归档

  • 标签

  • 读书

  • 小伙伴

  • 关于

  • 搜索

Java 设计模式之单例模式

发表于 2016-10-13 | 分类于 设计模式 | | 阅读次数

单例模式应该是大家最熟悉的设计模式,但是单例模式有好几种实现方式,下面就分析各种实现方式的优缺点。

概念

单例模式,即单例类只能有一个实例,并且对外提供一个全局访问入口。

下面依次介绍几种实现方式,关键在于如何创建唯一的实例。

饿汉式

饿汉式,是指类装载时就已经创建了实例,也是最简单的实现方式。

1
2
3
4
5
6
7
public class Singleton {
private static final Singleton sInstance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return sInstance;
}
}

饿汉式的实现方式,因其在类装载的时候就创建了实例,所以天生就是线程安全的。但是还有两个问题:1)如果构造方法中有耗时操作的话,会导致这个类的加载比较慢 2)饿汉式一开始就创建实例,但是并没有调用,会造成资源浪费。

阅读全文 »

探索注解之 Android 中的注解

发表于 2016-09-21 | 分类于 Android | | 阅读次数

Java 中有注解,Android 中也有注解,本文将介绍下 Android 的注解。这是探索注解系列文章的最后一篇:

  • 探索注解之注解的基本概念

  • 探索注解之 APT 编译时处理注解, 解析 Butterknife 注解原理 (鸿神写编译时注解的文章,非常好,所以自己就不再重复写了)

  • 探索注解之 Android 中的注解

引入注解库

Android 的注解库并没有包括在 framework 中,它被独立成一个单独的库。通常情况下,只需要编辑build.gradle文件就可引入:

1
2
3
dependencies {
compile 'com.android.support:support-annotations:22.2.0'
}

如果已经引入了appcompat库的话,就不需要额外引入support-annotations,因为appcompat包含了注解库。

对于 Android 应用或者 Android Library 模块的话,上面的工作就可以引入注解库。如果想要在纯粹的 Java 模块中(即在 gradle 文件中apply plugin: 'java')引入注解库的话,还要显式地标明 SDK 的 repositories,因为注解库不在 jcenter 上(Android 的 gradle plugin 默认包含这个依赖,而 Java plugin 并没有)。

1
2
3
4
repositories {
jcenter()
maven {url '<your-SDK-path>/extras/android/m2repository'}
}
阅读全文 »

探索注解之注解的基本概念

发表于 2016-09-07 | 分类于 Java | | 阅读次数

自从 Java 5.0 版本引入注解后,它就成为 Java 平台中非常重要的一部分。在日常开发过程中时常可以看到 @Override,@Deprecated 这样的注解,在使用 Butterknife 减少 findViewById 这样的重复劳动时也经常用到 @BindView 注解。下面几篇文章将讲述注解的基本概念,注解处理器的使用以及 Android中 的注解:

  • 探索注解之注解的基本概念

  • 探索注解之 APT 编译时处理注解 (鸿神写编译时注解的文章,非常好,所以自己就不再重复写了)

  • 探索注解之 Android 中的注解

什么是注解?

注解(Annotations),就是元数据,一种描述程序代码的数据,并且对程序运行没有任何影响。

例如下面这段代码:

1
2
3
4
@Override
public String toString() {
return "This is String Representation of current object";
}

在上面的代码中,我重写了 toString() 方法并使用了 @Override 注解。但是即便我不使用 @Override 注解标记代码,程序也能正常运行。那么这个注解有什么意义?@Override 告诉编译器这个方法是重写父类的方法,如果父类中没有该方法,编译器就会报错,提示没有重写父类中的方法。如果我不小心把 toString 写成 toStrings,而且也没有使用 @Override 注解的话,程序依然可以运行,但是跟之前期望就会大有不同。

注解有下面几种作用:

  • 为编译器提供信息 – 注解可以被编译器用来检测错误或抑制警告
  • 编译时和部署时处理 – 一些工具可以根据注解信息生成代码,XML 文件等等,例如 APT(Annotation Processing Tool)
  • 运行时处理 – 有些注解可以在运行时通过反射获取

在引入注解之前,开发人员通常使用标记 interfaces,注释或者 javadoc 定义元数据,没有统一的一种方式。注解定义了一种标准的描述元数据的方式,注解是一种应用于类、方法、参数、变量、构造器及包声明中的特殊修饰符。它是一种由 JSR-175 标准选择用来描述元数据的一种工具。

阅读全文 »

Android 开发过程中的坑和小技巧

发表于 2016-06-12 | 分类于 Android | | 阅读次数

空指针问题

NullPointerException 绝对是开发人员遇到最多的问题,也是 Android 开发过程中一个大坑,总是在你意料不到的时候出现。要解决这个问题,关键地方不要吝啬 if 语句,需要在用到某一对象的时候多想想有没什么可能会导致对象没有初始化或者被指向为null,下面是一些比较有代表性的例子:

  • Fragment的Handler 中调用 getActivity(),需要判空和判断 activity 是否销毁
1
2
3
4
5
6
7
8
9
10
private static class MyHandler extends Handler {
...
@Override
public void handleMessage(Message msg) {
// 需要判空
if(null != mFragment.getActivity() && !mFragment.getActivity().isDestroyed()) {
// TODO
}
}
}
  • 使用 Cursor 时没有判空,没有在 finally 代码块中关闭
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Cursor cursor = null;
try {
cursor = contentResolver.query(uri, null, selection, selectionArgs, null);
// cursor可能为空
if(null != cursor && cursor.moveToFirst()) {
// TODO
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != cursor) {
cursor.close();
}
}
阅读全文 »

一步一步扩展 Volley (二),缓存生存时间 TTL

发表于 2016-02-23 | 分类于 Android | | 阅读次数

之前根据 Volley 的工作流程大致解析了它的框架,接下来继续分析 Volley 的缓存机制,下面我在解析其缓存机制的同时也讲述一下个人对缓存生存时间的扩展.

缓存调度器的处理流程

要明白 Volley 的缓存机制,关键在于分析缓存调度器处理请求的过程,下面是我画的流程图:

这张流程图主要对应 CacheDispatcher 的 run 方法,首先根据 cachekey 查找缓存,如果没有缓存就把请求放到网络等待队列中,缓存调度器继续处理下一个请求;如果有缓存,但是缓存已经过期了,也将请求放到网络等待队列中并处理下一个请求,如果缓存没有过期,继续判断缓存是否需要刷新;如果不需要更新缓存,则直接传递解析后的缓存数据到主线程,如果需要更新缓存,则在传递解析后的缓存数据到主线程之后还会把请求添加到网络等待队列。

下面再看下流程中的两个关键的方法的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* Data and metadata for an entry returned by the cache.
*/
public static class Entry {
/** The data returned from cache. */
public byte[] data;
/** ETag for cache coherency. */
public String etag;
/** Date of this response as reported by the server. */
public long serverDate;
/** The last modified date for the requested object. */
public long lastModified;
/** TTL for this record. */
public long ttl;
/** Soft TTL for this record. */
public long softTtl;
/** Immutable response headers as received from server; must be non-null. */
public Map<String, String> responseHeaders = Collections.emptyMap();
/** True if the entry is expired. */
public boolean isExpired() {
return this.ttl < System.currentTimeMillis();
}
/** True if a refresh is needed from the original data source. */
public boolean refreshNeeded() {
return this.softTtl < System.currentTimeMillis();
}
}

从上面的代码中可以看出 ttl 就是缓存的生存时间,如果当前时间大于这个时间,缓存就过期,需要重新从网络请求数据。而 softTtl 代表软生存时间,过了这个时间缓存没有完全过期,可以返回给主线程,但是需要从网络请求新的数据刷新缓存.

阅读全文 »
1…101112…16
Johnny Shieh

Johnny Shieh

我本微末,心向天空

76 日志
13 分类
43 标签
GitHub Weibo Gmail 简书
  • 热门系列
  • Dagger 完全解析(6)
  • AspectJ in Android(3)
  • Kotlin 写 Android 单元测试(4)
  • Kotlin 协程完全解析(5)
© 2015 - 2019 Johnny Shieh
访客数 访问量