本文概述
愿意为你的Android应用程序实现文件/文件夹选择器吗?当然, 你不想自己创建一个, 而是想依靠第三方库来实现。尽管有很多库可让你实现此功能, 但是如果你想给用户提供选择的选项, 那么存储选择器无疑是一个不错的选择, 他希望从设备的哪个存储中选择文件/目录。 Storage Chooser是一个漂亮而简单的目录选择器和文件选择器库, 适用于4.4+(Kitkat或更高版本)的设备。那里有太多的存储选择器, 但是这一选择实在太重要了。易于实施, 并且不需要花费你宝贵的时间来设置每个开发人员都在寻求的所有其他必要的东西, 例如:
- 保存到sharedPreference的路径
- 选择路径并对该路径执行操作时发生的事件
- 以及更多。
我认为还有一些非常不错的功能会派上用场:
- 在选择之前, 你将快速概览当前的存储及其可用内存, 以便用户知道要选择哪个存储。
- 你可以在工作表布局和时尚的布局之间进行选择。
- 内联创建文件夹视图(不是要处理的另一个对话框)
- 完全本地化。我的意思是, 实际上每个字符串都可以本地化为所需的语言。
- 内存阈值-当用户的内存小于你定义的操作内存时显示的限制或祝酒。
- 并会很快添加更多。
在本文中, 我们将向你展示如何在Android应用程序中轻松实现此存储选择器/文件选择器/文件夹选择器。
1.添加库作为依赖项
要将这个库安装到你的项目中, 请将JitPack存储库添加到你的项目中, 并在build.gradle文件中添加依赖项, 如下所示, 并同步你的项目:
android {
repositories {
maven { url "https://jitpack.io" }
}
}
dependencies {
implementation 'com.github.codekidX:storage-chooser:2.0.4.4'
}
有关此库的更多信息, 请访问Github上的官方存储库。
2.迁移到AndroidX
如果你具有尚未迁移到AndroidX命名空间的任何Maven依赖项, 则在gradle.properties文件中将以下两个标志设置为true时, Android Studio构建系统也会为你迁移这些依赖项。你需要将以下属性添加到gradle.properties文件中并同步你的项目:
android.useAndroidX=true
android.enableJetifier=true
3.使用存储选择器
安装库之后, 你只需要创建StorageChooser.Builder类的实例并根据需要自定义它:
文件选择器
下面的代码初始化一个存储选择器, 该存储选择器使你可以从想要在设备中选择文件的位置进行选择:
// 1. Initialize dialog
final StorageChooser chooser = new StorageChooser.Builder()
// Specify context of the dialog
.withActivity(MainActivity.this)
.withFragmentManager(getFragmentManager())
.withMemoryBar(true)
.allowCustomPath(true)
// Define the mode as the FILE CHOOSER
.setType(StorageChooser.FILE_PICKER)
.build();
// 2. Handle what should happend when the user selects the directory !
chooser.setOnSelectListener(new StorageChooser.OnSelectListener() {
@Override
public void onSelect(String path) {
// e.g /storage/emulated/0/Documents/file.txt
Log.i(path);
}
});
// 3. Display File Picker whenever you need to !
chooser.show();
filepicker支持多重选择, 无需任何额外的代码, 用户只需要选择更长的第一项即可。
文件夹/目录选择器
以下代码初始化一个存储选择器, 该存储选择器使你可以从设备选择目录/文件夹的位置进行选择:
// 1. Initialize dialog
final StorageChooser chooser = new StorageChooser.Builder()
// Specify context of the dialog
.withActivity(MainActivity.this)
.withFragmentManager(getFragmentManager())
.withMemoryBar(true)
.allowCustomPath(true)
// Define the mode as the FOLDER/DIRECTORY CHOOSER
.setType(StorageChooser.DIRECTORY_CHOOSER)
.build();
// 2. Handle what should happend when the user selects the directory !
chooser.setOnSelectListener(new StorageChooser.OnSelectListener() {
@Override
public void onSelect(String path) {
// e.g /storage/emulated/0/Documents
Log.i(path);
}
});
// 3. Display File Picker whenever you need to !
chooser.show();
有关该库更多选项的详细信息, 请不要忘记查看Github官方存储库中的文档。不要忘记, 你将需要在应用程序中授予的READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限。
4.完整的例子
我们的示例将包括权限的管理, 特别是Android的READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限。如果你不请求权限, 则将通过应用程序中的Toast看到以下异常:无法访问你选择的存储。基本上是由你的应用程序中缺少权限引起的, 因此这就是为什么我们将提供一个示例, 说明如何在Android 6+中请求权限。你还需要添加以下属性:
android:configChanges="orientation|screenSize"
对于要在其中实现存储选择器的活动, 例如在AndroidManifest.xml文件中:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ourcodeworld.sandboxkitkat44">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
话虽如此, 让我们展示每种情况的完整示例:
A. Filepicker示例
在此示例中, 我们将有一个主要活动, 其activity_main.xml文件中的布局将包含以下内容:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button_filepicker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pick a file" />
</LinearLayout>
主要活动代码如下:
package com.yourcompany.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.codekidlabs.storagechooser.StorageChooser;
public class MainActivity extends AppCompatActivity {
public static final int FILEPICKER_PERMISSIONS = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button filepickerBtn = findViewById(R.id.button_filepicker);
filepickerBtn.setOnClickListener(new View.OnClickListener(){
@Override
//On click function
public void onClick(View view) {
String[] PERMISSIONS = {
android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE
};
if(hasPermissions(MainActivity.this, PERMISSIONS)){
ShowFilepicker();
}else{
ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS, FILEPICKER_PERMISSIONS);
}
}
});
}
/**
* Method that displays the filepicker of the StorageChooser.
*/
public void ShowFilepicker(){
// 1. Initialize dialog
final StorageChooser chooser = new StorageChooser.Builder()
.withActivity(MainActivity.this)
.withFragmentManager(getFragmentManager())
.withMemoryBar(true)
.allowCustomPath(true)
.setType(StorageChooser.FILE_PICKER)
.build();
// 2. Retrieve the selected path by the user and show in a toast !
chooser.setOnSelectListener(new StorageChooser.OnSelectListener() {
@Override
public void onSelect(String path) {
Toast.makeText(MainActivity.this, "The selected path is : " + path, Toast.LENGTH_SHORT).show();
}
});
// 3. Display File Picker !
chooser.show();
}
/**
* Helper method that verifies whether the permissions of a given array are granted or not.
*
* @param context
* @param permissions
* @return {Boolean}
*/
public static boolean hasPermissions(Context context, String... permissions) {
if (context != null && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
/**
* Callback that handles the status of the permissions request.
*
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case FILEPICKER_PERMISSIONS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(
MainActivity.this, "Permission granted! Please click on pick a file once again.", Toast.LENGTH_SHORT
).show();
} else {
Toast.makeText(
MainActivity.this, "Permission denied to read your External storage :(", Toast.LENGTH_SHORT
).show();
}
return;
}
}
}
}
B.文件夹选择器示例
在此示例中, 我们将有一个主要活动, 其activity_main.xml文件中的布局将包含以下内容:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button_folderpicker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pick a directory" />
</LinearLayout>
主要活动代码如下:
package com.yourcompany.yourapplication;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.codekidlabs.storagechooser.StorageChooser;
public class MainActivity extends AppCompatActivity {
public static final int FOLDERPICKER_PERMISSIONS = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button folderpickerBtn = findViewById(R.id.button_folderpicker);
folderpickerBtn.setOnClickListener(new View.OnClickListener(){
@Override
//On click function
public void onClick(View view) {
String[] PERMISSIONS = {
android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE
};
if(hasPermissions(MainActivity.this, PERMISSIONS)){
ShowDirectoryPicker();
}else{
ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS, FOLDERPICKER_PERMISSIONS);
}
}
});
}
/**
* Method that displays the directory chooser of the StorageChooser.
*/
public void ShowDirectoryPicker(){
// 1. Initialize dialog
final StorageChooser chooser = new StorageChooser.Builder()
.withActivity(MainActivity.this)
.withFragmentManager(getFragmentManager())
.withMemoryBar(true)
.allowCustomPath(true)
.setType(StorageChooser.DIRECTORY_CHOOSER)
.build();
// 2. Retrieve the selected path by the user and show in a toast !
chooser.setOnSelectListener(new StorageChooser.OnSelectListener() {
@Override
public void onSelect(String path) {
Toast.makeText(MainActivity.this, "The selected path is : " + path, Toast.LENGTH_SHORT).show();
}
});
// 3. Display File Picker !
chooser.show();
}
/**
* Helper method that verifies whether the permissions of a given array are granted or not.
*
* @param context
* @param permissions
* @return {Boolean}
*/
public static boolean hasPermissions(Context context, String... permissions) {
if (context != null && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
/**
* Callback that handles the status of the permissions request.
*
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case FOLDERPICKER_PERMISSIONS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(
MainActivity.this, "Permission granted! Please click on pick a file once again.", Toast.LENGTH_SHORT
).show();
} else {
Toast.makeText(
MainActivity.this, "Permission denied to read your External storage :(", Toast.LENGTH_SHORT
).show();
}
return;
}
}
}
}
编码愉快!
评论前必须登录!
注册