一、原理
1.目标
Andriod系统文件访问
2.要求
设计Android文件浏览器,以列表形式展示系统中存储的文件,排序规则为:文件夹在前面,文件在后面,如果同为文件夹或文件,则按字母顺序排列。文件夹和文件显示不同的图标,单击文件夹,可以进入下级目录并展示。应用顶部显示当前所在目录。
3.思路
主页首先获取系统外部存储的根目录,然后通过listview 控件列表展示。当单击某个文件夹时,获取单击文件夹的文件路径,通过listFiles()方法获取该路径下的子文件,并根据自定义的比较器对结果进行排序,然后更新listview的数据,刷新显示。需要建立4个java文件和3个xml文件供实验操作使用。并修改AndroidManifest.xml文件。
二、过程
开始,在MainActivity中,首先根据Environment.getExternalStorageState(方法判断外部存储是否可用,如果可用,获取外部存储的根目录,然后调用文件管理类FileMgr 的方法获取子文件列表,将文件列表设置到listView自定义的Adapter 中。在onCreate(方法中,对listview的item设置了单击的监听事件,当item被单击后,获取对应的文件对象。如果该文件属于文件夹,则获取子目录,并调用Adapter的noifyDataSetChanged(方法刷新页面显示。其中自定义Adapter和文件管理类的代码如下。
接着,在FileMgr中,调用了File 原生的listFiles()方法获取文件的子文件集合,只不过通过文件名对隐藏文件做了过滤。在返回结果之前,使用自定义的Comparator对文件集合做了排序。
需要在下图中加入两个图片,分别为文件和文件夹:
三、结果
运行结果如下:
点击任意一个可查看下级文件:点击第二个之后
再次点击后:
四、过程中存在的问题及解决方案
问题:
- 直运行停止,APP不响应.
- 无法进入下一级目录,点击后无反应
解决方案:
- 之前用的8.0,改成这个4.0.3之后一样的代码就可以运行了(我的就可以了)。
- 一直感觉是代码语句的原因,仔细一看还真是!!!将下列第一张图片红框中语句改为第二张图片中红框中的代码即可解决。
五、源代码
1、布局文件代码
设置listview并显示文件路径:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/txt_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="TextView" />
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:divider="#d9d9d9"
android:dividerHeight="1dp"
android:layout_below="@+id/txt_view">
</ListView>
</RelativeLayout>
设置文件及名称再item中显示的样式:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical">
<ImageView
android:id="@+id/item_iv"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_margin="8dp"
android:background="@drawable/folder" />
<TextView
android:id="@+id/item_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我是ListView的Item布局"
android:textColor="@color/colorAccent"
android:textSize="18sp" />
</LinearLayout>
2、程序文件
MainActivity.java:
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ListViewAdapter mAdpter;
private TextView mTitle;
private FileMgr fileMgr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_1);
//用于显示当前文件的路径
mTitle=(TextView)findViewById(R.id.txt_view);
//获取listview控件
ListView listView=(ListView)findViewById(R.id.lv);
//自定义的Adapter
mAdpter=new ListViewAdapter(this);
init();
listView.setAdapter(mAdpter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
//获取当前单击的文件
File file = mAdpter.getItem(pos);
//更新显示下级目录
change(file);
}
});
}
private void init()
{
fileMgr=new FileMgr();
//判断外部存储是否可用
if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
{
Toast.makeText(this,"the external storage is not avalible",Toast.LENGTH_SHORT).show();
return;
}
File rootFile=Environment.getExternalStorageDirectory();
mTitle.setText(rootFile.getAbsolutePath());
//获取当前目录的子列表
List<File>files=fileMgr.getSubFiles(rootFile);
mAdpter.updateFiles(files);
}
private void change(File file)
{
if(file.isFile())//如果不是文件夹,直接返回
{
return;
}
//更新路径的显示
mTitle.setText(file.getAbsolutePath());
//获取新的文件列表
List<File>files=fileMgr.getSubFiles(file);
//更新文件和视图显示
mAdpter.updateFiles(files);
mAdpter.notifyDataSetChanged();
}
}
ListViewAdapter.java:
package com.example.myapplication;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class ListViewAdapter extends BaseAdapter {
private LayoutInflater flater;
private List<File> mDatas;
public ListViewAdapter(Context context)
{
flater=LayoutInflater.from(context);
mDatas=new ArrayList<File>();
}
public void updateFiles(List<File>files)
{
mDatas.clear();
mDatas.addAll(files);
}
public int getCount(){
return (null==mDatas|| mDatas.isEmpty())?0:mDatas.size();
}
@Override
public File getItem(int pos){
if(null!=mDatas&&pos<mDatas.size())
{
return mDatas.get(pos);
}
return null;
}
@Override
public long getItemId(int position){
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent){
if(null==convertView)
{
//为每一个子项加载布局
convertView=flater.inflate(R.layout.list_item,null);
}
//获取字item布局文件的控件
ImageView imgView=(ImageView)convertView.findViewById(R.id.item_iv);
TextView txtTitle=(TextView)convertView.findViewById(R.id.item_tv);
File file=getItem(position);//根据position获取数据
if (null!=file)
{
imgView.setImageResource(file.isDirectory()?R.drawable.folder:R.drawable.file);
txtTitle.setText(file.getName());
}
return convertView;
}
}
FileMgr.java
package com.example.myapplication;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class FileMgr {
public List<File> getSubFiles(File file)
{
File[] files=file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File f, String name) {
return !name.startsWith(".");
}
});
System.out.println("files:"+(null==files));
if(null!=files)
{
System.out.println("file mgr length:"+files.length);
}
List<File> result= Arrays.asList(files);
Collections.sort(result,new CustomFileComparator());
return result;
}
}
CustomFileComparator.java
package com.example.myapplication;
import java.io.File;
import java.util.Comparator;
public class CustomFileComparator implements Comparator {
@Override
public int compare(Object o1,Object o2){
File file1=(File)o1;
File file2=(File)o2;
int compare = file1.getName().compareTo(file2.getName());
if (file1.isDirectory())
{
if (file2.isFile())
{
return -1;
}
return compare;
}
if (file2.isDirectory())
{
return 1;
}
return compare;
}
}
3、配置文件
需要添加代码:
<manifest …………
xmlns:tools="http://schemas.android.com/tools"
…………>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
tools:ignore="ProtectedPermissions"/>
</manifest>