Android编写简易文件管理模块

最近在做一个将word文档导入到SQLite的程序。对于文件选择问题,经过再三考虑决定写一个简易的文件管理模块,用来选择需要导入的文件文件

先看下效果图:

思路:

获取存储器接口
遍历当前目录
利用ListView显示文件文件夹

先是布局

<?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:orientation="vertical"> <HorizontalScrollView android:layout_width="match_parent" android:layout_height="wrap_content" android:scrollbars="none"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:id="@+id/lyPath"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:textAppearance" android:text="@string/txt_path_now"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:textAppearance" android:text="mnt/sdcard" android:id="@+id/txtPath"/> </LinearLayout> </HorizontalScrollView> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@android:color/darker_gray"/> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <ListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/folderList"/> </LinearLayout> </LinearLayout>

用于加载文件的Item布局

list_file_style.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:scaleY="0.9"> <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:focusable = "false" android:focusableInTouchMode="false" android:id="@+id/cbSelect"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/img" android:src="@mipmap/other" tools:ignore="ContentDescription" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:textAppearance" android:id="@+id/name" android:text="setting"/> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/time" android:text="2017-3-30 21:40:02"/> <View android:layout_width="20dp" android:layout_height="match_parent"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/size" android:text="1.2Mb"/> </LinearLayout> </LinearLayout> </LinearLayout> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@android:color/darker_gray"/> </LinearLayout>

自定义类

为了更好的将数据绑定到ListView上我选择自定义BaseAdapter类

