【Android】14.3 浏览手机中的所有文件夹和文件

时间:2022-12-30 15:45:59

分类:C#、Android、VS2015;

创建日期:2016-02-27

一、简介

前面我们了解了内部存储、外部存储的含义,用一句话说,内部存储实际上是保存在“data”文件夹下,外部存储(SD卡)实际是保存在“sdcard”或者“storage”文件夹下。

这个例子演示如何将这些内部存储和外部存储的文件夹及其子文件架下的文件全部显示出来,类似于树形结构一层一层地向下看(例子没有实现返回上层的功能,或者说,仅仅实现了Android自带的文件浏览功能的一部分功能)。

二、示例3运行截图

【Android】14.3 浏览手机中的所有文件夹和文件  【Android】14.3 浏览手机中的所有文件夹和文件

下面左图为单击【sdcard】后看到的结果,右图为单击【Download】后看到的结果。

【Android】14.3 浏览手机中的所有文件夹和文件   【Android】14.3 浏览手机中的所有文件夹和文件

三、主要设计步骤

本示例需要应用程序具有对外部文件的读写权限,由于上一个例子已经设置了对应的权限,所以可直接运行。

1、添加图像

在drawable文件夹下添加ch14_file.png、ch14_folder.png文件,图片自己找吧。

2、添加ch1403_ListItem.axml文件

在Resources/layout文件夹下添加该文件。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/ch14_image1"
android:layout_width="40dip"
android:layout_height="40dip"
android:layout_marginTop="5dip"
android:layout_marginBottom="5dip"
android:layout_marginLeft="5dip"
android:src="@drawable/ch14_file"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/ch14_text1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="left|center_vertical"
android:textSize="28sp"
android:layout_marginLeft="10dip"
android:singleLine="true"
android:text="文件名" />
</LinearLayout>

3、添加ch1403Helpers.cs文件

在SrcDemos文件夹下添加该文件,模板选择【Class】。

