Android 目录浏览支持文件夹、文件单选或者多选

废话没有,先看效果

第一步:创建MainActivity

<code>import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.rdsa.singleselectedfileorfolder.R;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

public Context mContext;
private Button selectFile, selectFolder, mSelectFile, mSelectFolder;
private TextView result;
private Activity activity;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.mContext = this;
this.activity = this;
setContentView(R.layout.activity_main);

initView();
initData();
initEvent();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (requestCode == ChooseFileOrDirActivity.RequestCode && resultCode == ChooseFileOrDirActivity.ResultCode) {
ArrayList<string> resPath = data.getStringArrayListExtra(ChooseFileOrDirActivity.ResultData);
StringBuffer sb = new StringBuffer();
for(String item : resPath) {
sb.append(item).append("\\r\\n");
}
result.setText(sb.toString());
}
}

private void initView() {
this.result = super.findViewById(R.id.result);


this.selectFile = super.findViewById(R.id.selectFile);
this.selectFolder = super.findViewById(R.id.selectFolder);
this.mSelectFile = super.findViewById(R.id.mSelectFile);
this.mSelectFolder = super.findViewById(R.id.mSelectFolder);
}

private void initData() {

}

private void initEvent() {
selectFile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(activity, ChooseFileOrDirActivity.class);
intent.putExtra(ChooseFileOrDirActivity.EnterVar, ChooseFileOrDirActivity.SingleFile);
activity.startActivityForResult(intent, ChooseFileOrDirActivity.RequestCode);
}
});

selectFolder.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(activity, ChooseFileOrDirActivity.class);
intent.putExtra(ChooseFileOrDirActivity.EnterVar, ChooseFileOrDirActivity.SingleFolder);
activity.startActivityForResult(intent, ChooseFileOrDirActivity.RequestCode);
}
});

mSelectFile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(activity, ChooseFileOrDirActivity.class);
intent.putExtra(ChooseFileOrDirActivity.EnterVar, ChooseFileOrDirActivity.MultiFile);
activity.startActivityForResult(intent, ChooseFileOrDirActivity.RequestCode);
}
});

mSelectFolder.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(activity, ChooseFileOrDirActivity.class);
intent.putExtra(ChooseFileOrDirActivity.EnterVar, ChooseFileOrDirActivity.MultiFolder);
activity.startActivityForResult(intent, ChooseFileOrDirActivity.RequestCode);
}
});
}
}/<string>/<code>

第二步:创建MainActivity布局文件activity_main.xml

<code><linearlayout> xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.rdsa.selectedfileorfolder.MainActivity">


<button> android:id="@+id/selectFolder"
android:text="文件夹选择(单选)"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<button> android:id="@+id/selectFile"
android:text="文件选择(单选)"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<button> android:id="@+id/mSelectFolder"
android:text="文件夹选择(多选)"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<button> android:id="@+id/mSelectFile"
android:text="文件选择(多选)"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<textview> android:id="@+id/result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Wait for Result" />


/<textview>/<button>/<button>/<button>/<button>/<linearlayout>/<code>

第三步:创建目录数据存储类FileOrDirBeans

<code>public class FileOrDirBeans {
String isFile, name, isCheckVisible, isChecked, absolutePath ;

public FileOrDirBeans(String... params) {
this.isFile = params[0];
this.name = params[1];
this.isCheckVisible = params[2];
this.isChecked = params[3];


this.absolutePath = params[4];
}

public String getIsFile() {
return isFile;
}

public void setIsFile(String isFile) {
this.isFile = isFile;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getIsCheckVisible() {
return isCheckVisible;
}

public void setIsCheckVisible(String isCheckVisible) {
this.isCheckVisible = isCheckVisible;
}

public String getIsChecked() {
return isChecked;
}

public void setIsChecked(String isChecked) {
this.isChecked = isChecked;
}

public String getAbsolutePath() {
return absolutePath;
}

public void setAbsolutePath(String absolutePath) {
this.absolutePath = absolutePath;
}
}
/<code>

第四步:创建文件浏览ChooseFileOrDirActivity

<code>import android.Manifest;
import android.app.Activity;
import android.content.Intent;


import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

import com.rdsa.singleselectedfileorfolder.R;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class ChooseFileOrDirActivity extends Activity {
public static final String EnterVar = "EnterVar";
public static final String ResultData = "SELECTED";
public static final int RequestCode = 888;
public static final int ResultCode = 999;
public static final int SingleFile = 1000;
public static final int SingleFolder = 2000;
public static final int MultiFile = 3000;
public static final int MultiFolder = 2001;


private String rootPath = Environment.getExternalStorageDirectory().getAbsolutePath();

private static final int REQUESCODE = 5;
private static final String NEED_PERMISSION = Manifest.permission.WRITE_EXTERNAL_STORAGE;
private ListView listView4File;
private TextView noDataTip;
private Button btChose;
private List<string> data;
private ArrayList<fileordirbeans> fileOrDirList;
private FileAdapter fileAdapter;



private int enterVar;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ly_choose_file_or_folder);

this.enterVar = this.getIntent().getIntExtra(EnterVar, SingleFile);


this.initView();
this.initData();
this.initEvent();

}

