Android学习之用ListView实现读取Android6.0系统中的文件信息树

在本篇文章中主要是使用ListView实现像电脑版的文件树的形式,以目录“/”作为根目录,依次显示次级目录,当单击ListView中的某一项的时候,如果是文件夹就显示其下包含的文件信息,如果是文件或者文档就显示提示信息。效果形式这里就不为大家显示了。如果感兴趣可以参考一下。

下面从代码的角度为读客介绍程序的编写思路:

package com.example.fileoperation;     //这个是自己的工程建立的包,可以根据自己的工程进行更改

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;

/*
类 Node,实现的Comparable<Node>接口,主要是问了通过比较和排序的方法,将文件夹和文档进行分类显示,实现该接口必须实现抽象函数:comparedTo(Node node),而在本例程中没有用该方法进行排序,而是使用的Collections.sort();
类Node的作用主要是:作为文件树的节点,包含很多信息——文件名、文件路径、父节点信息、子节点列表、是否有子节点、是否为文件夹、是否为文档、是否展开、本节点的级数、id号等信息。还有一些关于成员变量的一些方法。
*/




public class Node implements Comparable<Node> {

    private String str_Name;    // 表示本节点名;
    private String str_Path;    //表示本节点的路径;
    private String str_ParentName;  //表示父节点名;
    private String str_ParentPath;  //表示父节点路径;
    boolean bool_haveSub;//表示是否拥有子节点;
    List<String> subNodeAbsolutePath;
    public boolean isFile;      //表示是否问文件
    public boolean isDoc;      //表示是否问文档;
    public boolean isOpen=false;//表示是否被展开;

    public int level;       //表示本节点所处的级数,根节点(“/”)的级数level=0;
    public int id;
    public int parentID=0;

    private List<Node> subNodeList; //表示本节点的子节点的列表,主要是在该节点被点击之后使用,用于向显示的ListView中添加需要显示的子节点的信息。
    /*
     * @param Path:当表示文件xx的时候,输入格式为:/xx/xxx/xxx/xxx
     * */

    public Node (String Path)
    {
        str_Path = Path;        
        subNodeList = new LinkedList<Node>();           //初始化子节点信息列表
        subNodeAbsolutePath = new LinkedList<>();        //初始化子节点的文件名列表;
        extractInfo();                                   //用于根据传入的参数:Path提取需要信息。包括一些初始化的信息;
    }

//该方法用于返回子节点的个数
    public int getSubNodeSum()
    {
        if(subNodeList!=null) {
            return subNodeList.size();
        }
        else
        {
            return 0;
        }
    }



//该方法用于设置子节点:主要是根据子节点中的属性将子节点中的文件和文档进行归类排序;
    public void setSubNodeList(List<Node> subNodeList)
    {

/*
该方法就是前面给大家说的归类排序。通过比较节点之间的isFile属性,将文档归一类,将文件夹归一类;
*/
        Collections.sort(subNodeList, new Comparator<Node>() {
            @Override
            public int compare(Node node, Node node2) {
                int nodeInt_1 = node.isFile?1:0;
                int nodeInt_2 = node2.isFile?1:0;
                if(nodeInt_1>nodeInt_2)
                    return 1;
                if (nodeInt_1==nodeInt_2)
                    return 0;
                if (nodeInt_1<nodeInt_2)
                    return -1;
                return 0;
            }
        });

        this.subNodeList = subNodeList;
    }


/*
该方法用于获取子节点列表
*/
    public List<Node> getSubNodeList()
    {


        return this.subNodeList;
    }
/*
该方法用于根据输入的参数:Path,提取出相应的信息,包括节点名、父节点、节点的子节点信息等。
*/
    private void extractInfo()
    {

//如果传入的参数Path不为空,则进行相应的操作。
        if(!str_Path.isEmpty())
        {

            String[] info = str_Path.split("/");      //表示以“/”分开路径字符串。
            if(info.length>1) {                       //如果分开的信息的数组中的长度>1,则表示该路径不是第一节点,至少为第二节点。
                level = info.length;
                str_Name = info[info.length - 1];
                str_ParentName = info[info.length - 2];
                for (int i = 0; i < info.length - 1; i++) {
                    str_ParentPath = str_ParentPath + "/" + info[i]; //提取出父节点的路径信息。
                }
            }
            else   //表示该Path表示的第一节点的信息或者根节点"/"。
            {
                level = 1;
                str_Name = info[0];
                str_ParentName = "/";
                str_ParentPath = "/";
            }


            //判断是文档还是文件夹;
            File file = new File(str_Path);
            if(file.isDirectory()&&file.listFiles()!=null)//判断是否为文件夹
            {
                int listFilesLength = file.listFiles().length;
                if(listFilesLength>0) {                //如果子节点的长度大于0,表示含有子节点,反之,表示没有子节点。
                    bool_haveSub = true;                //标志有子节点
                    isFile = true;                        //标志是文件夹
                    isDoc = false;                        //标志不是文档

                    for (int i = 0;i<listFilesLength;i++)
                    {
                        //System.out.println("输出subNodeAbsolutePath中元素的个数:"+listFilesLength);
                        subNodeAbsolutePath.add(file.listFiles()[i].getAbsolutePath());//返回子节点列表,向子节点列表中添加子节点信息
                    }
                }
                else   //表示为文档
                {
                    bool_haveSub = false;
                    isFile = true;
                    isDoc = false;
                    subNodeAbsolutePath = null;
                }
            }
            else
            {
                bool_haveSub = false;
                isFile = false;
                isDoc = true;
            }


        }

    }