using Android.Content;
using Android.Runtime;
using Android.Views;
using System.IO; namespace MyDemos.SrcDemos
{
public static class ch1403Helpers
{
public static LayoutInflater GetLayoutInflater(this Context context)
{
return context.GetSystemService(Context.LayoutInflaterService).JavaCast<LayoutInflater>();
} public static bool IsDirectory(this FileSystemInfo fsi)
{
if (fsi == null || !fsi.Exists)
{
return false;
}
return (fsi.Attributes & FileAttributes.Directory) == FileAttributes.Directory;
} public static bool IsFile(this FileSystemInfo fsi)
{
if (fsi == null || !fsi.Exists)
{
return false;
}
return !IsDirectory(fsi);
} public static bool IsVisible(this FileSystemInfo fsi)
{
if (fsi == null || !fsi.Exists)
{
return false;
} var isHidden = (fsi.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
return !isHidden;
}
}
}

4、添加ch1403FileListRowViewHolder.cs文件

在SrcDemos文件夹下添加该文件,模板选择【Class】。

using Android.Widget;

namespace MyDemos.SrcDemos
{
public class ch1403FileListRowViewHolder : Java.Lang.Object
{
public ImageView ImageView { get; private set; }
public TextView TextView { get; private set; } public ch1403FileListRowViewHolder(TextView textView, ImageView imageView)
{
TextView = textView;
ImageView = imageView;
} public void Update(string fileName, int fileImageResourceId)
{
TextView.Text = fileName;
ImageView.SetImageResource(fileImageResourceId);
}
}
}

该类是这个例子中第1个比较重要的组件,这是一个性能优化类(适配器的GetView用这个类来实现)。

在这个类中,要显示的图标和名称分别用ImageView和TextView来显示。由于类中设置了Tag属性,因此在回收视图时,就没有必要每次都通过FindViewById来调用这两个视图了。

注意该类继承自Java.Lang.Object类,这是因为View.Tag类型不是.NET的System.Object类型,而是Java.Lang.Object类型。

当用户点击某个文件夹时,ListView会自动填充该文件夹下子文件夹的内容。

当用户选择某个文件时,该例子仅仅用Toast显示了文件的完整路径,并没有做其他的更多处理。

5、添加ch1403FileListAdapter.cs文件

在SrcDemos文件夹下添加该文件,模板选择【Class】。

using System.Collections.Generic;
using System.Linq;
using Android.Content;
using Android.Views;
using Android.Widget;
using System.IO; namespace MyDemos.SrcDemos
{
public class ch1403FileListAdapter : ArrayAdapter<FileSystemInfo>
{
private readonly Context _context; public ch1403FileListAdapter(Context context, IList<FileSystemInfo> fsi)
: base(context, Resource.Layout.ch1403_ListItem, Android.Resource.Id.Text1, fsi)
{
_context = context;
} public void AddDirectoryContents(IEnumerable<FileSystemInfo> directoryContents)
{
Clear();
if (directoryContents.Any())
{
AddAll(directoryContents.ToArray());
NotifyDataSetChanged();
}
else
{
NotifyDataSetInvalidated();
}
} public override View GetView(int position, View convertView, ViewGroup parent)
{
FileSystemInfo fileSystemEntry = GetItem(position);
ch1403FileListRowViewHolder viewHolder;
View row;
if (convertView == null)
{
row = ch1403Helpers.GetLayoutInflater(_context).Inflate(Resource.Layout.ch1403_ListItem, parent, false);
viewHolder = new ch1403FileListRowViewHolder(
row.FindViewById<TextView>(Resource.Id.ch14_text1),
row.FindViewById<ImageView>(Resource.Id.ch14_image1));
row.Tag = viewHolder;
}
else
{
row = convertView;
viewHolder = (ch1403FileListRowViewHolder)row.Tag;
} if (ch1403Helpers.IsDirectory(fileSystemEntry))
{
viewHolder.Update(fileSystemEntry.Name, Resource.Drawable.ch14_folder);
}
else
{
viewHolder.Update(fileSystemEntry.Name, Resource.Drawable.ch14_file);
}
return row;
}
}
}

该类是这个例子中第2个比较重要的组件。让ArrayAdapter基类处理需要显示的动态列表时,这种方式是一种比较好的处理办法,这是因为通过这种方式可照顾到很多需要在管理列表中做的工作。

在这个类中,让列表中的每一行显示一个文件夹(包括文件夹的图标和文件夹的名称),或者显示文件的图标和文件的名称。对于这些行来说,由于创建视图时重写了GetView()方法。因此无论列表中的行是文件名还是目录名,都可以用相同的XML布局来显示(见ch1403_ListItem.axml文件)。

在重写的GetView()方法中,ArrayAdapter基类会从基础列表中获取FileSystemInfo对象,然后将其返回给视图。

从性能来说,由于ListView可能回收现有的行,这种循环的行可作为convertView参数来传递。代码中通过检查convertView是否为null来决定填充方式。如果为null,则通过指定的XML布局填充它。

6、添加ch1403FileListFragment.cs文件

在SrcDemos文件夹下添加该文件,模板选择【Fragment】。

using System;
using System.Collections.Generic;
using System.Linq;
using Android.App;
using Android.OS;
using Android.Views;
using Android.Widget;
using System.IO; namespace MyDemos.SrcDemos
{
public class ch1403FileListFragment : ListFragment
{
public static readonly string DefaultInitialDirectory = "/";
private ch1403FileListAdapter _adapter;
private DirectoryInfo _directory
;
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
_adapter = new ch1403FileListAdapter(Activity, new FileSystemInfo[0]);
ListAdapter = _adapter;
} public override void OnListItemClick(ListView l, View v, int position, long id)
{
var fileSystemInfo = _adapter.GetItem(position);
if (ch1403Helpers.IsFile(fileSystemInfo))
{
Toast.MakeText(Activity, "你选择了文件:" + fileSystemInfo.FullName, ToastLength.Short).Show();
}
else
{
RefreshFilesList(fileSystemInfo.FullName);
}
base.OnListItemClick(l, v, position, id);
} public override void OnResume()
{
base.OnResume();
RefreshFilesList(DefaultInitialDirectory);
} public void RefreshFilesList(string directory)
{
IList<FileSystemInfo> visibleThings = new List<FileSystemInfo>();
var dir = new DirectoryInfo(directory);
try
{
var a = dir.GetFileSystemInfos()
.Where(item => ch1403Helpers.IsVisible(item));
foreach (var item in a)
{
visibleThings.Add(item);
}
}
catch (Exception ex)
{
Toast.MakeText(Activity,
$"获取{directory}的内容出错," +
$"无法存取该目录:{_directory.FullName}\n" +
"出错原因:" + ex,
ToastLength.Long).Show();
return;
}
_directory = dir;
_adapter.AddDirectoryContents(visibleThings);
ListView.RefreshDrawableState();
}
}
}

