Android实现获取本机中所有图片
本示例演示如何在Android中使用加载器(Loader)来实现获取本机中的所有图片,并进行查看图片的效果。
在这个示例中,我使用android-support-v4.jar中的加载器(Loader)来实现获取本机中所有图片,关于这个包在以前的文章中也提到,是一个非常有用的包,关于这个包的详细信息请大家查看官方文档:http://developer.android.com/sdk/compatibility-library.html。
关于加载器(Loader)是在Android3.0中才开始引进并使用的,Android3.0以前的版本中要想使用加载器则需要用 android-support-v4.jar来实现,我这个示例是基于Android2.2的。加载器(Loader)有什么作用呢?官方文档介绍是: 它能够使用得在activity或fragment中异步加载数据变得更加容易,它具有以下的特点:
1.它们对每一个Activity和Fragment都是有效的。
2.它们提供了一种异步加载数据的能力。
3.它们监视数据源并且数据内容改变时将会传递新的结果。
4.当配置改变而被重新创建时,它们自动的会重连到上一个加载器的游标,然而,它们不需要重新查询数据。
我会结合下面的代码逐步介绍加载器(Loader)相关类及使用方法。下面先让我们看下本示例实现的效果图:
左边的图是显示本机中所有的图片列表,右边的图则是点击一项时查看图片。
项目结构图如下所示:
创建项目时我们需要引入android-support-v4.jar包。
MyDevicePhotoActivity.java文件中代码如下:

