自定义文件管理器

时间:2022-08-04 21:06:34

最近在研究网易云信demo的时候,我发现他们居然提供API发送文件,这个功能是微信都没有的,于是我点开看了看,结果觉得很low,只是起了一个抛砖引玉的作用而已。于是我继续搬砖来抛!

demo效果:

自定义文件管理器

这里看内容也知道布局很简单,所以我就不贴代码了,接着讲java实现吧!其实实现非常简单,主要是获得根目录,拿到数据,然后将数据提供给ListView的Adapter。
系统提供获取根目录的方法有四个:

一、Android系统的总根目录,包含”/sdcard”、”/system”、”/data”、”/cache”、”/dev”(最后这个文件夹自行搜索吧,我搜出来的也不是很准确。注①),说了这么多,这个文件怎么找出来呢?两个方法:

File[] fileList=File.listRoots();  
File rootFile = fileList[0];
//File rootFile = new File("/");

Android系统的总根目录下可以加载出来有哪些文件呢?,效果如图:

自定义文件管理器

二、获取系统存储根目录,这里说的系统仅仅指”/system” ,不包括外部存储的,不过手机存储的范围远远大于所谓的系统存储,这个文件可以这样写:

File file=Environment.getRootDirectory();
//File file=new File("/system");

系统存储根目录下具体有哪些文件呢?,效果如图:

自定义文件管理器

这个路径下的文件和上一个路径下的文件是不是不一样呢?感觉我们平时看到的都不是这些文件?对的,我们平时一般查阅的都是SD卡的根目录。
三、获取SD卡根目录,这个文件写法:

File file=Environment.getExternalStorageDirectory();
//File file=new File("/sdcard");

SD卡根目录下具体有哪些文件呢?,效果如图:

自定义文件管理器

相信现在大家看见这个目录都很熟悉,这个才是我们平时经常用的目录,那么最后一个我们平时不常用的目录是什么呢?细节之处有魔鬼,我们还是去看看这里有没有魔鬼的存在!

四、获取data根目录,这个目录下就是我们的ApplicationData数据,不过一般情况下,面子不大是拿不到这个文件的。我们先看看这个文件应该怎么写?

File file=Environment.getDataDirectory();
//File file=new File("/data");

File file=new File(“/data”),郭神在《我的第一行代码》第六章讲数据存储持久化举例就是这样写的,那我们去看看以这个作为根目录下有哪些文件呢?

自定义文件管理器

咦?怎么会一个程序都没有,至少我现在运行这个程序应该存在额?为什么没有显示出来呢?原来是由于data文件夹是android里一个非常重要的文件夹,所以一般权限是无法获取到文件的,即fileList.length返回为0

OK,既然知道了这么多根目录,那挑一个SD卡根目录开工吧!这里我们先看看SD卡根目录下面的文件我们是怎么一个不少的全部找到的?

/**
* 初始化控件
*/

private void initView()
{
ivBack = (ImageView) findViewById(R.id.fileManager_title_bar_back);
tvTitle = (TextView) findViewById(R.id.fileManager_title_bar_filename);
lvContext = (ListView) findViewById(R.id.fileManager_listView);
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
{
rootFile = Environment.getExternalStorageDirectory();//14
data = rootFile.listFiles();
adapter = new fileManagerAdapter( data,true);
lvContext.setAdapter(adapter);
tvTitle.setText("data根目录");
}
}

这里重点是列出根目录文件夹下的所有文件和文件夹名,我们使用到一个API :File[] files = File.listFiles();就是如此简单的把Adapter的数据搞定了。but,怎么实现根目录的时候数组的第一个位置为点击没有无响应事件,但是非根目录下点击则可以返回上一级目录呢?
我想大家应该已经想到很多方法来实现,反正我只负责搬砖来抛砖,引来你们好玉的。看好,我要抛砖了!

Adapter的一些关键方法

this.data = addBack(data);
/**
* 第一个增加返回的位置
* @param data
* @return
*/

private File[] addBack(File[] data)
{
if(data==null)//遇到空文件夹
{
data = new File[0];//ListView的返回位置,表明这个集合是一个长度为1的空集合
}
File[] fileData = new File[data.length+1];
for (int i = 0; i < data.length; i++)
{
String path = "/";
//由于ListView下每一项都是文件类型,所以这里必须定义一个文件,只要是文件的类型即可
fileData[0] = new File(path);
fileData[i+1] = data[i];
}
return fileData;


}

@Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder viewHolder;
if(convertView==null)
{
convertView = inflater.inflate(R.layout.list_filemanager_item, parent, false);
viewHolder = new ViewHolder();
viewHolder.ivIcon = (ImageView) convertView.findViewById(R.id.list_filemanager_item_icon);
viewHolder.tvName = (TextView) convertView.findViewById(R.id.list_filemanager_item_name);
convertView.setTag(viewHolder);
}
else
{
viewHolder = (ViewHolder) convertView.getTag();
}