package czhy.grey.sun.exam.bin.adapter_; 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 java.io.File; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; import czhy.grey.sun.exam.R; import czhy.grey.sun.exam.bin.holder_.FileHolder; public class FileAdapter extends BaseAdapter { private ArrayList<File> list; private LayoutInflater inflater; private boolean isRoot; // 用来控制CheckBox的选中状况 private HashMap<Integer, Boolean> isSelected; private int selectNum; public FileAdapter(Context context, ArrayList<File> list,boolean isRoot) { this.list = list; this.isRoot = isRoot; inflater = LayoutInflater.from(context); isSelected = new HashMap<>(); // 初始化数据 initDate(); } @Override public int getCount() { return list.size(); } @Override public File getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { FileHolder holder; File file = getItem(position); if (convertView == null) { convertView = inflater.inflate(R.layout.list_file_style, parent, false); holder = new FileHolder(convertView); convertView.setTag(holder); } else { holder = (FileHolder) convertView.getTag(); } // TODO: 2017/4/1 根目录UI优化 if (!isRoot && position == 0) { holder.setName("返回上一层", file.isDirectory(),isSelectedFor(position)); holder.setId(position,isSelectedFor(position),new View.OnClickListener() { @Override public void onClick(View v) { int position = (int) v.getTag(); boolean b = !isSelected.get(position); isSelected.put(position, b); ((CheckBox) v).setChecked(b); //全选或全取消操作 for(int i=0;i< getCount();i++){ setChecked(i,b); } selectNum = b?getCount():0; notifyDataSetChanged(); } }); holder.setTime("全选"); holder.setSize("已选择"+selectNum+"项"); } else { holder.setName(file.getName(), file.isDirectory(),isSelectedFor(position)); holder.setId(position,isSelectedFor(position),new View.OnClickListener() { @Override public void onClick(View v) { int position = (int) v.getTag(); boolean b = !isSelectedFor(position); isSelected.put(position, b); ((CheckBox) v).setChecked(b); //是否已经全选 if(isSelectedAll()) { isSelected.put(0, true); selectNum = getCount(); }else { isSelected.put(0, false); selectNum = b?selectNum+1:selectNum-1; } notifyDataSetChanged(); } }); holder.setTime(new SimpleDateFormat("yyyy/mm/hh/dd hh:mm:ss").format(file.lastModified())); if (file.isFile()) holder.setSize(fileLength(file.length())); else { holder.setSize(""); } } return convertView; } public boolean isSelectedFor(int id) { return isSelected.get(id); } public int getSelectNum() { return selectNum; } //私有函数 /** 初始化isSelected的数据 */ private void initDate() { selectNum = 0; for (int i = 0; i < list.size(); i++) { isSelected.put(i, false); } } private void setChecked(int id,boolean isChecked) { isSelected.put(id,isChecked); } private String fileLength(long length) { String size; if (length > 1024 * 1024) size = new DecimalFormat("#.00").format(length / (1024.0 * 1024.0)) + "MB"; else if (length > 1024) size = new DecimalFormat("#.00").format(length / 1024.0) + "KB"; else size = length + "B"; return size; } private boolean isSelectedAll(){ for(int i=1;i< getCount();i++){ if(!isSelectedFor(i)) return false; } return true; } }

以及用于布局导入的Holder

package czhy.grey.sun.exam.bin.holder_; import android.view.View; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.TextView; import czhy.grey.sun.exam.R; public class FileHolder{ private CheckBox cbSelect; private TextView name; private TextView time; private TextView size; private ImageView img; public FileHolder(View convertView) { cbSelect = (CheckBox)convertView.findViewById(R.id.cbSelect); name = (TextView)convertView.findViewById(R.id.name); time = (TextView)convertView.findViewById(R.id.time); img = (ImageView)convertView.findViewById(R.id.img); size = (TextView)convertView.findViewById(R.id.size); } public void setTime(String time) { this.time.setText(time); } public void setId(int id,boolean isSelected, View.OnClickListener listener) { cbSelect.setTag(id); cbSelect.setChecked(isSelected); cbSelect.setOnClickListener(listener); } public void setName(String name,boolean isDirectory,boolean isChecked) { this.name.setText(name); cbSelect.setChecked(isChecked); if (isDirectory) { if(name.equalsIgnoreCase("返回上一层")){ img.setImageResource(R.mipmap.back); }else img.setImageResource(R.mipmap.folder); }else { String type = name.substring(name.lastIndexOf(".")+1,name.length()); if ((type.equalsIgnoreCase("doc") || type.equalsIgnoreCase("docx") || type.equalsIgnoreCase("txt"))) { img.setImageResource(R.mipmap.doc_text); } else { img.setImageResource(R.mipmap.other); } } } public void setSize(String size) { this.size.setText(size); } }

控制文件

全局变量

private ListView folderList; private TextView txtPath; private FileAdapter fileAdapter; private ArrayList<File> rootFileList; private boolean isRootNow;

首先是获取存储器列表

private void getRootFile(){ rootFileList = new ArrayList<>(); StorageManager storageManager = (StorageManager) this.getSystemService(STORAGE_SERVICE); try { //内部存储器 File inside = null; //可移除存储器集合 ArrayList<File> outside = new ArrayList<>(); //获取存储器接口 API-24以下不支持StorageVolume接口 //API-24开始可直接 List<StorageVolume> svList = storageManager.getStorageVolumes(); Method getVolumeList = StorageManager.class.getMethod("getVolumeList"); getVolumeList.setAccessible(true); //获取存储器列表 Object[] invokes = (Object[]) getVolumeList.invoke(storageManager); if (invokes != null) { for (Object obj:invokes) { //获取存储器地址接口 Method getPath = obj.getClass().getMethod("getPath"); //获取存储器地址 String path = (String) getPath.invoke(obj); File file = new File(path); if (file.canWrite()) { //获取存储器是否可移除接口 Method isRemovable = obj.getClass().getMethod("isRemovable"); //存储器是否可移除 if((isRemovable.invoke(obj)).equals(true)){ outside.add(file); }else { inside = file; } } } //按0-内部存储器 >0外部存储器 顺序 添加到根目录列表 rootFileList.add(inside); rootFileList.addAll(outside); } } catch (NoSuchMethodException | IllegalArgumentException | IllegalAccessException | InvocationTargetException e1) { e1.printStackTrace(); } }

当我们点击一个文件夹时,打开文件夹以及更新UI

//获取目录数据 private void refurbish(File folder) { txtPath.setText(folder.getPath()); ArrayList<File> files = new ArrayList<>(); files.add(folder.getParentFile()); File[] folderFile = folder.listFiles(); if (null != folderFile && folderFile.length > 0) { for(File file:folderFile) files.add(file); } //新建集合用做打开文件夹 ArrayList<File> openedFolder = new ArrayList<>(); //获取第一个文件夹 上一级文件夹 openedFolder.add(files.get(0)); //移除 上一级文件夹 剩下为当前文件夹内容 files.remove(0); //排序 文件夹在前,然后按文件名排序 Collections.sort(files, new Comparator<File>() { @Override public int compare(File f1, File f2) { if (f1.isDirectory()) { if (f2.isDirectory()) { return f1.getName().compareToIgnoreCase(f2.getName()); } else { return -1; } } else if (f2.isDirectory()) { return 1; } else { return f1.getName().compareToIgnoreCase(f2.getName()); } } }); //将排序完毕的内容添加到目标集合 目的:解决第一个文件夹不是上一层地址问题 openedFolder.addAll(files); fileAdapter = new FileAdapter(this, openedFolder,folder.getParent() == null); folderList.setAdapter(fileAdapter); isRootNow = false; }

程序刚运行时需要加载存储器列表,而不是某一文件夹,所有需要额外定义一个函数

//获取根目录数据 private void rootFile() { txtPath.setText("/"); fileAdapter = new FileAdapter(this, rootFileList,true); folderList.setAdapter(fileAdapter); isRootNow = true; }

因为存储器挂载点的问题,返回上一层时不会返回到存储器列表也就是/storage目录
加上有些文件夹是空或者为系统文件的安全性考虑需要对其隐藏,在获取存储器列表是已经完成了
但,如果直接让其返回上一层会出现进入不安全的目录,所以需要对其进行判断是否是返回根目录

public boolean isRootFile(File file) { //经过两部不同的手机测试,这两个目录是可能的目录 //如果不能正确返回可以自行测试 //测试方法:输出父目录,然后在这里添加或修改即可 return file.getParent().equalsIgnoreCase("/") || file.getParent().equalsIgnoreCase("/storage"); }

有了以上这些,在控制文件创建是直接调用相应的函数即可

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_import); txtPath = (TextView) findViewById(R.id.txtPath); folderList = (ListView) findViewById(R.id.folderList); folderList.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { File file = fileAdapter.getItem(position); //因为为的程序中不需要对文件进行其他操作,所有不做处理 //有需求的在这里添加else即可 if (file.isDirectory()) { if (isRootNow) refurbish(file); else if (isRootFile(file)) rootFile(); else refurbish(file); } } }); getRootFile(); rootFile(); }

弄了这么多基本算是完成了,为了用户友好,我对返回键进行了重载

/** * 监听物理按键 * 需要注意的是这个函数是有返回值的 * 返回值可以理解为 * true表示做了处理,就不提交给处理系统的back按键事件 * false则是提交给系统处理 */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0)) { if (!isRootNow) { File file = fileAdapter.getItem(0); if (isRootFile(file)) rootFile(); else refurbish(file); return true; } else { finish(); } } return super.onKeyDown(keyCode, event); }

参考文献:

Android获取内外置存储卡的方法

android文件管理器用法详解

如何获取Android设备挂载的所有存储器

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

时间: 2024-10-27 16:08:36

Android编写简易文件管理模块的相关文章

android简易文件管理器实例(列表式文件目录)

核心代码: File fatherFile = new File(path);File[] files = fatherFile.listFiles(); 效果图: 实现这种列表式的目录,用直接读取目录下文件方法会比较简单,但是如果要根据文件类型从所有文件中分类,那就用ContentProvider去查询数据库方式会更有效率: 实现代码: FileListActivity.java package com.example.d_readandwritetextfile; import java.i

用安卓编写简易论坛app 怎么实现发帖功能

问题描述 用安卓编写简易论坛app 怎么实现发帖功能 import java.text.SimpleDateFormat; import java.util.Date; import com.example.Service.tieziS; import com.example.project.tiezi; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.

android 编写fragment中

问题描述 android 编写fragment中 一致出现程序很不幸,**运行已经停止的那个弹出框,是什么问题啊? 解决方案 请给出具体的错误信息,最好能附上相应的源代码以方便分析. 解决方案二: 请给出具体的错误信息,最好能附上相应的源代码以方便分析. 解决方案三: anr错误,可能logcat日志,找到你的代码出错行 解决方案四: 调试的错误日志信息是什么 解决方案五: LZ贴出错误日志才能知道错在哪里 解决方案六: 对话框是依靠Activity存在的,是不是你的Activity finis

屏幕分辨率-android编写适应不同分辨率的手机

问题描述 android编写适应不同分辨率的手机 我做了一个记账的安卓小程序 在我自己手机运行很美观 但是到别的手机会使一些元素看不到 怎么去适应别的手机分辨率 谢谢 解决方案 你可以利用线性布局的特性,设置比例weight就可以解决这个问题, 解决方案二: android适配不同分辨率的手机android适配不同分辨率的手机android 不同分辨率,屏幕适应 解决方案三: 很简单,线性布局就好了,, 解决方案四: 不要写绝对的布局,并且减少使用"固定"的尺寸. 解决方案五: 在An

activity-急!android编写高分榜Activity因为SQLite无法实现跳转,求大神找错

问题描述 急!android编写高分榜Activity因为SQLite无法实现跳转,求大神找错 我是直接跟别人代码里一样写的,但到了我自己的项目里就无法实现活动跳转,程序报错自动关闭了, 求大神帮忙看看错在哪里了 package com.example.re; import android.app.Activity; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import andr

Android下RTL8192cu WiFi模块的移植

问题描述 Android下RTL8192cu WiFi模块的移植 本人用的友善之臂的tiny210开发板,想要在Android4.0系统下移植WiFi热点功能,所用的WiFi模块是USB接口的RTL8192CU模块.移植过程中,realtek技术文档说如果要使用nl80211接口的话,需要在驱动autoconf.h头文件中定义宏CONFIG_IOCTL_CFG80211,但是定义该宏变量后,系统每次加载该驱动时就会报错并自动重启. 报错结果如下: 然而,如果不定义该宏变量,驱动虽然正确加载,但是

div 模块 网页编写-编写网页DIV模块总是下移

问题描述 编写网页DIV模块总是下移 我定义了一个大的DIV里面包含两个整体的DIV模块内容.我想实现的是把大的DIV隐藏起来,用户点击的时候大的DIV宽度慢慢增长,然后内容显现出来,现在的问题是第二个DIV总是跑到第一个DIV的下边去,用了很多方法都实现不了,求助. 解决方案 你也不上代码,谁知你到哪一步了 慢慢增长的都实现了吧,用jquery animate可以达到很好效果 关于DIV跑下面去了,那是布局问题 你可以设置两个div都float:left;这样就一排了 但如果外框div从太窄变

android开发之文件管理器

问题描述 android开发之文件管理器 android开发之如何调用系统文件管理器跳转到sd卡指定目录?

多媒体-求大神帮忙解答用VS c++编写简易图像压缩软件带窗口的问题

问题描述 求大神帮忙解答用VS c++编写简易图像压缩软件带窗口的问题 因为我们老师布置了一门多媒体作业需要我们自己去设计一个简单的压缩算法来实现图片的压缩而且还要做成窗体的形式,因为本人是跨专业学的计算机这学期上的很累真的希望有好人能帮忙解答一下这到底是一个怎么样的流程,我的命令行程序怎么样才能和窗体连在其一起使用,还有几周要交了 .求助,求助,求助 重要的事要说三遍~~ 解决方案 http://www.cnblogs.com/tiandsp/archive/2012/12/03/279956