package com.device.photo; import android.app.Dialog;
import android.content.ContentResolver;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener; import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter.ViewBinder; /**
* Android实现获取本机中所有图片
* @Description: Android实现获取本机中所有图片 * @FileName: MyDevicePhotoActivity.java * @Package com.device.photo * @Author Hanyonglu * @Date 2012-5-10 下午04:43:55 * @Version V1.0
*/
public class MyDevicePhotoActivity extends FragmentActivity implements LoaderCallbacks<Cursor>{
private Bitmap bitmap = null;
private byte[] mContent = null; private ListView listView = null;
private SimpleCursorAdapter simpleCursorAdapter = null; private static final String[] STORE_IMAGES = {
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.LATITUDE,
MediaStore.Images.Media.LONGITUDE,
MediaStore.Images.Media._ID
}; /** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); listView = (ListView)findViewById(android.R.id.list);
simpleCursorAdapter = new SimpleCursorAdapter(
this,
R.layout.simple_list_item,
null,
STORE_IMAGES,
new int[] { R.id.item_title, R.id.item_value},
0
); simpleCursorAdapter.setViewBinder(new ImageLocationBinder());
listView.setAdapter(simpleCursorAdapter);
// 注意此处是getSupportLoaderManager(),而不是getLoaderManager()方法。
getSupportLoaderManager().initLoader(0, null, this); // 单击显示图片
listView.setOnItemClickListener(new ShowItemImageOnClickListener());
} @Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
// TODO Auto-generated method stub
// 为了查看信息,需要用到CursorLoader。
CursorLoader cursorLoader = new CursorLoader(
this,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
STORE_IMAGES,
null,
null,
null);
return cursorLoader;
} @Override
public void onLoaderReset(Loader<Cursor> arg0) {
// TODO Auto-generated method stub
simpleCursorAdapter.swapCursor(null);
} @Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) {
// TODO Auto-generated method stub
// 使用swapCursor()方法,以使旧的游标不被关闭.
simpleCursorAdapter.swapCursor(cursor);
} // 将图片的位置绑定到视图
private class ImageLocationBinder implements ViewBinder{
@Override
public boolean setViewValue(View view, Cursor cursor, int arg2) {
// TODO Auto-generated method stub
if (arg2 == 1) {
// 图片经度和纬度
double latitude = cursor.getDouble(arg2);
double longitude = cursor.getDouble(arg2 + 1); if (latitude == 0.0 && longitude == 0.0) {
((TextView)view).setText("位置:未知");
} else {
((TextView)view).setText("位置:" + latitude + ", " + longitude);
} // 需要注意:在使用ViewBinder绑定数据时,必须返回真;否则,SimpleCursorAdapter将会用自己的方式绑定数据。
return true;
} else {
return false;
}
}
} // 单击项显示图片事件监听器
private class ShowItemImageOnClickListener implements OnItemClickListener{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// TODO Auto-generated method stub
final Dialog dialog = new Dialog(MyDevicePhotoActivity.this);
// 以对话框形式显示图片
dialog.setContentView(R.layout.image_show);
dialog.setTitle("图片显示"); ImageView ivImageShow = (ImageView) dialog.findViewById(R.id.ivImageShow);
Button btnClose = (Button) dialog.findViewById(R.id.btnClose); btnClose.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
dialog.dismiss(); // 释放资源
if(bitmap != null){
bitmap.recycle();
}
}
}); Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon().
appendPath(Long.toString(id)).build();
FileUtil file = new FileUtil();
ContentResolver resolver = getContentResolver(); // 从Uri中读取图片资源
try {
mContent = file.readInputStream(resolver.openInputStream(Uri.parse(uri.toString())));
bitmap = file.getBitmapFromBytes(mContent, null);
ivImageShow.setImageBitmap(bitmap);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} dialog.show();
}
} @Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy(); if(bitmap != null){
bitmap.recycle();
}
}
}

我们在上面的代码中可以使用回调方法onCreateLoader()来创建一个新的加载器。
LoaderManager.LoaderCallbacks:是一个用于客户端与LoaderManager交互的回调接口。
LoaderManager:是一个抽像类,并关联到一个Activity或Fragment,管理一个或多个装载器的实例。这能够帮助一个应 用管理那些与Activity或Fragment的生命周期相关的运行长时间的的操作。最常见的方式是它与一个CursorLoader一起使用,然而应 用是可以自由的写它们自己的装载器以加载其它类型的数据。
Loader:是一个执行异步数据加载的抽象类。它是加载器的基类。我们可以使用典型的CursorLoader,但是我们也可以实现自己的子类。如果加载器被激活,它们将监视它们的数据源并且当数据改变时发送新的结果。
AsyncTaskLoader:是一个抽象类,能够提供一个AsyncTask来执行异步工作。
CursorLoader:它是AsyncTaskLoader的子类,它可以查询ContentResolver然后返回一个Cursor。 该类实现了加载器的协议并能够以标准的方式查询cursors.以AsyncTaskLoader为基础,在后台线程中执行cursor查询以便不阻塞程 序的UI。使用这个加载器是从ContentProvider中异步查询数据的最好的方式,而不是使用Activity或Fragment的API去执行 一个被管理的查询。
一个使用加载器的应用一般的会包括以下:
1. An Activity or Fragment.
2. An instance of the LoaderManager.
3. 一个被ContentProvider所支持的加载器,该加载器用以加载数据。当然了,我们也可以继承Loader或AsyncTaskLoader以实现自己的子类,去加载其他数据源的数据。
4. 实现LoaderManager.LoaderCallbacks接口,我们可以创建新的装载器以及管理已有的加载器的引用。
5. 一种展现加载器数据的方式 ,比如可以使用SimpleCursorAdapter。
6. 一个数据源,比如ContentProvider。
LoaderManager用以管理一个Activiry或Fragment中的一个或多个装载器.但每个Activity或Fragment只能一个LoaderManager.
那么如何初始化一个加载器呢?需要在Activity的onCreate()方法或是Fragment中的onActivityCreate()方法中实现。
在本示例的代码中,通过如下代码初始化加载器。
getSupportLoaderManager().initLoader(0, null, this);
如果是在Android3.0中则需要通过如下代码进行初始化。
getLoaderManager().initLoader(0, null, this);
initLoader()方法有如下的参数:
1. 一个标识加载器的唯一ID。在本示例中,加载器的ID是0。
2. 一个可选的参数以支持加载器的构建。在本示例中,使用null。
3. 一个LoaderManager.LoaderCallbacks的实现。被LoaderManager调用以报告装载器的事件,在本示例中实现了LoaderManager.LoaderCallbacks这个接口,因此它传递this这个参数。
initLoader()方法能够确保加载器被初始化并激活。它有两种可能的结果:
1. 如果被ID标识的加载器已经存在,那么该加载器将被重新使用。
2. 如果被ID标识的加载器不存在,initLoader()将激发LoaderManager.LoaderCallbacks的onCreateLoader()方法.这能够实现并返回一个新加载器。
一般情况下,对LoaderManager.LoaderCallbacks的实现都与加载器紧密联系着一起,并且当加载器的状态变化时该方法
将被调用。如果调用者在这个时候处于开始状态,并且那请求的加载器已经存在且已经产生了它的数据,然后系统将立即会调用onLoadFinished()
方法(当initLoader()方法执行过程中),所以我们必须为这个事情的发生做好准备。
我们需要注意iniLoader()方法返回被创建的加载器,我们不必捕获对它的一个引用。因为LoaderManager会自动的管理加载器
的生命。LoaderManager会在必要的时候开始和停止加载工作,并且会保持加载器的状态和加载器相关联的内容。这就意味着,我们很少直接与加载器
们交互。我们大多数情况下当特殊的事件发生时去使用LoaderManager.LoaderCallbacks的回调方法去介入加载过程。
如果我们想放弃旧的数据,则应使用restartLoader()方法。
LoaderManager.LoaderCallbacks包含以下的方法:
1. onCreateLoader():根据所给出的ID,初始化并返回一个新的加载器。
2. onLoadFinished():当一个先前被创建的加载器完成了它的加载过程时被调用。
3.onLoaderReset():当一个先前被创建的加载器被重置时被调用,然后使加载器的数据无效。
在onCreateLoader()方法中,能够使我们创建一个新的加载器,或者是实现我们自己的加载器。
在本示例中创建加载器的代码如下:

// 创建新的加载器
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
// TODO Auto-generated method stub
// 为了查看信息,需要用到CursorLoader,也可以实现我们自己的加载器。
CursorLoader cursorLoader = new CursorLoader(
this,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
STORE_IMAGES,
null,
null,
null);
return cursorLoader;
}

在onLoadFinished()方法中,加载器一旦知道应用不再使用数据时,加载器将会释放数据。如果数据是一个从 CursorLoader来的cursor,我们不应该调用它自己的close()方法,如果cursor被放置在CursorAdapter或是 SimpleCursorAdapter中,我们应该使用它自己的swapCursor()方法以使旧的Cursor不被关闭。
在本示例中代码如下:
@Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) {
// TODO Auto-generated method stub
// 使用swapCursor()方法,以使旧的游标不被关闭.
simpleCursorAdapter.swapCursor(cursor);
}
在onLoaderReset()方法中,当一个先前被创建的加载器被重置时该方法会被调用,然后使加载器的数据无效。该回调方法让我们发现数据在什么时候将被释放以便我们删除对它的引用。通常我们实现swapCursor()方法,并给方法传递一个null参数。
在本示例中代码如下:
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
// TODO Auto-generated method stub
simpleCursorAdapter.swapCursor(null);
}
我通过Uri的形式查询到图片,代码如下:

Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon().
appendPath(Long.toString(id)).build();
FileUtil file = new FileUtil();
ContentResolver resolver = getContentResolver(); // 从Uri中读取图片资源
try {
mContent = file.readInputStream(resolver.openInputStream(Uri.parse(uri.toString())));
bitmap = file.getBitmapFromBytes(mContent, null);
ivImageShow.setImageBitmap(bitmap);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}

FileUtil.java文件主要是对图片Uri的处理过程。代码如下:

package com.device.photo; import java.io.ByteArrayOutputStream;
import java.io.InputStream; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; /**
* 文件操作类
* @Description: 文件操作类 * @FileName: FileUtil.java * @Package com.device.photo * @Author Hanyonglu * @Date 2012-5-10 下午01:37:49 * @Version V1.0
*/
public class FileUtil {
public FileUtil() {
// TODO Auto-generated constructor stub
} /**
* InputStream to byte
* @param inStream
* @return
* @throws Exception
*/
public byte[] readInputStream(InputStream inStream) throws Exception {
byte[] buffer = new byte[1024];
int len = -1;
ByteArrayOutputStream outStream = new ByteArrayOutputStream(); while ((len = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, len);
} byte[] data = outStream.toByteArray();
outStream.close();
inStream.close(); return data;
} /**
* Byte to bitmap
* @param bytes
* @param opts
* @return
*/
public Bitmap getBitmapFromBytes(byte[] bytes, BitmapFactory.Options opts) {
if (bytes != null){
if (opts != null){
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length,opts);
}
else{
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}
} return null;
}
}

