最近在做一个将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(),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设备挂载的所有存储器
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。
总结以上是内存溢出为你收集整理的Android编写简易文件管理模块全部内容,希望文章能够帮你解决Android编写简易文件管理模块所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)