private void initData() {
this.listView4File.setEmptyView(noDataTip);

this.data = new ArrayList<>();
this.fileOrDirList = new ArrayList<>();
this.fileAdapter = new FileAdapter(this, fileOrDirList, enterVar);
this.listView4File.setAdapter(fileAdapter);

if (Build.VERSION.SDK_INT >= 23) { // 判断系统版本是否大于6.0
if (checkSelfPermission(NEED_PERMISSION) == PackageManager.PERMISSION_GRANTED) { //检查是否有读写权限
loadDataFromPath(rootPath, enterVar);//从路径中加载数据
} else {
requestPermissions(new String[]{NEED_PERMISSION}, REQUESCODE); // 申请权限
}
} else {
loadDataFromPath(rootPath, enterVar);//系统版本小于6.0直接加载数据
}
}

private void loadDataFromPath(final String mPath, final int type) {
this.data.clear(); // data为 ListView 中要显示的数据
this.fileOrDirList.clear();

new Thread() {
public void run() {
super.run();

data = orderByName(mPath, type == SingleFolder || type == MultiFolder);
fileOrDirList = getBeans(data, type);

runOnUiThread(new Runnable() {
@Override
public void run() {
fileAdapter.setData(data, fileOrDirList);//将数据载入适配器当中
}
});
}

}.start();
}

private ArrayList<fileordirbeans> getBeans(List<string> fileList, final int type) {
ArrayList<fileordirbeans> resultList = new ArrayList<>();
for(String fileItem : fileList) {
File file = new File(fileItem);

String isFile = String.valueOf(file.isFile());
String isCheckVisible = (file.isFile() || type == SingleFolder || type == MultiFolder) ? "true" : "false";;

FileOrDirBeans bean = new FileOrDirBeans(isFile, file.getName(), isCheckVisible, "false", fileItem);
resultList.add(bean);
}
return resultList;
}

private void initView() {
listView4File = findViewById(R.id.rvFileView);
noDataTip = findViewById(R.id.noDataTip);
}

private void initEvent() {

fileAdapter.setEvent(new FileAdapter.Event() {
@Override
public void enterNextDir(String path) {
rootPath = path;
loadDataFromPath(rootPath, enterVar);
}
});

findViewById(R.id.btChose).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.putStringArrayListExtra(ResultData, fileAdapter.getSelectData());
setResult(ResultCode, intent);
finish();
}
});
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUESCODE && permissions[0].equals(NEED_PERMISSION)) {
loadDataFromPath(rootPath, enterVar);
}
}


@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {//点击的是返回键
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {//按键的按下事件
if (rootPath.trim().equals(Environment.getExternalStorageDirectory().getAbsolutePath())) {
return super.onKeyDown(keyCode, event);
} else {
File file = new File(rootPath);
if (!file.exists()) {
return super.onKeyDown(keyCode, event);
}
rootPath = file.getParent();
loadDataFromPath(rootPath, enterVar);
return false;
}
}
}
return super.onKeyDown(keyCode, event);
}


public static ArrayList<string> orderByName(String filePath, boolean excludeFile) {
ArrayList<string> FileNameList = new ArrayList<string>();
File file = new File(filePath);
File[] files = file.listFiles();
List fileList = Arrays.asList(files);
Collections.sort(fileList, new Comparator<file>() {
@Override
public int compare(File o1, File o2) {
if (o1.isDirectory() && o2.isFile())
return -1;
if (o1.isFile() && o2.isDirectory())
return 1;
return o1.getName().compareTo(o2.getName());
}
});
for (File itemFile : files) {
if(itemFile.getName().startsWith(".")) {
continue;
} else {
if(itemFile.isFile() && excludeFile) {
continue;
}
FileNameList.add(itemFile.getAbsolutePath()); //往集合中添加符合条件的数据
}
}
return FileNameList;

}
}
/<file>/<string>/<string>/<string>/<fileordirbeans>/<string>/<fileordirbeans>/<fileordirbeans>/<string>/<code>

第五步:创建ChooseFileOrDirActivity布局文件ly_choose_file_or_folder.xml

<code>
<linearlayout> android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<relativelayout> android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#F9F9FA">

<textview> android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />

<button> android:id="@+id/btChose"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="5dp"
android:background="@drawable/bg_button"
android:text="确定"
android:textColor="#458B74" />
/<button>/<textview>/<relativelayout>

<listview> android:id="@+id/rvFileView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<textview> android:id="@+id/noDataTip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:text="没有数据可用,返回上一层" />


