一、原理
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>