天天看点

Android下最简单的共享文件的方法

Android手机的多样性给了用户很多选择,但也造成了开发的难度。举例来说,连象Storage这样的最基本的功能也会有意想不到的复杂度。

每个Android手机都有一个Primary external storage, 用来存储程序数据,以及和其他程序共享文件。许多程序都需要这个空间来存储文件。比如Camera用它来存储照片,Gmail用它来存储下载的文件。

造成问题的是不同手机用不同的硬件来提供这个存储空间。有的用板上的Flash,有的用SdCard. 问题就出在SdCard上,SdCard是可以取掉的。有个时候是故意取掉的,有个时候是无意的。一次,我同事说我们程序出问题,我刚开始看,SdCard在的呀。最后把手机打开,竟然是因为卡没有完全插进去。从外面是看不出来的。

当然用户是永远没错的,Dev需要处理没有SdCard的情形。我们程序里面带有一个apk文件,运行的时候需要调用PackageInstallerActivity来安装这个apk文件。但因为这是两个不一样的进程,所以我们是把apk文件拷贝到外部存储空间上,这样PackageInstallerActivity才能访问到它。

当我的同事SdCard没有全部插进去的时候,这种方式就不能工作了。因为存储空间不存在了。

花了好几个小时研究怎样共享内部的文件,一直没找到什么好方法。Android的Sandbox方式还真是让共享造成很多麻烦。都开始想做一个ContentProvider了,当然是有点小题大做的味道,但也没有其他的好办法。

直到在Context中看到这个。

http://developer.android.com/reference/android/content/Context.html#openFileOutput(java.lang.String, int)

public static final int MODE_WORLD_READABLE

Since: API Level 1
File creation mode: allow all other applications to have read access to the created file.
           

基本上,这可以允许在程序的Sandbox里创建文件的时候,允许其他程序访问。

接下来就简单了。把需要共享的文件从Resource里拷贝到程序的私有存储空间,并且赋予足够的权限,然后就可以用文件路径来访问了。

主要代码如下

/**
	 * Get the shared file path. The shared file resides in app private storage but it's make world readable.
	 * In the first time, the shared file is copied from raw resource.
	 * @param ctx Context
	 * @return The shared file object.
	 */
	private File getSharedFilePath(Context ctx) {
		File cacheFile = ctx.getFileStreamPath(CACHE_APK);
		if (!cacheFile.exists()) {
			Log.i(TAG, "Copy the file to internal storage for the first time.");
			OutputStream os = null;
			InputStream is = null;
			try {
				is = ctx.getResources().openRawResource(R.raw.nytimes);
				os = ctx.openFileOutput(CACHE_APK, Context.MODE_WORLD_READABLE);
				IOUtils.copy(is, os);
			} catch (FileNotFoundException e) {
				Log.i(TAG, "Shouldn't happen:" + e);
			} catch (IOException e) {
				Log.i(TAG, "Failed to copy:" + e);
			} finally {
				IOUtils.closeSilently(os);
				IOUtils.closeSilently(is);
			}
		}
		return cacheFile;
	}