FileListFragment子类继承自ListFragment类,用于显示文件夹下的内容。这是这个例子中第3个比较重要的组件,在这个文件中,用一个单独的activity承载(hosts)这个ListFragment。

FileListAdapter加载Activity以后,会自动创建这个fragment,如layout文件夹下的Main.axml文件所示。

创建这个fragment时,在其生命周期内会自动调用OnCreate()方法。在该方法中,用FileListAdapter构造一个空数组来初始化FileSystemInfo对象,并设置ListAdapter属性。

fragment下一个生命周期实现的是OnResume()方法。此方法将在当前目录中创建的文件和子目录列表提供给FileListAdapter。

刷新适配器的逻辑是在RefreshFileList()方法中实现的。

接下来需要重写OnListItemClick()方法。用户每次点击列表视图中的行,都会调用此方法。在这个方法中,FileSystemInfoobject是从适配器被单击的行中检索的。如果对象是一个文件,Toast将显示带路径的的完整文件名,否则显示原目录名。

7、添加纵向放置的ch1403_Main.axml文件

在Resources/layout文件夹下添加该文件。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
class="MyDemos.SrcDemos.ch1403FileListFragment"
android:id="@+id/ch14_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>

8、添加横向放置的ch1403_main.axml文件

在Resources/layout-land子文件夹下添加该文件,注意文件名必须和纵向放置的文件名相同,否则切换到横屏显示时它无法自动找到对应的文件。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<fragment
class="MyDemos.SrcDemos.ch1403FileListFragment"
android:id="@+id/ch14_titles_fragment"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent" />
<FrameLayout
android:id="@+id/ch14_details"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent"
android:background="@android:color/holo_blue_light" />
</LinearLayout>

9、添加ch1403MainActivity.cs文件

在SrcDemos文件夹下添加该文件,模板选择【Activity】。

using Android.App;
using Android.OS; namespace MyDemos.SrcDemos
{
[Activity(Label = "例14-3 手机目录和文件浏览")]
public class ch1403MainActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.ch1403_Main);
}
}
}

注意:ch1403MainActivity继承自FragmentActivity而不是继承自Activity。

FragmentActivity是Android.Support.V4.App命名空间下提供的类,添加程序包的办法见【13.0节】的介绍。

按<F5>键运行程序,即得到截图所示的结果。

