在android中实现下载指定URL的图片并显示
好像很长时间没有写技术文章了,正好最近整理了一下前阵子做的android开发,在这里记录一下。这是一个简单的应用-下载指定URL的图片并显示。
说实在的这个应用没有什么特殊的地方,规模很小,用到的技术也很普通,但不失为一个很好的练手题材。既然是一个android的应用,那么里面多少涉及到了一些android开发的技术点,具体如下:
1. 界面-ImageSwitcher, ImageView, Gallery, Dialog, ProcessBar等等控件
2. 网络访问- HttpClient, HttpEntity, HttpGet, HttpResponse等
3. 图片文件处理- Bitmap, BitmapFactory, ByteArrayOutputStream等
4. Java -如WeakReference等
5. Unit Test - ActivityInstrumentationTestCase2, LargeTest, KeyEvent等
因为没有准备去保存图片文件到外存,所以在例子中不涉及到数据库和磁盘文件读写的内容。下面我们按照软件工程的做法,先进行一下需求分析的。
其实不复杂,稍微思考一下我们就能得到以下的基本需求:
1. 输入URL
2. 下载图片
3. 显示图片
如果要进一步的优化这个应用,我们还需要做以下工作:
4. 良好的交互界面 - 如URL输入方式,错误处理,图片展示等等
5. 性能优化 - 内存使用率,网络延迟等
好了,需求确定下来以后,我们就要进入开发阶段了。实际上按照敏捷的开发方式来做,我们还要进一步的拆分需求。但自己做就不那么教条了^_^。根据TDD实践原则,那么我先来写一些测试。因为使用Eclipse来创建的android项目(如何搭建开发环境请上网搜,很多啦)。你可以在构建工程时同时构建测试工程,假设工程名为PicShow
这步完成后,我们会得到2个工程PicShow, PicShowTest。下面向PicShow的工程中添加代码了,在这之前我要给PicShowTest工程加入一些测试代码,
因为将来会有一个类叫PicShow用于显示下载的图片,所以我在setUp方法中这写:
@Override protected void setUp() throws Exception { super.setUp(); final PicShow a = getActivity(); assertNotNull(a); }
当你写完这段代码,编译一定不能通过,因为这个时候PicShow类还没定义, ^_^。那么我们可以借助Eclipse神奇的快速修正功能(ctrl+1)来新建一个类。然后创建一个TextBox用于输入URL, 一个Button处理点击事件。那在android里你有两种选择来创建控件,一是用代码生成一个实例,二是用layout文件。通常做法是选择后者(可以少写不少代码哦^_^),最后还需要一个imageView对象来显示图片。到这里就需要添加真正的测试代码了:
@LargeTest
public void testDownloadImage() throws Exception {
sendKeys(KeyEvent.KEYCODE_ENTER);
SystemClock.sleep(5000);
SimpleImageViewListAdapter adapter = (SimpleImageViewListAdapter)ga.getAdapter();
ImageView iv = (ImageView)adapter.getItem(0);
assertTrue( iv.getDrawable() != null);
}
在android的测试里面有几个annotation: @SmallTest, @MediumTest, @LargeTest。这些annotation有什么区别呢?
Feature | Small | Medium | Large |
Network access | No | localhost only | Yes |
Database | No | Yes | Yes |
File system access | No | Yes | Yes |
Use external systems | No | Discouraged | Yes |
Multiple threads | No | Yes | Yes |
Sleep statements | No | Yes | Yes |
System properties | No | Yes | Yes |
Time limit (seconds) | 60 | 300 | 900+ |
主要是跟测试的内容有关系,我们在测试中要访问网络所以需要使用@LargeTest标志。接下来我们写一段下载图片的代码给按钮的Click事件调用:
public Bitmap loadImageFromUrl(String url) throws Exception {
final DefaultHttpClient client = new DefaultHttpClient();
final HttpGet getRequest = new HttpGet(url);
HttpResponse response = client.execute(getRequest);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.e("PicShow", "Request URL failed, error code =" + statusCode);
}
HttpEntity entity = response.getEntity();
if (entity == null) {
Log.e("PicShow", "HttpEntity is null");
}
InputStream is = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
is = entity.getContent();
byte[] buf = new byte[1024];
int readBytes = -1;
while ((readBytes = is.read(buf)) != -1) {
baos.write(buf, 0, readBytes);
}
} finally {
if (baos != null) {
baos.close();
}
if (is != null) {
is.close();
}
}
byte[] imageArray = baos.toByteArray();
return BitmapFactory.decodeByteArray(
imageArray, 0, imageArray.length);
}
这样我们一个简单的图片下载应用就搞定的。完整代码就在这里