分类: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文件夹下添加该文件。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="wrap_content"
  5. android:orientation="horizontal">
  6. <ImageView
  7. android:id="@+id/ch14_image1"
  8. android:layout_width="40dip"
  9. android:layout_height="40dip"
  10. android:layout_marginTop="5dip"
  11. android:layout_marginBottom="5dip"
  12. android:layout_marginLeft="5dip"
  13. android:src="@drawable/ch14_file"
  14. android:scaleType="centerCrop" />
  15. <TextView
  16. android:id="@+id/ch14_text1"
  17. android:layout_width="fill_parent"
  18. android:layout_height="wrap_content"
  19. android:layout_weight="1"
  20. android:layout_gravity="left|center_vertical"
  21. android:textSize="28sp"
  22. android:layout_marginLeft="10dip"
  23. android:singleLine="true"
  24. android:text="文件名" />
  25. </LinearLayout>

3、添加ch1403Helpers.cs文件

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

  1. using Android.Content;
  2. using Android.Runtime;
  3. using Android.Views;
  4. using System.IO;
  5.  
  6. namespace MyDemos.SrcDemos
  7. {
  8. public static class ch1403Helpers
  9. {
  10. public static LayoutInflater GetLayoutInflater(this Context context)
  11. {
  12. return context.GetSystemService(Context.LayoutInflaterService).JavaCast<LayoutInflater>();
  13. }
  14.  
  15. public static bool IsDirectory(this FileSystemInfo fsi)
  16. {
  17. if (fsi == null || !fsi.Exists)
  18. {
  19. return false;
  20. }
  21. return (fsi.Attributes & FileAttributes.Directory) == FileAttributes.Directory;
  22. }
  23.  
  24. public static bool IsFile(this FileSystemInfo fsi)
  25. {
  26. if (fsi == null || !fsi.Exists)
  27. {
  28. return false;
  29. }
  30. return !IsDirectory(fsi);
  31. }
  32.  
  33. public static bool IsVisible(this FileSystemInfo fsi)
  34. {
  35. if (fsi == null || !fsi.Exists)
  36. {
  37. return false;
  38. }
  39.  
  40. var isHidden = (fsi.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
  41. return !isHidden;
  42. }
  43. }
  44. }

4、添加ch1403FileListRowViewHolder.cs文件

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

  1. using Android.Widget;
  2.  
  3. namespace MyDemos.SrcDemos
  4. {
  5. public class ch1403FileListRowViewHolder : Java.Lang.Object
  6. {
  7. public ImageView ImageView { get; private set; }
  8. public TextView TextView { get; private set; }
  9.  
  10. public ch1403FileListRowViewHolder(TextView textView, ImageView imageView)
  11. {
  12. TextView = textView;
  13. ImageView = imageView;
  14. }
  15.  
  16. public void Update(string fileName, int fileImageResourceId)
  17. {
  18. TextView.Text = fileName;
  19. ImageView.SetImageResource(fileImageResourceId);
  20. }
  21. }
  22. }

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

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

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

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

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

5、添加ch1403FileListAdapter.cs文件

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

  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using Android.Content;
  4. using Android.Views;
  5. using Android.Widget;
  6. using System.IO;
  7.  
  8. namespace MyDemos.SrcDemos
  9. {
  10. public class ch1403FileListAdapter : ArrayAdapter<FileSystemInfo>
  11. {
  12. private readonly Context _context;
  13.  
  14. public ch1403FileListAdapter(Context context, IList<FileSystemInfo> fsi)
  15. : base(context, Resource.Layout.ch1403_ListItem, Android.Resource.Id.Text1, fsi)
  16. {
  17. _context = context;
  18. }
  19.  
  20. public void AddDirectoryContents(IEnumerable<FileSystemInfo> directoryContents)
  21. {
  22. Clear();
  23. if (directoryContents.Any())
  24. {
  25. AddAll(directoryContents.ToArray());
  26. NotifyDataSetChanged();
  27. }
  28. else
  29. {
  30. NotifyDataSetInvalidated();
  31. }
  32. }
  33.  
  34. public override View GetView(int position, View convertView, ViewGroup parent)
  35. {
  36. FileSystemInfo fileSystemEntry = GetItem(position);
  37. ch1403FileListRowViewHolder viewHolder;
  38. View row;
  39. if (convertView == null)
  40. {
  41. row = ch1403Helpers.GetLayoutInflater(_context).Inflate(Resource.Layout.ch1403_ListItem, parent, false);
  42. viewHolder = new ch1403FileListRowViewHolder(
  43. row.FindViewById<TextView>(Resource.Id.ch14_text1),
  44. row.FindViewById<ImageView>(Resource.Id.ch14_image1));
  45. row.Tag = viewHolder;
  46. }
  47. else
  48. {
  49. row = convertView;
  50. viewHolder = (ch1403FileListRowViewHolder)row.Tag;
  51. }
  52.  
  53. if (ch1403Helpers.IsDirectory(fileSystemEntry))
  54. {
  55. viewHolder.Update(fileSystemEntry.Name, Resource.Drawable.ch14_folder);
  56. }
  57. else
  58. {
  59. viewHolder.Update(fileSystemEntry.Name, Resource.Drawable.ch14_file);
  60. }
  61. return row;
  62. }
  63. }
  64. }

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

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

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

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

6、添加ch1403FileListFragment.cs文件

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

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Android.App;
  5. using Android.OS;
  6. using Android.Views;
  7. using Android.Widget;
  8. using System.IO;
  9.  
  10. namespace MyDemos.SrcDemos
  11. {
  12. public class ch1403FileListFragment : ListFragment
  13. {
  14. public static readonly string DefaultInitialDirectory = "/";
  15. private ch1403FileListAdapter _adapter;
  16. private DirectoryInfo _directory
  17. ;
  18. public override void OnCreate(Bundle savedInstanceState)
  19. {
  20. base.OnCreate(savedInstanceState);
  21. _adapter = new ch1403FileListAdapter(Activity, new FileSystemInfo[0]);
  22. ListAdapter = _adapter;
  23. }
  24.  
  25. public override void OnListItemClick(ListView l, View v, int position, long id)
  26. {
  27. var fileSystemInfo = _adapter.GetItem(position);
  28. if (ch1403Helpers.IsFile(fileSystemInfo))
  29. {
  30. Toast.MakeText(Activity, "你选择了文件:" + fileSystemInfo.FullName, ToastLength.Short).Show();
  31. }
  32. else
  33. {
  34. RefreshFilesList(fileSystemInfo.FullName);
  35. }
  36. base.OnListItemClick(l, v, position, id);
  37. }
  38.  
  39. public override void OnResume()
  40. {
  41. base.OnResume();
  42. RefreshFilesList(DefaultInitialDirectory);
  43. }
  44.  
  45. public void RefreshFilesList(string directory)
  46. {
  47. IList<FileSystemInfo> visibleThings = new List<FileSystemInfo>();
  48. var dir = new DirectoryInfo(directory);
  49. try
  50. {
  51. var a = dir.GetFileSystemInfos()
  52. .Where(item => ch1403Helpers.IsVisible(item));
  53. foreach (var item in a)
  54. {
  55. visibleThings.Add(item);
  56. }
  57. }
  58. catch (Exception ex)
  59. {
  60. Toast.MakeText(Activity,
  61. $"获取{directory}的内容出错," +
  62. $"无法存取该目录:{_directory.FullName}\n" +
  63. "出错原因:" + ex,
  64. ToastLength.Long).Show();
  65. return;
  66. }
  67. _directory = dir;
  68. _adapter.AddDirectoryContents(visibleThings);
  69. ListView.RefreshDrawableState();
  70. }
  71. }
  72. }

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文件夹下添加该文件。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent">
  5. <fragment
  6. class="MyDemos.SrcDemos.ch1403FileListFragment"
  7. android:id="@+id/ch14_fragment"
  8. android:layout_width="match_parent"
  9. android:layout_height="match_parent" />
  10. </FrameLayout>

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

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

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="horizontal"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent">
  6. <fragment
  7. class="MyDemos.SrcDemos.ch1403FileListFragment"
  8. android:id="@+id/ch14_titles_fragment"
  9. android:layout_weight="1"
  10. android:layout_width="0px"
  11. android:layout_height="match_parent" />
  12. <FrameLayout
  13. android:id="@+id/ch14_details"
  14. android:layout_weight="1"
  15. android:layout_width="0px"
  16. android:layout_height="match_parent"
  17. android:background="@android:color/holo_blue_light" />
  18. </LinearLayout>

9、添加ch1403MainActivity.cs文件

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

  1. using Android.App;
  2. using Android.OS;
  3.  
  4. namespace MyDemos.SrcDemos
  5. {
  6. [Activity(Label = "例14-3 手机目录和文件浏览")]
  7. public class ch1403MainActivity : Activity
  8. {
  9. protected override void OnCreate(Bundle savedInstanceState)
  10. {
  11. base.OnCreate(savedInstanceState);
  12. SetContentView(Resource.Layout.ch1403_Main);
  13. }
  14. }
  15. }

注意: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. cocos2dx 3.0研究(1)-- hello world程序

    1. 在mac上构建hello world很easy ./setup.py source /Users/jiangxf/.bash_profile cocos new AliGame -p com.m ...

  2. 惠普HP compaq康柏系列 CQ40笔记本电脑拆机除尘

    工具:两用螺丝刀(一字口的拆CPU,十字口的拆其它所有螺丝)    散热硅胶和CPU上的散热贴 正面照(A面) 反面照(D面) 第一步:拆掉电池,不要忘记了红圈这里的两颗螺丝.共6颗小螺丝. 第二步: ...

  3. [Compose] 15. Applicative Functors for multiple arguments

    Working our way backwards from solution to problem, we define an applicative functor, then use it to ...

  4. [AngularJS] $scope.$warchCollection

    For the $watch in last article, we watch 'user.password', actually it is a string. If you watch 'use ...

  5. (剑指Offer)面试题6:重建二叉树

    题目: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树. 假设输入的前序遍历和中序遍历结果中都不含重复的数字. 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7, ...

  6. html中嵌入flvplayer.swf播放器,播放视频

    只需要改动红色的代码: <object classid='clsid:D27CDB6E-AE6D-11cf-96B8-4445535411111' codebase='http://downlo ...

  7. linux中Oops信息的调试及栈回溯

    Oops 信息来源及格式 Oops 这个单词含义为“惊讶” ,当内核出错时(比如访问非法地址)打印出来的信息被 称为 Oops 信息. Oops 信息包含以下几部分内容. 1 一段文本描述信息. 比如 ...

  8. (转)更新Java final常量后,请重新编译你的class

    程序中使用的各种常量用一个类来统一管理,类似: public class AppConst { public static final String STR_1 = "String1&quo ...

  9. Unity发布各平台路径

    #if UNITY_EDITOR string filepath = Application.dataPath + "/StreamingAssets"; #elif UNITY_ ...

  10. JavaScript严格模式下this指向

    一般认为:严格模式下this不允许指向全局对象.是函数体是否处于严格模式! 如:http://www.ruanyifeng.com/blog/2013/01/javascript_strict_mod ...