【Android】14.3 浏览手机中的所有文件夹和文件的更多相关文章

  1. android 获取文件夹、文件的大小 以B、KB、MB、GB 为单位

    android 获取文件夹.文件的大小 以B.KB.MB.GB 为单位   public class FileSizeUtil { public static final int SIZETYPE_B ...

  2. Android创建文件夹及文件并写入数据

    package elwin.fei.mobileaudio; import java.io.BufferedWriter; import java.io.File; import java.io.Fi ...

  3. Win7-其中的文件夹或文件已在另一个程序中打开

    Win7-其中的文件夹或文件已在另一个程序中打开 如何解决Win7系统在删除或移动文件时提示,“操作无法完成,因为其中的文件夹或文件已在另一个程序中打开,请关闭该文件夹或文件,然后重试”.   步骤阅 ...

  4. 有关文件夹与文件的查找,删除等功能 在 os 模块中实现

    最近在写的程序频繁地与文件操作打交道,这块比较弱,还好在百度上找到一篇不错的文章,这是原文传送门,我对原文稍做了些改动. 有关文件夹与文件的查找,删除等功能 在 os 模块中实现.使用时需先导入这个模 ...

  5. php中读取中文文件夹及文件报错

    php读取时出现中文乱码 一般php输出中出现中文乱码我们可用 header ('content:text/html;charset="utf-8"'); php中读取中文文件夹及 ...

  6. java 查询路径中所有文件夹和文件的名称,支持文件名模糊查询

    java 查询路径中所有文件夹和文件的名称,支持文件名模糊查询 有时候我们遇到需要查询服务器或者本机某个路径下有哪些文件?或者根据文件名称模糊搜索文件,那么就可以使用本方法:可以获取某个路径下所有文件 ...

  7. 从GitHub远程仓库中删除文件夹或文件

    在上传项目到github时,忘记忽略了某个文件夹target,就直接push上去了, 最后意识到了此问题,决定删除掉远程仓库中的target文件夹 删除前: 删除后: 在github上只能删除仓库,却 ...

  8. &lpar;笔记&rpar;ubuntu中取消文件夹或文件等右下解一把锁的标志的方法

    ubuntu中取消文件夹或文件等右下解一把锁的标志的方法   方法:   sudo chmod -R 777 路径(文件夹或文件)   对文件递归做改变权限为可读可写可运行,即可.

  9. Linux中在主机上实现对备机上文件夹及文件的操作的C代码实现

    需求描写叙述 编敲代码.完毕在主机上实现对备机上文件夹及文件的操作. 比如,主机为A,备机为B,要求编写的程序运行在A机上,该程序实如今B机上创建文件文件夹及复制文件的操作. 需求分析 我们先不考虑用 ...

随机推荐

  1. HTML基础篇之表格的运用

    <html> <head> <title></title> </head> <body> <table border=”1 ...

  2. EXCEL datatable 根据列名自动写入到相应属性、字段或列中

    string path = openFileDialog1.FileName; try { DataTable dt = ExcelHelper.ExcelInput(path); ; ; ; ; i ...

  3. iOS:基于AVPlayer实现的视频播放器

    最近在学习AVFoundation框架的相关知识,写了一个基于AVPlayer的视频播放器,相关功能如下图: 代码github:https://github.com/wzpziyi1/VideoPla ...

  4. HTML5的动画学习历程

    一.三角学原理. function getRadio(d){//根据角度获得弧度,                return d*Math.PI/180;                }, fun ...

  5. &lbrack;C&plus;&plus;&rsqb;PAT乙级1004&period; 成绩排名 &lpar;20&sol;20&rpar;

    /* 1004. 成绩排名 (20) 读入n名学生的姓名.学号.成绩,分别输出成绩最高和成绩最低学生的姓名和学号. 输入格式:每个测试输入包含1个测试用例,格式为 第1行:正整数n 第2行:第1个学生 ...

  6. centOS 自动锁屏 解决办法

    System-->preferences --> Screensaver中 找到 Lock screen when screensaver is active 把前面的钩去掉

  7. 用JavaScript获取URL参数的方法之一

    若地址栏URL为:abc.html?m=tomms&c=allsearchlist&pageNo=1&pageNum=20&text=1 <script> ...

  8. 【QQ输入法】QQ输入法输入的英文字母顺便空格很大

    正常的输入出来是这个样子的: 现在变成了这个样子: 怎么解决这个问题呢: 快捷键 shift+空格   即可解决

  9. hadoop 一些命令

    关闭访问墙  service iptables stop hadoop dfs -mkdir input hadoop dfs -copyFromLocal conf/* input hadoop j ...

  10. GNU汇编 伪指令

    伪指令 本身并没有所对应的机器码 它只是在编译的时候起作用,或者转换为其他的实际指令来运行 global ascii byte word data equ align @ 下面的例子是在数据段存放数据 ...