0%

LayoutInflater,布局填充器,把XML布局文件实例化为相应的View。Android开发者对LayoutInflater都已经很熟悉了。但是究竟它是如何做到的呢?让我们来简单探究一下主要流程。

LayoutInflater实例

先看一下LayoutInflater实例的创建

1
LayoutInflater inflater = LayoutInflater.from(context);

或者

1
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

其实这两种写法效果完全一样,只不过Android给我们简单封装一下。LayoutInflater.from()的源码如下:

1
2
3
4
5
6
7
8
9
10
11
/**
* Obtains the LayoutInflater from the given context.
*/
public static LayoutInflater from(Context context) {
LayoutInflater LayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
throw new AssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}

Read more »

使用Ubuntu(最近换了deepin,本地化做的很好)+Android studio开发Android一年多了,看源码的时候,一直怀念Windows下的source insight。后来发现原来Android提供了eclipse和idea等工具进行阅读的方法。
只需要执行如下命令:

1
./development/tools/idegen/idegen.sh

这行命令的意思是在根目录生成对应的android.ipr、android.iml的工程配置文件。

可能会出现如下错误

解决办法是,下载idegen.jar复制到指定目录。重新执行命令即可。成功结果如下:

在android studio选择打开android.ipr,稍等一会就可查看源码了。

大功告成!看下效果

上篇Retrofit初探中已初步使用了Retrofit,简单介绍了Retrofit的使用步骤。本篇继续深入分析一下Retrofit流程。

Retrofit创建

先看一下Retrofit的创建

1
2
3
4
5
6
7
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL)
//手动指定Fastjson解析方式,可指定不同Convert来使用如Gson,Jackson,XML等解析方式
.addConverterFactory(FastjsonConverterFactory.create())
//返回数据为RxJava形式
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();

可以看出Retrofit对象是通过Builder来创建,构建器很方便我们设置Retrofit需要的属性。通过build()方法就创建了一个Retrofit对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public Retrofit build() {
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}

Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}

// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}

如果我们没有指定一个client或者callFactory,Retrofit2中默认生成一个OkHttpClient。然后通过platform.defaultCallbackExecutor()实例化一个Executor的对象callbackExecutor。Converter是数据转换器,该接口将Http请求返回的数据解析成Java对象,
addConverterFactory(FastjsonConverterFactory.create())添加一个FastjsonConverter来使用Fastjson来将我们的结果转化成Model类。CallAdapter是Call的适配器,负责将Call对象转化成另一个对象,同样在创建Retrofit实例时调用addCallAdapterFactory(Factory)来添加。
这样一个Retrofit的实例就创建完成了。其中platform是Builder进行初始化的时候调用了Platform.get()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}

private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
//...省略部分代码...
return new Platform();
}

使用了单例的PLATFORM,通过findPlatform()初始化实例,如果是Android平台就实例化一个Android对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 static class Android extends Platform {
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}

@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}

static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r); //提交到主线程,起到切换线程的作用
}
}
}

在Android平台中defaultCallbackExecutor()方法返回的是一个线程池,在execute()中执行绑定MainLooper的Handler提交Runnable到主线程。

Retrofit请求的创建

在Volley中描述一个HTTP请求是需要创建一个Request对象,然后把这个请求对象放到一个队列中,让网络线程去处理。那Retrofit是怎么做的呢?

1
2
3
4
5
6
7
interface Api {
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> repoContributors(
@Path("owner") String owner,
@Path("repo") String repo);
}
Api api = retrofit.create(Api.class);

声明一个Api的接口,给Retrofit对象传了一个Api接口的Class对象,怎么又返回一个Api对象呢?进入create方法看一下:
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
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();

@Override public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//对java8的兼容
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}

create(final Class service)方法使用了 动态代理 来生成接口实现类。通过该函数,我们可以拿到一个前面自定义的Api的一个代理类,其功能就相当于一个Api对象,
即我们可以通它调用Api里的各个成员函数。其中最重要的三行代码为:

1
2
3
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
Read more »

Retrofit简介

Retrofit是一个类型安全的REST网络请求库(A type-safe HTTP client for Android and Java)。作者是大名鼎鼎的Square,已开源到github。这个库为网络认证、API请求以及用OkHttp发送网络请求提供了强大的框架 。Retrofit直接支持RxJava,使得这个库被更多人去尝试。

使用

添加依赖

首先下载jar或者添加Gradle:

1
compile 'com.squareup.retrofit2:retrofit:2.0.2'

初始化 - Retrofit 类型
Read more »

Stetho简介

Stetho 是 Facebook 开源的一个 Android 调试工具。是一个 Chrome Developer Tools 的扩展,可用来检测应用的网络、数据库、WebKit 等方面的功能。开发者也可通过它的 dumpapp 工具提供强大的命令行接口来访问应用内部。无需root查看sqlite文件、sharedpreference文件等等。更多详细介绍可以进入Stetho官网

Stetho结合OkHttp使用

1.添加依赖
1
2
3
4
// Gradle dependency on Stetho 
dependencies {
compile 'com.facebook.stetho:stetho:1.1.1'
}
2.Stetho初始化配置
Read more »

