首页 > 代码库 > 加载图片和6.0SD卡读写权限
加载图片和6.0SD卡读写权限
转载请标明出处: :http://blog.csdn.net/huaiyiheyuan/article/details/52473984
一、Semaphore(信号量)
1、先来了解一下这个玩意儿,Semaphore semp = new Semaphore(5); 这 里设置的可以访问的资源个数为5.
2、copy介绍 : Semaphore实现的功能就类似厕所有5个坑,假如有10个人要上厕所,那么同时只能有多少个人去上厕所呢?同时只能有5个人能够占用,当5个人中 的任何一个人让开后,其中等待的另外5个人中又有一个人可以占用了。另外等待的5个人中可以是随机获得优先机会,也可以是按照先来后到的顺序获得机会,这取决于构造Semaphore对象时传入的参数选项。单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。
3、示例
public class TestSemaphore {
public static void main(String[] args) {
// 线程池
ExecutorService exec = Executors.newCachedThreadPool();
// 只能5个线程同时访问
Semaphore semp = new Semaphore(5);
// 模拟20个客户端访问
for (int index = 0; index < 20; index++) {
final int NO = index;
Runnable run = new Runnable() {
public void run() {
try {
// 获取许可
semp.acquire();
System.out.println("Accessing: " + NO);
Thread.sleep((long) (Math.random() * 10000));
// 访问完后,释放
semp.release();
System.out.println("-----------------" + semp.availablePermits());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
exec.execute(run);
}
// 退出线程池
exec.shutdown();
}
}
REFERENCE: http://www.cnblogs.com/whgw/archive/2011/09/29/2195555.html
二 、接下来要考虑的是图片的存储位置了
前面也有提过android保存文件到sd卡有两种方式
1、内部存储:下面几个特点
它始终可用。
默认情况下只有您的应用可以访问此处保存的文件。
当用户卸载您的应用时,系统会从内部存储中删除您的应用的所有文件。
当您希望确保用户或其他应用均无法访问您的文件时,内部存储是最佳选择。
外部存储 :外部存储又分为 外部私有存储 、外部公有存储
它并非始终可用,因为用户可采用 USB 存储的形式装载外部存储,并在某些情况下会从设 备中将其删除。
它是全局可读的,因此此处保存的文件可能不受您控制地被读取。
当用户卸载您的应用时,只有在您通过 getExternalFilesDir() 将您的应用的文件保存在 目录中时,系统才会从此处删除您的应用的文件。
对于无需访问限制以及您希望与其他应用共享或允许用户使用电脑访问的文件,外部存储是最佳位置。
公共文件
应供其他应用和用户自由使用的文件。 当用户卸载您的应用时,用户应仍可以使用这些文件。
例如,您的应用拍摄的照片或其他已下载的文件。
私有文件
本属于您的应用且应在用户卸载您的应用时删除的文件。尽管这些文件在技术上可被用户和其他应用访问(因为它们在外部存储上),它们是实际上不向您的应用之外的用户提供值的文件。当用户卸载您的应用时,系统会删除应用外部专用目录中的所有文件。
例如,您的应用下载的其他资源或临时介质文件。
2、特别注意 mkdir(),mkdirs(),createNewFile()的区别
createNewFile:新建文件(非目录)
mkdir:新建目录
mkdirs:新建目录,与mkdir的区别是:比如 mkdirs(“D:/test/test2”) 如果test
不存在会创建,然后创建test2,如果是 mkdir(“D:/test/test2”) ,如果
test不存在,会失败。
3、先来看下内部存储
创建内部目录
目录的路径是这样的:
fileDir /data/data/com.android.imageloaderstorage/files/inner/img
fileCache /data/data/com.android.imageloaderstorage/cache/inner/img
/**
* 创建内部目录
*/
private String fileInnerName = "/inner/img";
private String fileOutName = "/outDir/apk";
private String fileOutPublicName = "/outPublic/outDir";
protected void createInnerDir() {
File fileDir = new File(getActivity().getFilesDir(), fileInnerName);
File fileCache = new File(getActivity().getCacheDir(), fileInnerName);
if (!fileDir.exists()) {
boolean isInner = fileDir.mkdirs();
System.out.println(isInner);
}
if (!fileCache.exists()) {
boolean isInner = fileCache.mkdirs();
System.out.println(isInner);
}
}
内部存储( 下载图片,后面两种就是修改目录就行了)
我这边自己定义目录,就没用openFileOutput,这里用的FileOutputStream(File),这里File如果有多级目录没有创建得先创建目录,否则写入不成功
/**
* 内置存储
* @param context
* @param uniqueName
* @return
*/
public String getInnerCachPath(Context context, String uniqueName) {
String cachePath = context.getCacheDir().getPath() + cache_dir;
if (!new File(cachePath).exists()) {
new File(cachePath).mkdirs();
}
return cachePath + File.separator + uniqueName;
}
/**
* 根据url下载图片在指定的文件
* @param urlStr
* @param file
* @return
*/
public static boolean downloadImgByUrl(String urlStr, File file) {
FileOutputStream fos = null;
InputStream is = null;
try {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
is = conn.getInputStream();
fos = new FileOutputStream(file);
byte[] buf = new byte[512];
int len = 0;
while ((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
}
fos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null)
is.close();
} catch (IOException e) {
}
try {
if (fos != null)
fos.close();
} catch (IOException e) {
}
}
return false;
}
创建外部私有目录
路径是这样滴:fileOut /storage/emulated/0/Android/data/com.android.imageloaderstorage/cache/outdirfalfjlajlfjllllllllllllllllllllll
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
/**
* 创建外部私有目录
*/
protected void creatOutPrivateDir() {
if (!isExternalStorageWritable()) {
return;
}
File fileOut = new File(getActivity().getExternalCacheDir() + fileOutName);
if (!fileOut.exists()) {
Boolean isInner = fileOut.mkdirs();
System.out.println(isInner);
}
}
外部公共目录
路径:/storage/emulated/0/OutIFOAFOFOJFJFFJ/img
/**
* 创建外部公有目录
*/
protected void createOutPublicDir() {
if (!isExternalStorageWritable()) {
return;
}
File filePublic = new File(Environment.getExternalStorageDirectory() + fileOutPublicName);
if (!filePublic.exists()) {
filePublic.mkdirs();
}
}
后面两种只要把存储路径修改就可以了
三、
创建完目录,接下来还要来看下6.0的sd卡去写权限问题了
1、说到权限,那么就要弄清楚 compileSdkVersion 、minSdkVersion、targetSdkVersion的区别 了。
compileSdkVersion :
需要强调的是修改 compileSdkVersion 不会改变运行时的行为。当你修改了 compileSdkVersion 的时候,可能会出现新的编译警告、编译错误,但新的 compileSdkVersion 不会被包含到 APK 中:它纯粹只是在编译的时候使用。(你真的应该修复这些警告,他们的出现一定是有原因的)
因此我们强烈推荐总是使用最新的 SDK 进行编译。在现有代码上使用新的编译检查可以获得很多好处,避免新弃用的 API ,并且为使用新的 API 做好准备。
minSdkVersion:
这个好理解 minSdkVersion 则是应用可以运行的最低要求。minSdkVersion 是 Google Play 商店用来判断用户设备是否可以安装某个应用的标志之一
targetSdkVersion :
targetSdkVersion 是 Android 提供向前兼容的主要依据,就像后面在“外置公有目录”创建快捷方式,targetSdkVersion 22可以创建,targetSdkversion 23不能创建
2、创建代码
外置公有目录(Environment.getExternalStorageDirectory()) 创建
/**
* 创建外部公共目录
*/
protected void createOutPublicDir() {
if (!isExternalStorageWritable()) {
return;
}
File filePublic = new File(Environment.getExternalStorageDirectory() + fileOutPublicName);
if (!filePublic.exists()) {
boolean isCreate = filePublic.mkdirs();
System.out.println(isCreate);
}else {
boolean isDelete = filePublic.delete();
System.out.println(isDelete);
}
}
A、 这是当前版本设置的内容
然后就是跑起来了
结果是这样
B 、接下里把targetSdkVersion 改成 22
运行结果
但是我把版本号马上改回23(没有卸载应用重装),竟然还是可以创建,可能是一个bug吧。
C、如果targetSdkVersion=23 ,我怎么创建目录呢
就是调起 授权弹框
类似于这种效果
Framgent的源码给我们写好了例子
接着看最后的运行效果
如果我们在低于23的手机上运行,那么它安装试默认给定权限,targetSdkVersion 不管怎么改都没用了
2、接着看外部私有目录(context.getExternalCacheDir())
A、Saving files that are app-private
If you are handling files that are not intended for other apps to use (such as graphic textures or sound effects used by only your app), you should use a private storage directory on the external storage by calling getExternalFilesDir(). This method also takes a type argument to specify the type of subdirectory (such as DIRECTORY_MOVIES). If you don’t need a specific media directory, pass null to receive the root directory of your app’s private directory.
Beginning with Android 4.4, reading or writing files in your app’s private directories does not require the READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE permissions. So you can declare the permission should be requested only on the lower versions of Android by adding the maxSdkVersion attribute:
这里是出处: https://developer.android.com/guide/topics/data/data-storage.html#AccessingExtFiles
就是android4.4(api =19)图片和音频文件写入外置私有目录,并且不用声明权限 ,不过为了适配19一下的可以这样写
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
...
</manifest>
B.创建私有目录 我在4.1的机器上跑结果是这样
前提是我去掉了 android.permission.WRITE_EXTERNAL_STORAGE
在高于4.4(api =19)的手机上是这样的无论怎么修改都可以创建了
加载图片和6.0SD卡读写权限