/<textview>/<listview>/<linearlayout>
/<code>

第六步:创建ListView的数据容器类FileAdapter

<code>
import android.content.Context;


import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.rdsa.singleselectedfileorfolder.R;
import java.util.ArrayList;
import java.util.List;

public class FileAdapter extends BaseAdapter {
private Context context;
private Event event;
private ArrayList<string> selectData;
private ArrayList<fileordirbeans> fileOrDirList;
private LayoutInflater mLayoutInflater; // 将 Item 的 XML 转换成 View
private final int enterVar;

public FileAdapter(Context context, final ArrayList<fileordirbeans> fileOrDirList, int enterVar) {
this.context = context;
this.selectData = new ArrayList<>();
this.mLayoutInflater = LayoutInflater.from(context); // context 必须是界面所在的 context

this.enterVar = enterVar;
this.fileOrDirList = fileOrDirList;
}

@Override
public int getCount() {
return this.fileOrDirList.size();
}

@Override // 数据项
public Object getItem(int position) {
return fileOrDirList.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override // 显示的内容
public View getView(final int position, View convertView, ViewGroup viewGroup) {
ViewHolder viewHolder;

if(convertView == null) {
convertView = mLayoutInflater.inflate(R.layout.filechoose_layout_fileitme, null);
viewHolder = new ViewHolder();
viewHolder.icon = convertView.findViewById(R.id.icon);
viewHolder.fileName = convertView.findViewById(R.id.fileName);
viewHolder.checkBox = convertView.findViewById(R.id.checkBox);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder)convertView.getTag();
}

final FileOrDirBeans bean = fileOrDirList.get(position);
final String absPath = bean.getAbsolutePath();

bean.setIsChecked("false"); // 初始化一个boolean值 来判断是否被选中
for (String s : selectData) { // 遍历选中的集合
if (s.trim().equals(absPath)) { // 如果集合中的子元素与适配其中的路径相同
bean.setIsChecked("true"); // 判断已被选中
break; //终止循环
}
}

viewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {//设置checkBox的点击事件
if (isChecked) {//选中状态
if (selectData.contains(absPath)) {//如果集合中包含了该元素则直接返回
if (enterVar == ChooseFileOrDirActivity.SingleFile || enterVar == ChooseFileOrDirActivity.SingleFolder) {
selectData.clear();
selectData.add(absPath);
}
} else {//否则添加
if(enterVar == ChooseFileOrDirActivity.SingleFile || enterVar == ChooseFileOrDirActivity.SingleFolder) {
selectData.clear();
}
selectData.add(absPath);
}
} else {//未选中状态
if (selectData.contains(absPath)) {//如果集合中包含了该元素则移除
selectData.remove(absPath);

} else {//否则 返回
return;
}
}

notifyDataSetChanged();
}
});


viewHolder.icon.setImageDrawable(Boolean.parseBoolean(bean.getIsFile()) ? context.getResources().getDrawable(R.drawable._16_file) : context.getResources().getDrawable(R.drawable._16_folder));
viewHolder.fileName.setText(bean.getName());
viewHolder.checkBox.setVisibility((Boolean.parseBoolean(bean.isCheckVisible))? View.VISIBLE : View.GONE);
viewHolder.checkBox.setChecked(Boolean.parseBoolean(bean.getIsChecked()));

viewHolder.fileName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(!Boolean.parseBoolean(bean.getIsFile())) {
event.enterNextDir(fileOrDirList.get(position).getAbsolutePath());
}
}
});

return convertView;
}

static class ViewHolder {
private ImageView icon;
private TextView fileName;
private CheckBox checkBox;
}

public interface Event {
void enterNextDir(String path);//进入下一个文件夹
}

public void setData(List<string> data, ArrayList<fileordirbeans> fileOrDirList) {
this.fileOrDirList.clear();
this.fileOrDirList.addAll(fileOrDirList);

notifyDataSetChanged();
}

public void setEvent(Event event) {
this.event = event;
}

public ArrayList<string> getSelectData() {

return selectData;
}

}/<string>/<fileordirbeans>/<string>/<fileordirbeans>/<fileordirbeans>/<string>/<code>

第七步:创建FileAdapter每一项的布局文件filechoose_layout_fileitme.xml

<code>
<relativelayout> android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >


<imageview> android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:class="lazy" src="//p2.ttnews.xyz/loading.gif" data-original="@drawable/file" />

<textview> android:id="@+id/fileName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"


android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:paddingRight="50dp"
android:layout_toRightOf="@+id/icon"
android:layout_centerVertical="true"
android:text="TextView" />

<checkbox> android:id="@+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="8dp" />

/<checkbox>/<textview>/<imageview>/<relativelayout>/<code>

第八步:AndroidManifest 增加对文件操作的授权

<code><uses-permission>
<uses-permission>/<code>

第九步:用到的图片资源_16_file.png和_16_folder.png