概述

  上篇文章Android高效加载大图、多图解决方案是翻译自Android Doc的,其中防止多图OOM的核心解决思路就是使用LruCache技术。但LruCache只是管理了内存中图片的存储与释放,如果图片从内存中被移除的话,那么又需要从网络上重新加载一次图片,这显然非常耗时。对此,Google又提供了一套硬盘缓存的解决方案:DiskLruCache(非Google官方编写,但获得官方认证)。只可惜,Android Doc中并没有对DiskLruCache的用法给出详细的说明,而网上关于DiskLruCache的资料也少之又少,因此今天我准备专门写一篇博客来详细讲解DiskLruCache的用法,以及分析它的工作原理,这应该也是目前网上关于DiskLruCache最详细的资料了。。

  那么我们先来看一下有哪些应用程序已经使用了DiskLruCache技术。在我所接触的应用范围里,Dropbox、Twitter、网易新闻等都是使用DiskLruCache来进行硬盘缓存的,其中Dropbox和Twitter大多数人应该都没用过,那么我们就从大家最熟悉的网易新闻开始着手分析,来对DiskLruCache有一个最初的认识吧。

初探

  相信所有人都知道,网易新闻中的数据都是从网络上获取的,包括了很多的新闻内容和新闻图片,如下图所示:

  但是不知道大家有没有发现,这些内容和图片在从网络上获取到之后都会存入到本地缓存中,因此即使手机在没有网络的情况下依然能够加载出以前浏览过的新闻。而使用的缓存技术不用多说,自然是DiskLruCache了,那么首先第一个问题,这些数据都被缓存在了手机的什么位置呢?

Read more »

本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工,英文好的朋友也可以直接去读原文。

http://developer.android.com/training/displaying-bitmaps/index.html

高效加载大图片

  我们在编写Android程序的时候经常要用到许多图片,不同图片总是会有不同的形状、不同的大小,但在大多数情况下,这些图片都会大于我们程序所需要的大小。比如说系统图片库里展示的图片大都是用手机摄像头拍出来的,这些图片的分辨率会比我们手机屏幕的分辨率高得多。大家应该知道,我们编写的应用程序都是有一定内存限制的,程序占用了过高的内存就容易出现OOM(OutOfMemory)异常。我们可以通过下面的代码看出每个应用程序最高可用内存是多少。

1
2
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
Log.d("TAG", "Max memory is " + maxMemory + "KB");

  因此在展示高分辨率图片的时候,最好先将图片进行压缩。压缩后的图片大小应该和用来展示它的控件大小相近,在一个很小的ImageView上显示一张超大的图片不会带来任何视觉上的好处,但却会占用我们相当多宝贵的内存,而且在性能上还可能会带来负面影响。下面我们就来看一看,如何对一张大图片进行适当的压缩,让它能够以最佳大小显示的同时,还能防止OOM的出现。
  BitmapFactory这个类提供了多个解析方法(decodeByteArray, decodeFile, decodeResource等)用于创建Bitmap对象,我们应该根据图片的来源选择合适的方法。比如SD卡中的图片可以使用decodeFile方法,网络上的图片可以使用decodeStream方法,资源文件中的图片可以使用decodeResource方法。这些方法会尝试为已经构建的bitmap分配内存,这时就会很容易导致OOM出现。为此每一种解析方法都提供了一个可选的BitmapFactory.Options参数,将这个参数的inJustDecodeBounds属性设置为true就可以让解析方法禁止为bitmap分配内存,返回值也不再是一个Bitmap对象,而是null。虽然Bitmap是null了,但是BitmapFactory.Options的outWidth、outHeight和outMimeType属性都会被赋值。这个技巧让我们可以在加载图片之前就获取到图片的长宽值和MIME类型,从而根据情况对图片进行压缩。如下代码所示:

Read more »

设置build.gradle文件:

在配置的android节点下加入下面的内容:

1
2
3
4
5
sourceSets {  
main {
jniLibs.srcDirs = ['libs']
}
}

或者在源码main子目录下建jniLibs目录,把libs下的so库按目录结构丢进去,如下图:

Eclipse中快捷键与Studio中的差别还是比较大,通过对比两者,让记忆更深刻。

常用快捷键

显示快捷键列表:Ctrl+Shift+L (Eclipse)

功能 Eclipse Android studio
打开资源 Ctrl+Shift+R Ctrl+Shift+N
打开类型 Ctrl+Shift+T Ctrl+N
导入包 Ctrl+Shift+M Alt+回车
当前文件的结构 Ctrl+O Ctrl+F12
格式化代码 Ctrl+Shift+F Ctrl+Alt+L
组织导入 Ctrl+Shift+O Ctrl+Alt+O
当前行往上或下移动 Alt+方向键 Ctrl+Shift+方向
生成getter setter方法 Alt+Shift+s Alt+Insert
重命名 Alt+Shift+R Shift+F6
自动补全代码 Alt+/ Ctrl+Shift+Space(会与输入法切换有冲突)
Ctrl+空格 代码提示
Ctrl+Alt+Space 类名或接口提示
Ctrl+P 方法参数提示
行操作 Ctrl+D 删除行 Ctrl+X 删除行
Ctrl+D 复制行
定位在某行 Ctrl+L
返回上次位置 Alt+ left/right Ctrl+Alt+ left/right
注释 Ctrl+/ Ctrl+/ 或 Ctrl+Shift+/

调试

功能 Eclipse Android studio
运行程序 Ctrl+F11 Shift+F10运行当前,Alt+Shift+F10选择运行程序
单步跳入 F5 F7
单步执行 F6 F8
单步返回 F7 Shift+F8
继续 F8 F9
查看变量 Shift+Ctrl+I Alt+F10
计算 Alt+F8
Read more »