JasonWang's Blog

Glide详解之图片加载过程分析

在之前的一篇文章(Glide架构分析 )中介绍了Glide的具体原理。这篇文章,用一个下载图片的示例来说明Glide加载图片的整个过程。以下是用Glide从网络上加载一个图片的代码片段:

1
2
3
4
5
6
7
8
9
    
Glide
.with(activity) // Activity
.load(url)
.centerCrop()
.placeholder(R.drawable.loading_spinner)
.crossFade()
.into(myImageView);

大致说来,在Glide中图片的加载有如下几个过程:

  • 产生一个图片加载的请求GenericRequest<T>;
  • 将图片加载请求发送给资源引擎中心Engine,由其负责资源的加载以及数据解码任务的管理;
  • EngineRunnable首先尝试从DISK加载资源,完成后进行回调,将数据加载到ImageView中;
  • 磁盘中没有请求对应的资源,则尝试从网络端下载,并解码完成后回调,将数据加载到Target对象;

现在就来详细的看下Glide加载图片的整个过程。

Java并发编程之Java Memory Model

在之前一篇文章里,讲到了利用synchronized关键字来进行同步,从而避免多线程并发执行时可能出现的竞争条件,那么JVM又是如何实现线程之间的通信的?换句话说,线程A写共享数据的结果怎么确保被其他线程可见,使得线程之间共享的数据对每个线程而言都是一致的?Java从5.0开始定义了一个新的Memory Model(Java Specification Request 133, JSR133),在多线程情况下,为Java程序提供了一个最少程度的保证:正确同步的情况下,一个线程写共享变量对于其他线程是可见的。Java Memory Model(JMM)抽象了不同计算机平台底层内存读写细节(Register; Cache; Main Memory),为程序员提供了一个访问内存的统一的模型与视角,从而确保在不同平台上程序能有同样的结果,实现Java“编写一次,可以在任何平台上执行”的目标。

Zygote进程启动过程详解

与Java程序类似,Android应用程序框架层(Application Framework)以及APP运行在一个Dalvik Virtual Machine之上,那么,Android启动时框架层是如何初始化的,从何处初始化的?为此,Android在启动时会首先初始化一个专门的系统进程zygote来负责启动与初始化Java代码,比如系统服务进程system_server的启动,系统启动时各种Java服务的初始化,APP资源文件的加载,APP进程的创建与启动。这篇文章,主要讲zygote进程的两个问题:

  • zygote进程如何初始化的;
  • APP进程是如何通过zygote创建的?
Java并发编程综述

在计算机诞生初期,由于其高昂的计算成本,只能允许一个用户运行一个任务或者一批任务(Batch processing)。随着技术的发展,人们开始思考一个问题,如何在计算机上实现多个任务“同时”运行?一开始,采用的是分时策略(Time sharing),就是允许多个用户共享一台计算机,但每个用户占用计算机的一个时间片,在这个时间后,由另一个用户接着运行使用。分时系统在一定程度上提高了计算效率,实现了资源的共享。但其实际上并没有真正实现任务的“同时”(并发,concurrency)运行。

现代并发编程(Concurrent Pragramming)概念的出现一方面是受到操作系统中如进程、中断以及抢占的影响;一方面由于计算机硬件技术的发展而出现的多核处理器。

  • 进程,是程序执行的一个实体,是操作系统对CPU,寄存器,堆栈,内存,文件系统等计算资源的一种执行时的抽象;有了进程,计算机就可以通过调度系统来实现多个任务“同时”运行了,这里所谓的“同时”并不是多个程序真的在一个CPU中同时运行,而是说调度程序快速的在多个进程之间切换,交替执行不同程序,从而更有效的利用了计算机资源;
  • 多核CPU的出现,为并发、并行计算提供了另一种可能。以前程序只能在一个CPU上运行,现在单个程序可以同时在多个CPU上同时运行了(Parallel Computing);或者多个进程同时在多个CPU上运行。
Glide详解之架构分析

Glide是BumpTech开发的一个同时可支持图片、GIF以及视频加载的Android开源库,同时Glide支持任何用户自定义的网络栈,其主要有以下几个特点:

  • 支持GIF格式动画的解码;
  • 支持本地视频加载解码;
  • 加载大图之前,可预先加载一个小图片
  • 自动管理资源加载请求的生命周期;
  • 给定图片尺寸,可以对资源进行自由转换

Github:https://github.com/bumptech/glide

这里就来分析下Glide的具体架构以及介绍其主要特点,分如下几个方面:

  • Glide代码架构及工作原理;
  • Glide如何自动管理资源加载请求的生命周期的?
  • Glide是如何进行图片的加载与转换的?
Java并发编程之同步

在单一线程执行的情况下,并不用考虑任何数据一致性与同步等问题,但到了多个线程执行的情况下,共享数据的同步就显得至关重要了。比如有一个银行账户的操作问题(例子来自Wikipedia),现在有两个线程A与B共享一个账户变量balance,这个提款的操作有两个部分,首先需要判定提款数目是否小于当前账户存款,记为s1;如果该条件满足,则从账户中提取资金,记为s2。假定开始时账户balance=600,现在A调用withdraw(200),B调用withdraw(500),如果两个线程A与B调用时,s1都发生在s2之前,则两个线程都可以进入判定条件,提取相应的资金,而实际的存款是小于两个线程需要提取的资金的。

1
2
3
4
5
6
7
8
9
10
11
12
13

bool withdraw(int withdrawal)
{

if (balance >= withdrawal) // --> s1
{

balance -= withdrawal; // --> s2
return true;
}
return false;
}

这种线程之间共享资源的一致性同步问题在并发编程中十分常见,通常被称为Data Race。根据官网上的定义(what is data race),Data Race出现是由以下原因导致:

  • 多个线程同时访问共享内存;
  • 至少有一个线程写该共享内存区域;
  • 线程访问共享内存并没有利用锁进行同步;
Java并发编程之线程

线程作为操作系统的最小调度单位。一个进程里可以有多个线程,这些线程有各自的程序计数器、堆栈空间和局部变量,而且可以共享进程的内存空间,因而在上下文切换时时间更短,效率更高,也常被成为轻量级进程(Light Weight Process)。接下来,将从三个方面来介绍Java线程类Thread的具体用法:

  • 线程构造与初始化;
  • 线程状态切换;
  • 线程变量ThreadLocal的使用

Thread: https://en.wikipedia.org/wiki/Thread_(computing)

单例模式在Java中的应用

单例模式(Singleton Pattern)用于确保系统中某个类只有一个实例存在,即该类被创建初始化一次后,之后都不会再被创建。这里就来看下单例模式在Java中常见的几种实现方式:

  • 双重检查锁
  • 类初始化
  • enum类型实现
Picasso从使用到原理详解

Picasso是SquareUp公司开源的专门为Android平台量身制作的图片加载库。通过Picasso,用户可以方便的将图片加载到特定的ImageView中,而不用关心图片是在一个文件夹里,还是在一个服务器上。那么,Picasso是如何何实现图片的快速加载了?

  • 利用两级缓存机制对图片进行缓存: 加载一个图片时,首先从内存中查看是否存在;如果不存在,则查看外部存储是否有该图片。这时,如果还没有找到,则通过网络端下载图片;
  • 利用OkHttp库进行图片下载,下载后保存到缓存,下次请求时无需从网络端下载;如果出现网络错误,会自动重试下载;