    //获得str_Name;
    public String getStr_Name()
    {
        return str_Name;
    }

    //获得str_Parent;
    public String getStr_ParentName()
    {
        return str_ParentName;
    }

    //表示是否拥有子节点
    public boolean getbool_haveSub()
    {
        return  bool_haveSub;
    }

    //获取节点的路径
    public String getStr_Path()
    {
        return this.str_Path;
    }

    //获取父节点路径
    public String getStr_ParentPath()
    {
        return str_ParentPath;
    }


    @Override
    public int compareTo(Node node) {

        int i = (String.valueOf(isFile)).compareTo(String.valueOf(node.isFile));
        return i;
    }
}

上面介绍的是节点类的申明,其中已经备注和解释了相关信息。

下面是适配器,主要是用于向ListView控件中添加指定的信息。该类继承自BaseAdapter适配器。

package com.example.fileoperation;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;


/*
该类为适配器类,继承自BaseAdapter。用于将Node类对象的信息添加到ListView中去。
*/

public class PathListAdapter extends BaseAdapter {

    private Context context;
    private List<Node> displayTree;
    public static final int indentValue = 60;
    ListView listView;


//构造函数。
/*
@context:表示调用的Activity;
@displayTree:表示需要显示在ListView控件中的节点;
@listView:表示使用到的控件:ListView;
*/
    public PathListAdapter(final Context context, final List<Node> displayTree, ListView listView)
    {
        this.context = context;
        this.displayTree = displayTree;
        this.listView = listView;

/*
设置ListView控件的事件,点击控件中的指定项item触发。用于向显示的Node列表中——displayTree添加Node信息。
*/
        this.listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {

                List<Node> childrenNodeList = new LinkedList<>();
                Node treenode = displayTree.get(i);
                if(!treenode.isOpen)     //当节点没有被点击的时候,即未被展开显示的时候。
                {
                    if (treenode.isDoc) { //如果是文件夹,则可以用于展开
                        Toast.makeText(context, "该选项是文档,无法再点击。", Toast.LENGTH_SHORT).show();
                        treenode.isOpen = false;
                    } else {
                        if (treenode.bool_haveSub) {
                            treenode.isOpen = true;
                            for (String each : treenode.subNodeAbsolutePath) {
                                Node node = new Node(each);
                                childrenNodeList.add(node);
                            }
                            treenode.setSubNodeList(childrenNodeList);
                            displayTree.addAll(i + 1, childrenNodeList);
                        } else {
                            treenode.isOpen = false;
                            Toast.makeText(context, "该选项是文件,但是无子文件,无法再往下点击了。", Toast.LENGTH_SHORT).show();
                        }
                    }
                }
                else
                {
                    collapse(treenode,i);//用于迭代关闭其下的子节点和后辈节点,即可以关闭多级节点的子节点。
                }

                notifyDataSetChanged();//系统自带函数,用于更新适配器当数据源改变的时候。
            }
        });
    }


    public void collapse(Node treenode,int position)
    {
        if(treenode.isOpen)
        {
            treenode.isOpen = false;
            List<Node> childrenNode = treenode.getSubNodeList();
            for(int i=0;i<treenode.getSubNodeSum();i++)
            {
                if(childrenNode.get(i).isOpen)
                {
                    collapse(childrenNode.get(i),position+1);//迭代关闭子节点
                }
                displayTree.remove(position+1);
            }

        }
    }

    @Override
    public int getCount() {
        return displayTree.size();//返回节点列表中节点的个数
    }

    @Override
    public Object getItem(int i) {//返回节点列表中的某一项
        return displayTree.get(i);
    }

    @Override
    public long getItemId(int i) {//返回节点所属的列表中的索引
        displayTree.get(i).id=i;
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {//显示的节点对应的ListView中的item的控件的设置。
        ViewHolder viewHolder = null;//新建类,用于包含控件view中指定的控件。
        Node node = displayTree.get(i);
        if(view == null)
        {
            view = LayoutInflater.from(context).inflate(R.layout.fileitem_layout,viewGroup,false);//用于自定义ListView中的item显示的格式或者样式。
            viewHolder = new ViewHolder(view);
            view.setTag(viewHolder);//用于将ViewHolder中的控件与view关联起来。
        }
        else
        {
            viewHolder = (ViewHolder)view.getTag();
        }
        viewHolder.tv_showPathName.setText(node.getStr_Name());
        if(node.isDoc)
        {
            viewHolder.iv_showFileOrDoc.setBackgroundResource(R.mipmap.doc);
        }

        if(node.isFile)
        {
            viewHolder.iv_showFileOrDoc.setBackgroundResource(R.mipmap.file);
        }

        if(node.isOpen)
        {
            viewHolder.iv_showOpenOrClose.setBackgroundResource(R.mipmap.downofopen);
        }
        else
        {
            viewHolder.iv_showOpenOrClose.setBackgroundResource(R.mipmap.top);
        }

        view.setPadding(indentValue*(node.level-2),0,0,0);
        return view;
    }
}


