国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android編寫簡易文件管理模塊

2019-10-23 18:32:25
字體:
供稿:網(wǎng)友

最近在做一個將word文檔導(dǎo)入到SQLite的程序。對于文件選擇問題,經(jīng)過再三考慮決定寫一個簡易的文件管理模塊,用來選擇需要導(dǎo)入的文件文件

先看下效果圖:

Android,文件管理

思路:

獲取存儲器接口
遍歷當前目錄
利用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>

自定義類

為了更好的將數(shù)據(jù)綁定到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<>(); // 初始化數(shù)據(jù) 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優(yōu)化 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);  //是否已經(jīng)全選  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; } //私有函數(shù) /** 初始化isSelected的數(shù)據(jù) */ 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; }}

以及用于布局導(dǎo)入的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 { //內(nèi)部存儲器 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-內(nèi)部存儲器 >0外部存儲器 順序 添加到根目錄列表 rootFileList.add(inside); rootFileList.addAll(outside); } } catch (NoSuchMethodException | IllegalArgumentException | IllegalAccessException | InvocationTargetException e1) { e1.printStackTrace(); } }

當我們點擊一個文件夾時,打開文件夾以及更新UI

 //獲取目錄數(shù)據(jù) 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)); //移除 上一級文件夾 剩下為當前文件夾內(nèi)容 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()); } } }); //將排序完畢的內(nèi)容添加到目標集合 目的:解決第一個文件夾不是上一層地址問題 openedFolder.addAll(files); fileAdapter = new FileAdapter(this, openedFolder,folder.getParent() == null); folderList.setAdapter(fileAdapter); isRootNow = false; } 

程序剛運行時需要加載存儲器列表,而不是某一文件夾,所有需要額外定義一個函數(shù)

 //獲取根目錄數(shù)據(jù) private void rootFile() { txtPath.setText("/"); fileAdapter = new FileAdapter(this, rootFileList,true); folderList.setAdapter(fileAdapter); isRootNow = true; }

因為存儲器掛載點的問題,返回上一層時不會返回到存儲器列表也就是/storage目錄
加上有些文件夾是空或者為系統(tǒng)文件的安全性考慮需要對其隱藏,在獲取存儲器列表是已經(jīng)完成了
但,如果直接讓其返回上一層會出現(xiàn)進入不安全的目錄,所以需要對其進行判斷是否是返回根目錄

 public boolean isRootFile(File file) { //經(jīng)過兩部不同的手機測試,這兩個目錄是可能的目錄 //如果不能正確返回可以自行測試 //測試方法:輸出父目錄,然后在這里添加或修改即可 return file.getParent().equalsIgnoreCase("/") || file.getParent().equalsIgnoreCase("/storage"); }

有了以上這些,在控制文件創(chuàng)建是直接調(diào)用相應(yīng)的函數(shù)即可

@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(); }

弄了這么多基本算是完成了,為了用戶友好,我對返回鍵進行了重載

 /** * 監(jiān)聽物理按鍵 * 需要注意的是這個函數(shù)是有返回值的 * 返回值可以理解為 * true表示做了處理,就不提交給處理系統(tǒng)的back按鍵事件 * false則是提交給系統(tǒng)處理 */ @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); }

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 周至县| 汤阴县| 东乡族自治县| 探索| 句容市| 依兰县| 凤台县| 山西省| 疏勒县| 芦溪县| 社旗县| 奉节县| 元谋县| 华阴市| 新蔡县| 随州市| 嘉义县| 凤翔县| 合川市| 岑溪市| 宜兰市| 太白县| 屏南县| 白城市| 定兴县| 乡城县| 陆河县| 通榆县| 龙川县| 通道| 德州市| 和政县| 新乡市| 蕲春县| 子洲县| 报价| 绵竹市| 津市市| 江西省| 汽车| 枣庄市|