在本示例中,我们不需要配置任何的权限就可以实现。
关于Android中使用加载器(Loader)来实现获取本机中的所有图片的实现过程及加载器(Loader)的使用大致上就介绍到这里了。
关于加载器更多的信息大家可以查阅官方帮助文档:http://developer.android.com/guide/topics/fundamentals/loaders.html
最后,希望转载的朋友能够尊重作者的劳动成果,加上转载地址:http://www.cnblogs.com/hanyonglu/archive/2012/05/10/2494908.html,谢谢。
Github:https://github.com/hanyonglu/CursorLoader
示例下载:点击下载。
完毕。^_^
Android实现获取本机中所有图片的更多相关文章
- 【android】获取本机ip地址
方法是利用网址:http://pv.sohu.com/cityjson?ie=utf-8,返回String类型的ip地址: public static String getNetIp() { Stri ...
- 【Android】如何获取本机号码、IMSI、EMSI
获取本机号码: 获取本机号码,需要在配置文件中加入权限: <uses-permission android:name="android.permission.READ_PHONE_ST ...
- 用Python批量裁取图,来获取文件夹中所有图片名
批量截图(截取正方形图,哪个边短就用哪个边作为标准来截取) 功能是裁取图片中红色框的部分. 代码为: import sys from tkinter.tix import Tk from PIL im ...
- android 中获取网络状态、判断3G、2G、wifi网络、判断wifi是否打开、获取本机地址、获取本机串号IMEI整理
代码如下:package com.android.xym; import java.io.IOException; import java.net.HttpURLConnection; import ...
- android 获取本机号码需要root吗?
首先要明白,有的手机是获取不到自身的手机号的, 查了些资料,有以下两种方式可以获取到: 1. 通过对方给你发短信,打电话获取本机号码: 2. 还有一个就是通过APN来查询,但是这 ...
- Android编程获取手机型号,本机电话号码,sdk版本号及firmware版本号号(即系统版本号号)
Android开发平台中,可通过TelephonyManager 获取本机号码. TelephonyManager phoneMgr=(TelephonyManager)this.getSystemS ...
- android获取本机的IP地址和mac物理地址
/获取本机IP地址 public String getLocalIpAddress() { WifiManager wifiManager = (WifiManager) getSystemServi ...
- 获取本机 Android 默认sha1 秘钥
获取本机 Android 默认sha1 秘钥: 以Windows操作系统为例,打开CMD,运行以下指令将得到所有默认秘钥. keytool -list -v -keystore C:\Users\pa ...
- Android 获取本机WIFI及3G网络IP
获取本机WIFIprivate String getLocalIpAddress() { WifiManager wifiManager = (WifiManager) getSystemServic ...
随机推荐
- WinAPI——模拟正弦波
/*************************** * * 程序名称 : 模拟正弦波 * 作 者 : doodle777 * 版 本 : 1.1 * 日 期 : 2012-10-19 * 说 明 ...
- gis基本概念之"投影变换"-浅谈
目录 1,概述 2,常用的投影方法有 正解变换 反解变换 数值变换 3,定义投影 4,投影变换 1,栅格(投影变换) 2,要素(投影变换) 注意 1,概述 因为GIS描述的是位于地球表面的信息,所以根 ...
- HTTP Content-type 对照表
文件扩展名 Content-Type(Mime-Type) 文件扩展名 Content-Type(Mime-Type) .*( 二进制流) application/octet-stream .tif ...
- bootstrap兼容IE8的一些注意
准备 bootstrap 3.3.5 jQuery 1.12.0 注意 支持html5 需要引入html5.js 支持placeholder 需要引入placeholder.js ie8 不支持 fo ...
- [转]使用wireshark分析TCP/IP协议中TCP包头的格式
本文简单介绍了TCP面向连接理论知识,详细讲述了TCP报文各个字段含义,并从Wireshark俘获分组中选取TCP连接建立相关报文段进行分析. 一.概述 TCP是面向连接的可靠传输协议,两个进程互发数 ...
- DEV XtraGrid绑定非绑定列(转)
在Gridview创建一列 .将该列的UnboundType属性设置为bound(默认值)以外的数据类型 为该列设置一个窗体内全局唯一的FieldName,注意这个FieldName甚至不能出现在 ...
- Backbone学习笔记
model model的get和set是对model.attributes进行操作,并不是直接对model进行操作 collection collection.set()会触发相应的add,remov ...
- 1109HTML学习
<div><!--face里面用逗号隔开表示 字体优先选择.size是字体1到7 --><font color="red" face="微软 ...
- MVC中修改报错
修改的时候有空值传入.
- JS--图片轮播效果
搞了很长时间才弄清楚图片轮播效果的原理,理解各个事件发生的原因,浪费了这么长的时间,只怪自己的知识太过于薄弱.现将代码写下,供大家参看,如有不妥之处还望指出,大家一起学习. 功能: 1.点击左右两边的 ...