class ViewHolder
{
    TextView tv_showPathName;
    ImageView iv_showOpenOrClose;
    ImageView iv_showFileOrDoc;

    public ViewHolder(View view)
    {
        tv_showPathName = (TextView)view.findViewById(R.id.tv_showPathName);
        iv_showFileOrDoc = (ImageView)view.findViewById(R.id.iv_showFileOrDoc);
        iv_showOpenOrClose = (ImageView)view.findViewById(R.id.iv_showOpenOrClose);
    }


}

下面就是主页面的MainActivity中的代码部分。

package com.example.fileoperation;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       
        ListView listView = (ListView)findViewById(R.id.lv_list);
        List<Node> displayTreeNode = new LinkedList<>();

        String rootPath = "/";
        File file = new File(rootPath);
        for(File each:file.listFiles())
        {
            displayTreeNode.add(new Node(each.getAbsolutePath()));
        }

//用于对显示的列表中项进行归类。这是对第一级节点信息进行处理,在Node类中使用该方法主要是对于节点的子节点的信息进行归类处理。两者不一样,但是功能一样。
        Collections.sort(displayTreeNode, new Comparator<Node>() {
            @Override
            public int compare(Node node, Node node2) {
                int nodeInt_1 = node.isFile?1:0;
                int nodeInt_2 = node2.isFile?1:0;
                if(nodeInt_1>nodeInt_2)
                    return 1;
                if (nodeInt_1==nodeInt_2)
                    return 0;
                if (nodeInt_1<nodeInt_2)
                    return -1;
                return 0;
            }
        });
        PathListAdapter pathListAdapter = new PathListAdapter(getApplicationContext(),displayTreeNode,listView);
        listView.setAdapter(pathListAdapter);
    }
}

如下是两个XML文件的信息,其中第一个是主界面的Layout;第二个是适配器中采用的对于item项的Layout。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:layout_width="300dp"
        android:layout_height="60dp"
        android:id="@+id/ev_search"
        android:layout_centerHorizontal="true"
        android:textColor="#00000000"
        android:textSize="40sp"
        android:text="333333"/>


    <ListView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/lv_list"
        android:layout_below="@+id/ev_search"
        android:footerDividersEnabled="false" />

</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="80dp">

    <ImageView
        android:layout_width="60dp"
        android:layout_height="match_parent"
        android:id="@+id/iv_showOpenOrClose"
        android:layout_marginStart="10dp"
        android:layout_centerVertical="true"/>

    <ImageView
        android:layout_height="match_parent"
        android:layout_width="60dp"
        android:id="@+id/iv_showFileOrDoc"
        android:layout_toEndOf="@+id/iv_showOpenOrClose"
        android:layout_marginStart="20dp"
        android:layout_centerVertical="true"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/tv_showPathName"
        android:layout_toEndOf="@+id/iv_showFileOrDoc"
        android:layout_centerVertical="true"
        android:textColor="#00BCD4"
        android:textSize="20sp"/>

</RelativeLayout>

以上就是全部源码信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值