该包所包含的图片如下
其中ImageDownloader为接口,BaseImageDownloader为ImageDownloaer的实现类。
ImageDownloader(接口)该接口对外提供了一个接口方法:
InputStream getStream(String imageUri,Object extra) throws IOException;
很明显该方法的作用很明显是获取imageUri指定的图片文件的输入流。
由于imageUri所指定的文件源可以来自不同种类的服务器或者地址,所以该接口又定义了一个枚举类Scheme来指定imageUri的来源属于什么种类,其所列举的类型有如下几种:
HTTP("http"), HTTPS("https")
图片来源于http服务器
FILE("file")
imageUri为file协议的字符串
CONTENT("content")
图片文件来源于app的contentprovider
ASSETS("assets")
图片来源于app中的assets文件夹
DRAWABLE("drawable")
图片来源于app的drawable文件夹
UNKNOWN("")
图片来源于其它的途径,在这种情况下,会抛出runtimeexception异常
同时该枚举类还提供了如下几个方法:
ofUri(String uri):此方法根据图片的uri来判断该图片属于以上七个枚举类型的哪一个种。
wrap(String path):此方法用来为path加上uri的前缀,比如http://+path
corp(String uri):与wrap方法相反,去掉uri的前缀
注意:该枚举类的最重要的作用就是根据不同枚举类型来返回图片的不同的图片文件输入流。这个在该接口的实现类BaseImageDownloader会体现出来。
BaseImageDownloader(implements ImageDownLoader)该类的主要作用是根据imageUri来获取图片文件的输入流,提供了如下几个重要属性:
字段名
属性
字段说明
DEFAULT_HTTP_CONNECT_TIMEOUT
final int
网络链接的最大超时时间
DEFAULT_HTTP_READ_TIMEOUT
final int
从主机中读书数据的超时时间
BUFFER_SIZE
final int
缓存的大小,为32k
MAX_REDIRECT_COUNT
final int
链接网络超时的时候重新请求链接的次数
CONTENT_CONTACTS_URI_PREFIX
final int
当图片来自contentprovider的时候用到它
ERROR_UNSUPPORTED_SCHEME
final int
错误信息,当imageUri的scheme属于UNKNOWN的时候,提示错误信息
context
Context
app应用的上下文
connectTimeout
int
让用户设置链接超时时间
readTimeout
int
让用户设计读取超时时间
该类提供了两个构造器:
/**
* 使用该构造器设置的对象,来设置默认最大连接时间
* @param context
*/
public BaseImageDownloader(Context context) {
this.context = context.getApplicationContext();
this.connectTimeout = DEFAULT_HTTP_CONNECT_TIMEOUT;
this.readTimeout = DEFAULT_HTTP_READ_TIMEOUT;
}
/**
* 用户自己设定超时时间
* @param context
* @param connectTimeout
* @param readTimeout
*/
public BaseImageDownloader(Context context, int connectTimeout, int readTimeout) {
this.context = context.getApplicationContext();
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
}
下面看看该类是如何实现接口的getStream方法的,具体代码如下
public InputStream getStream(String imageUri, Object extra) throws IOException {
switch (Scheme.ofUri(imageUri)) {
case HTTP:
case HTTPS:
return getStreamFromNetwork(imageUri, extra);//获取网络输入流
case FILE:
return getStreamFromFile(imageUri, extra);//获取文件输入流
case CONTENT:
return getStreamFromContent(imageUri, extra);//获取应用上下文的图片文件输入流
case ASSETS:
return getStreamFromAssets(imageUri, extra);//获取assets的图片文件输入流
case DRAWABLE:
return getStreamFromDrawable(imageUri, extra);//获取drawable里面的图片文件的输入流
case UNKNOWN:
default:
return getStreamFromOtherSource(imageUri, extra);//获取其他源的图片的输入流
}
}
该类还提供了一个createConnection方法来根据imageUrl来获取一个httpUrlConnection的链接对象
protected HttpURLConnection createConnection(String url, Object extra) throws IOException {
String encodedUrl = Uri.encode(url, ALLOWED_URI_CHARS);
//通过url链接获取一个HttpUrlConnecttion
HttpURLConnection conn = (HttpURLConnection) new URL(encodedUrl).openConnection();
conn.setConnectTimeout(connectTimeout);
conn.setReadTimeout(readTimeout);
return conn;
}
当imageuri的scheme为http,https和file的时候返回的输入流对象是经过装饰(装饰模式的应用)的输入流对象ContentLengthInputStream
下面贴出来getStream方法中所涉及的方法如下:protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {
HttpURLConnection conn = createConnection(imageUri, extra);//根据imagUri来获取一个HttpUrlConnection对象
int redirectCount = 0;
//如果请求不成功,就再次请求直到请求成功并或者重定向的次数超过了最大请求次数
while (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) {
conn = createConnection(conn.getHeaderField("Location"), extra);
redirectCount++;
}
InputStream imageStream;
try {
//获取网络输入流,有了这个对象才能从网络中读取数据
imageStream = conn.getInputStream();
} catch (IOException e) {
// Read all data to allow reuse connection (http://bit.ly/1ad35PY)
IoUtils.readAndCloseStream(conn.getErrorStream());
throw e;
}
//对网络输入流进行进一步封装,这里面应用了装饰模式
return new ContentLengthInputStream(new BufferedInputStream(imageStream, BUFFER_SIZE), conn.getContentLength());
}
protected InputStream getStreamFromFile(String imageUri, Object extra) throws IOException {
String filePath = Scheme.FILE.crop(imageUri);//根据url获取路径
return new ContentLengthInputStream(new BufferedInputStream(new FileInputStream(filePath), BUFFER_SIZE),
(int) new File(filePath).length());
}
protected InputStream getStreamFromContent(String imageUri, Object extra) throws FileNotFoundException {
/*
* ContentProviders存储和检索数据,通过它可以让所有的应用程序访问到,这也是应用程序之间唯一共享数据的方法,则负责获取ContentProvider提供的数据;
*/
ContentResolver res = context.getContentResolver();
Uri uri = Uri.parse(imageUri);
if (imageUri.startsWith(CONTENT_CONTACTS_URI_PREFIX)) {
return ContactsContract.Contacts.openContactPhotoInputStream(res, uri);
} else {
return res.openInputStream(uri);
}
}
protected InputStream getStreamFromAssets(String imageUri, Object extra) throws IOException {
String filePath = Scheme.ASSETS.crop(imageUri);//获取文件的路径
return context.getAssets().open(filePath);//获取文件的输入流
}
protected InputStream getStreamFromDrawable(String imageUri, Object extra) {
String drawableIdString = Scheme.DRAWABLE.crop(imageUri);
int drawableId = Integer.parseInt(drawableIdString);
return context.getResources().openRawResource(drawableId);
}
protected InputStream getStreamFromOtherSource(String imageUri, Object extra) throws IOException {
throw new UnsupportedOperationException(String.format(ERROR_UNSUPPORTED_SCHEME, imageUri));
}