分类:C#、Android、VS2015;

创建日期:2016-02-27

一、简介

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

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

二、示例3运行截图

 

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

  

三、主要设计步骤

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

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. (笔记)ubuntu中取消文件夹或文件等右下解一把锁的标志的方法

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

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

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

随机推荐

  1. 第十二章 Openwrt无法识别2.0 USB 盘

    今天新的U盘不能识别,还以为是U盘本身的问题,原来是缺少 kmod-usb-storage kmod-usb-storage-extras 这两个软件包. 软件包安装后重启便可识别.

  2. JAVA单例MongoDB工具类

    我经常对MongoDB进行一些基础操作,将这些常用操作合并到一个工具类中,方便自己开发使用. 没用Spring Data.Morphia等框架是为了减少学习.维护成本,另外自己直接JDBC方式的话可以 ...

  3. SASS详解之编译输出的样式

    SASS是一种CSS预处理语言,没有装环境的话是不能被解析的.但是有了koala编译工具之后,解析SASS不需要环境也毫无压力了.SASS的输出格式有四种:嵌套.扩大.紧凑和压缩.下面结合小例子为大家 ...

  4. go语言基础之defer延迟调用

    1.defer作用 关键字 defer ⽤于延迟一个函数或者方法(或者当前所创建的匿名函数)的执行.注意,defer语句只能出现在函数或方法的内部. 运行场景: defer语句经常被用于处理成对的操作 ...

  5. DWG/DGN格式导入Arcgis;转化为shp格式;更改地理坐标;导入Google Earth【转】

      其实本来,我就是需要把一个autocad的dwg/dgn格式的东西导入到google earth里面:但是首先我对dwg/dgn格式的东西根本就不熟:其次我拿到的dwg/dgn格式文件是用的HK8 ...

  6. 模拟jQuery中的ready方法及实现按需加载css,js实例代码

    这篇文章介绍了模拟jQuery中的ready方法及实现按需加载css,js实例代码,有需要的朋友可以参考一下     一.ready函数的实现经常用jQuery类库或其他类库中的ready方法,有时候 ...

  7. .net使用自定义类属性

    .net中可以使用Type.GetCustomAttributes获取类上的自定义属性,可以使用PropertyInfo.GetCustomAttributes获取属性信息上的自定义属性. 下面以定义 ...

  8. 查看网络IP连接

  9. vue - 页面跳转

    HTML:a 小程序:navigator Vue:router-link 1. router-link => a标签 2. javascript标签跳转页面 2.1   2.2 3. 常用方法之 ...

  10. setup factory 打包VB 工程

    setup factory 使用起来很简单你可以如下:1.你把你刚编译出来的exe和相关的资源文件复制到某一空目录下.把exe文件添加到setup factory里之后,在列表里右键,属性里面可以设置 ...