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

分类: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>键运行程序,即得到截图所示的结果。

时间: 2024-10-18 09:27:57

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

Android 使用ContentProvider扫描手机中的图片,仿微信显示本地图片效果

首先我们先看第一个界面吧,使用将手机中的图片扫描出来,然后根据图片的所在的文件夹将其分类出来,并显示所在文件夹里面的一张图片和文件夹中图片个数,我们根据界面元素(文件夹名, 文件夹图片个数,文件夹中的一张图片)使用一个实体对象ImageBean来封装这三个属性 package com.example.imagescan; /** * GridView的每个item的数据对象 * * @author len * */ public class ImageBean{ /** * 文件夹的第一张图片路

可视化webpart基础开发——TreeView控件读取文档库中的所有文件夹和文件(递归方法读取)

可视化webpart基础开发——TreeView控件读取文档库中的所有文件夹和文件(递归方法读取) 分类: SharePoint2011-12-23 14:44 1584人阅读 评论(0) 收藏 举报 文档sharepointurl测试stringforms 可视化webpart基础开发——TreeView控件读取文档库中的所有文件夹和文件(递归方法读取) 1.在部署的sharepoint网站中新建一个名为“测试文档库”的文档库,并添加各级的子文件夹和子文件,用于测试 2.在VS2010中新建空

在sd卡中创建文件夹和文件

本文以在sd卡中创建文件和文件夹为例,讲述如何创建文件夹和文件的重点. 1. 路径问题(下面的例子是在Java中测试的,在Android中同样适用) 1.1 如果需要在文件夹中创建文件的文件夹存在,直接创建文件即可. 例如:File file = new File("F:/1.png"); 1.2 如果需要在文件夹中创建文件的文件夹不存在,需要首先创建文件夹. 例如: File file = new File("F:/123/1.png"); 注释:需要首先在F盘创

eclipse中每次重新启动服务,运行环境下的文件夹或者文件被还原

手动在tomcat运行环境修改了文件,但是每次在eclipse中重启tomcat的时候,总是会把eclipse中的文件更新到tomcat,类似还原,包括上传文件到服务器运行目录,重启的时候,会把上传的文件夹或者文件删掉,很是不解,最后按照下面的方法,暂时好像好了,后期有待观察.大家知道原因的,也可以发表意见,互相学习: 为了使项目默认部署到tomcat安装目录下的webapps中,show view->servers->找到需要修改的tomcat->右击 ①停止eclipse内的Tomc

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

最近在写的程序频繁地与文件操作打交道,这块比较弱,还好在百度上找到一篇不错的文章,这是原文传送门,我对原文稍做了些改动. 有关文件夹与文件的查找,删除等功能 在 os 模块中实现.使用时需先导入这个模块, 导入的方法是: import os 一.取得当前目录 s = os.getcwd() # s 中保存的是当前目录(即文件夹) 比如运行abc.py,那么输入该命令就会返回abc所在的文件夹位置. 举个简单例子,我们将abc.py放入A文件夹.并且希望不管将A文件夹放在硬盘的哪个位置,都可以在A

android创建文件夹和文件和安装其他apk

一.android下创建文件夹 File sd=Environment.getExternalStorageDirectory(); String path=sd.getPath()+"/notes"; File file=new File(path); if(!file.exists()) file.mkdir(); 二.android下创建文件 HttpClient httpClient = new DefaultHttpClient(); HttpGet httpGet= new

Android 删除SD卡文件和文件及创建文件夹和文件

package com.jiub.client.mobile.addphoto; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import android.graphics.Bitmap; import android.os.Environment; import android.util.Log; p

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

在上传项目到github时,忘记忽略了某个文件夹target,就直接push上去了, 最后意识到了此问题,决定删除掉远程仓库中的target文件夹 删除前: 删除后: 在github上只能删除仓库,却无法删除文件夹或文件, 所以只能通过命令来解决 首先进入你的master文件夹下, Git Bash Here ,打开命令窗口 $ git --help 帮助命令 $ git pull origin master 将远程仓库里面的项目拉下来 $ dir  查看有哪些文件夹 $ git rm -r -

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

php读取时出现中文乱码 一般php输出中出现中文乱码我们可用 header ('content:text/html;charset="utf-8"'); php中读取中文文件夹及文件报错? 这就要用到iconv函数了 但php.5以下的版本好像要改php.ini这个配置文件 但我用的是php高版本所以可以直接用 iconv这个函数 用法: iconv('GB2312', 'UTF-8', $file); 但想要继续打开中文文件夹(二级中文目录),还是不行还是会报错, 我认为这应该是地