if(position!=0)//一定要判断这个位置是不是第一个
{
File item = data[position];
String name = item.getName();
viewHolder.tvName.setText(name);
if(item.isFile())
{
//根据文件类型item设置不同的Icon
setIcon(name,viewHolder);
}else
{
viewHolder.ivIcon.setImageResource(R.drawable.directory);
}
}
else //第一个位置
{
viewHolder.ivIcon.setImageResource(R.drawable.directory);
if(isDir)//当前是根目录下
{
viewHolder.tvName.setText("/");
}
else //当前非根目录
{
viewHolder.tvName.setText("..");
}
}
return convertView;
}


/**
* 设置文件icon
* @param name
* @param viewHolder
*/

private void setIcon(String name, ViewHolder viewHolder)
{
if(name.lastIndexOf(".xls")!=-1 ||name.lastIndexOf(".xlsx")!=-1)
{
viewHolder.ivIcon.setImageResource(R.drawable.file_ic_detail_excel);
}
else if(name.lastIndexOf(".zip")!=-1 )
{
viewHolder.ivIcon.setImageResource(R.drawable.file_ic_detail_zip);
}
else
{
viewHolder.ivIcon.setImageResource(R.drawable.file);
}

}

Adapter里面整明白了是怎么一回事之后,我们看看ListView的监听事件:

/**
* 初始化监听事件
*/

private void initListener()
{
lvContext.setOnItemClickListener(new OnItemClickListener()
{

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id)
{

if(position!=0)//不是第一项
{
File item = adapter.data[position];
if(item.isFile())//点击了文件
{
Intent intent = new Intent();
intent.putExtra("filePath", item.getAbsolutePath());
setResult(RESULT_OK, intent);
finish();
}
else//点击了文件夹
{
Log.i("FileManagerActivity", "filePath:"+item.getAbsolutePath());
data = item.listFiles();
adapter = new fileManagerAdapter( data,false);
lvContext.setAdapter(adapter);
tvTitle.setText(item.getName());
rootFile = item;
}
}
else//点击第一项
{
//当前是否在SD卡根目录下
if(rootFile.equals(Environment.getExternalStorageDirectory()))
{//这里本来说好点击无响应,处于放假状态的,为什么还有活要干呢?
//因为从根目录的下一层文件返回回来的时候,需要对adapter进行更新
data = rootFile.listFiles();
adapter = new fileManagerAdapter( data,true);
lvContext.setAdapter(adapter);
tvTitle.setText(FileManagerActivity.this.getResources().getString(R.string.file_manager_title_name));
}
else
{//当前不是在SD卡的根目录下,需要返回上一级目录
rootFile=rootFile.getParentFile();
if(rootFile!=null)
{
data = rootFile.listFiles();
adapter = new fileManagerAdapter( data,false);
lvContext.setAdapter(adapter);
tvTitle.setText(rootFile.getName());
}
}
}

}
});
ivBack.setOnClickListener(new OnClickListener()
{

@Override
public void onClick(View v)
{
FileManagerActivity.this.setResult(RESULT_CANCELED);
FileManagerActivity.this.finish();
}
});
}

这里有使用到几个比较常用的关于File的API:
判断SD卡是否插入
Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED);
因为涉及到SDK的读取,自然就需要先判断SDK是否插入。
判断一个文件是不是文件还是文件夹?
判断是不是文件? File.isFile();
判断是不是文件夹? File.isDirectory();
获取文件所在路径即文件所在文件夹:String parentPath = File.getParent();

这里因为我只需要将文件选中之后执行发送,大家看到我选中一个文件之后直接返回路径然后finish()了。不过如果大家有兴趣还可以做一个对话框对文件进行重命名( File.renameTo(destName);)、删除( File.delete();)、移动(获取到文件绝对路径,然后在指定位置写入该文件,最后删除原文件)等等,最后看看你们能做出什么样的文件管理器!!动手试一试吧!!

我最后加载出来的效果是这样:

自定义文件管理器

本文写到这里就完成了,如果有不明白的地方小菜欢迎指出,大家一起学习讨论,谢谢!

傍的大腿:
http://www.cnblogs.com/wenjiang/p/3140055.html
http://blog.chinaunix.net/uid-24227137-id-3027131.html

点击下载源码

注①:dev是设备(device)的英文缩写。/dev这个目录对所有的用户都十分重要。因为在这个目录中包含了所有Linux系统中使用的外部设备。但是这里并不是放的外部设备的驱动程序,这一点和windows,dos操作系统不一样。它实际上是一个访问这些外部设备的端口。我们可以非常方便地去访问这些外部设备,和访问一个文件,一个目录没有任何区别。 Linux沿袭Unix的风格,将所有设备认成是一个文件。)