Android之从特定目录读取和写入数据

来源:互联网 发布:怎么样才能做好淘宝店 编辑:程序博客网 时间:2024/04/27 16:46

Android之访问内外部存储空间

本文链接:http://blog.csdn.net/qq_16628781/article/details/61413556


知识点:

1、权限管理;

2、获取内外部目录的方法;

3、此示例演示如何从特定目录读取和写入数据,同时需要较少的权限

在开发中,我们经常会用到存储空间,这是一个不可避免的问题。那么,我们该如何来获取到我们需要的存储空间呢。下面为大家介绍一个方法,因为我都在代码里头做了解释,所以文字我就不写那么多了,省的大家一开头就看到这么多的文字,就不想看下去了。

关键的代码都做了注释。


这里要注意一点:我的项目至少是24的SDK才能运行的。

compileSdkVersion 24    buildToolsVersion "25.0.2"    defaultConfig {        minSdkVersion 24        targetSdkVersion 24    }


什么?你手头没有24以上的机器?这还不简单,我们可以利用as提供的虚拟机设备啊。只要你勤点更新SDK,你就能启动一个25SDK机器了。

首先上图



我打开的是sd卡的目录,我们可以看到,列出了这么多,但是因为是模拟题,里头都是没有东西的。


下面,我先把这个页面的代码贴出来


1、是主页fragment_scoped_directory_access的布局:


<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:gravity="center_vertical"    android:orientation="vertical"    android:padding="@dimen/margin_medium">    <LinearLayout        android:id="@+id/container_volumes"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:orientation="vertical">        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginBottom="@dimen/margin_small"            android:orientation="horizontal">            <TextView                android:id="@+id/textview_primary_volume_name"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_marginEnd="@dimen/margin_medium"                android:text="内部存储空间" />            <Button                android:id="@+id/button_open_directory_primary_volume"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="打开" />        </LinearLayout>    </LinearLayout>    <Spinner        android:id="@+id/spinner_directories"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginBottom="@dimen/margin_small" />    <LinearLayout        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginEnd="@dimen/margin_small"        android:layout_marginStart="@dimen/margin_small"        android:orientation="horizontal">        <TextView            android:id="@+id/label_current_directory"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="选择的目录" />        <TextView            android:id="@+id/textview_current_directory"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:enabled="false"            android:textColor="#000000" />    </LinearLayout>    <TextView        android:id="@+id/textview_nothing_in_directory"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginStart="@dimen/margin_small"        android:layout_marginTop="@dimen/margin_medium"        android:text="选择的文件夹为空"        android:visibility="gone" />    <android.support.v7.widget.RecyclerView        android:id="@+id/recyclerview_directory_entries"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_marginEnd="@dimen/margin_small"        android:layout_marginStart="@dimen/margin_small"        android:drawSelectorOnTop="true"        android:scrollbars="vertical"        app:layoutManager="LinearLayoutManager" /></LinearLayout>


然后是volume_entry的布局:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_marginBottom="@dimen/margin_small"    android:orientation="horizontal">    <TextView        android:id="@+id/textview_volume_name"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginEnd="@dimen/margin_medium" />    <Button        android:id="@+id/button_open_directory"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="打开" /></LinearLayout>


2、是Java代码:

import android.app.Activity;import android.content.ContentResolver;import android.content.Context;import android.content.Intent;import android.database.Cursor;import android.net.Uri;import android.os.Bundle;import android.os.Environment;import android.os.storage.StorageManager;import android.os.storage.StorageVolume;import android.provider.DocumentsContract;import android.support.v4.app.Fragment;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ArrayAdapter;import android.widget.Button;import android.widget.LinearLayout;import android.widget.Spinner;import android.widget.TextView;import java.util.ArrayList;import java.util.List;/** * 访问内外部存储空间的例子 */public class ScopedDirectoryAccessFragment extends Fragment {    private static final String DIRECTORY_ENTRIES_KEY = "directory_entries";    private static final String SELECTED_DIRECTORY_KEY = "selected_directory";    private static final int OPEN_DIRECTORY_REQUEST_CODE = 1;    private static final String[] DIRECTORY_SELECTION = new String[]{            DocumentsContract.Document.COLUMN_DISPLAY_NAME,            DocumentsContract.Document.COLUMN_MIME_TYPE,            DocumentsContract.Document.COLUMN_DOCUMENT_ID,    };    private Activity mActivity;    private StorageManager mStorageManager;    private TextView mCurrentDirectoryTextView;    private TextView mNothingInDirectoryTextView;    private TextView mPrimaryVolumeNameTextView;    private Spinner mDirectoriesSpinner;    private DirectoryEntryAdapter mAdapter;    private ArrayList<DirectoryEntry> mDirectoryEntries;    public static ScopedDirectoryAccessFragment newInstance() {        ScopedDirectoryAccessFragment fragment = new ScopedDirectoryAccessFragment();        return fragment;    }    public ScopedDirectoryAccessFragment() {    }    @Override    public void onAttach(Context context) {        super.onAttach(context);        mActivity = getActivity();        mStorageManager = mActivity.getSystemService(StorageManager.class);    }    @Override    public void onActivityResult(int requestCode, int resultCode, Intent data) {        // 回调        super.onActivityResult(requestCode, resultCode, data);        if (requestCode == OPEN_DIRECTORY_REQUEST_CODE && resultCode == Activity.RESULT_OK) {            // 向用户获取权读取内部存储和外部存储的权限            getActivity().getContentResolver().takePersistableUriPermission(data.getData(),                    Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);            updateDirectoryEntries(data.getData());        }    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        return inflater.inflate(R.layout.fragment_scoped_directory_access, container, false);    }    @Override    public void onViewCreated(final View rootView, Bundle savedInstanceState) {        super.onViewCreated(rootView, savedInstanceState);        mCurrentDirectoryTextView = (TextView) rootView                .findViewById(R.id.textview_current_directory);        mNothingInDirectoryTextView = (TextView) rootView                .findViewById(R.id.textview_nothing_in_directory);        mPrimaryVolumeNameTextView = (TextView) rootView                .findViewById(R.id.textview_primary_volume_name);        // Set onClickListener for the primary volume        Button openPictureButton = (Button) rootView                .findViewById(R.id.button_open_directory_primary_volume);        /* 内部存储空间按钮 */        openPictureButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                // 得到spinner的选择项                String selected = mDirectoriesSpinner.getSelectedItem().toString();                // 获取到要访问的目录名称                String directoryName = getDirectoryName(selected);                // 获取到外部存储空间的大小                StorageVolume storageVolume = mStorageManager.getPrimaryStorageVolume();                // 创建一个访问的意图,得到用户的允许之后,就可以访问了                Intent intent = storageVolume.createAccessIntent(directoryName);                // 启动                startActivityForResult(intent, OPEN_DIRECTORY_REQUEST_CODE);            }        });        //获取外部存储空间        List<StorageVolume> storageVolumes = mStorageManager.getStorageVolumes();        LinearLayout containerVolumes = (LinearLayout) mActivity                .findViewById(R.id.container_volumes);        //如果内部存储空间(sd卡)存在的话,就加入访问外部存储空间的按钮        for (final StorageVolume volume : storageVolumes) {            String volumeDescription = volume.getDescription(mActivity);            if (volume.isPrimary()) {                // Primary volume area is already added...                if (volumeDescription != null) {                    // 设置外部存储的真实名称,如果可用的话                    mPrimaryVolumeNameTextView.setText(volumeDescription);                }                continue;            }            // 加载自定义布局            LinearLayout volumeArea = (LinearLayout) mActivity.getLayoutInflater()                    .inflate(R.layout.volume_entry, containerVolumes);            TextView volumeName = (TextView) volumeArea.findViewById(R.id.textview_volume_name);            volumeName.setText(volumeDescription);            Button button = (Button) volumeArea.findViewById(R.id.button_open_directory);            // 设置点击事件            button.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View view) {                    String selected = mDirectoriesSpinner.getSelectedItem().toString();                    String directoryName = getDirectoryName(selected);                    Intent intent = volume.createAccessIntent(directoryName);                    startActivityForResult(intent, OPEN_DIRECTORY_REQUEST_CODE);                }            });        }        RecyclerView recyclerView = (RecyclerView) rootView                .findViewById(R.id.recyclerview_directory_entries);        // 这里做一个判断,是否之前有保存此fragment的状态        if (savedInstanceState != null) {            mDirectoryEntries = savedInstanceState.getParcelableArrayList(DIRECTORY_ENTRIES_KEY);            mCurrentDirectoryTextView.setText(savedInstanceState.getString(SELECTED_DIRECTORY_KEY));            mAdapter = new DirectoryEntryAdapter(mDirectoryEntries);            if (mAdapter.getItemCount() == 0) {                mNothingInDirectoryTextView.setVisibility(View.VISIBLE);            }        } else {            mDirectoryEntries = new ArrayList<>();            mAdapter = new DirectoryEntryAdapter();        }        recyclerView.setAdapter(mAdapter);        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));        // 给spinner设置值        mDirectoriesSpinner = (Spinner) rootView.findViewById(R.id.spinner_directories);        ArrayAdapter<CharSequence> directoriesAdapter = ArrayAdapter                .createFromResource(getActivity(),                        R.array.directories, android.R.layout.simple_spinner_item);        directoriesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);        mDirectoriesSpinner.setAdapter(directoriesAdapter);    }    @Override    public void onSaveInstanceState(Bundle outState) {        super.onSaveInstanceState(outState);        // 当fragment被系统意外杀死是,会调用此方法        // 如果有不明白的,可以看 这个文章:        // http://blog.csdn.net/qq_16628781/article/details/60877412        outState.putString(SELECTED_DIRECTORY_KEY, mCurrentDirectoryTextView.getText().toString());        outState.putParcelableArrayList(DIRECTORY_ENTRIES_KEY, mDirectoryEntries);    }    private void updateDirectoryEntries(Uri uri) {        mDirectoryEntries.clear();        // 这里涉及到内容提供者,可以搜索内容提供者的相关知识        // 也可以看这篇文章的解释:http://blog.csdn.net/qq_16628781/article/details/61195621        // 获取内容获得者        ContentResolver contentResolver = getActivity().getContentResolver();        // 根据URI和id,建立一个URI代表目标去访问内容提供者        Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri,                DocumentsContract.getTreeDocumentId(uri));        // 访问URI的子目录        Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(uri,                DocumentsContract.getTreeDocumentId(uri));        // 查询URI提供者        try (Cursor docCursor = contentResolver                .query(docUri, DIRECTORY_SELECTION, null, null, null)) {            while (docCursor != null && docCursor.moveToNext()) {                mCurrentDirectoryTextView.setText(docCursor.getString(docCursor.getColumnIndex(                        DocumentsContract.Document.COLUMN_DISPLAY_NAME)));            }        }        // 查询子目录        try (Cursor childCursor = contentResolver                .query(childrenUri, DIRECTORY_SELECTION, null, null, null)) {            while (childCursor != null && childCursor.moveToNext()) {                // 获得子目录下的所有文件夹,最后在recycleview里头展示出来                DirectoryEntry entry = new DirectoryEntry();                entry.fileName = childCursor.getString(childCursor.getColumnIndex(                        DocumentsContract.Document.COLUMN_DISPLAY_NAME));                entry.mimeType = childCursor.getString(childCursor.getColumnIndex(                        DocumentsContract.Document.COLUMN_MIME_TYPE));                mDirectoryEntries.add(entry);            }            if (mDirectoryEntries.isEmpty()) {                mNothingInDirectoryTextView.setVisibility(View.VISIBLE);            } else {                mNothingInDirectoryTextView.setVisibility(View.GONE);            }            mAdapter.setDirectoryEntries(mDirectoryEntries);            mAdapter.notifyDataSetChanged();        }    }    /**     * 获取目录的名称     *     * @param name name     * @return name,比如有dcim图片目录,下载目录,音乐等等文件类型     */    private String getDirectoryName(String name) {        switch (name) {            case "ALARMS":                return Environment.DIRECTORY_ALARMS;            case "DCIM":                return Environment.DIRECTORY_DCIM;            case "DOCUMENTS":                return Environment.DIRECTORY_DOCUMENTS;            case "DOWNLOADS":                return Environment.DIRECTORY_DOWNLOADS;            case "MOVIES":                return Environment.DIRECTORY_MOVIES;            case "MUSIC":                return Environment.DIRECTORY_MUSIC;            case "NOTIFICATIONS":                return Environment.DIRECTORY_NOTIFICATIONS;            case "PICTURES":                return Environment.DIRECTORY_PICTURES;            case "PODCASTS":                return Environment.DIRECTORY_PODCASTS;            case "RINGTONES":                return Environment.DIRECTORY_RINGTONES;            default:                throw new IllegalArgumentException("Invalid directory representation: " + name);        }    }}


里边还有一个数组directories在string.xml文件里头:

<?xml version="1.0" encoding="UTF-8"?><resources>    <string-array name="directories">        <item>ALARMS</item>        <item>DCIM</item>        <item>DOCUMENTS</item>        <item>DOWNLOADS</item>        <item>MOVIES</item>        <item>MUSIC</item>        <item>NOTIFICATIONS</item>        <item>PICTURES</item>        <item>PODCASTS</item>        <item>RINGTONES</item>    </string-array></resources>


然后是适配器:DirectoryEntryAdapter.java,适配器的代码比较简单,我就不做解释了,主要使用到了RecyclerView这个新的控件,如果��不懂的,可以自己搜索一下,这里都是最简单的用法,一看就懂了。


package com.example.android.scopeddirectoryaccess;import android.provider.DocumentsContract;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import android.widget.TextView;import java.util.ArrayList;import java.util.List;/** * 适配器 */public class DirectoryEntryAdapter extends RecyclerView.Adapter<DirectoryEntryAdapter.ViewHolder> {    private List<DirectoryEntry> mDirectoryEntries;    public DirectoryEntryAdapter() {        this(new ArrayList<DirectoryEntry>());    }    public DirectoryEntryAdapter(List<DirectoryEntry> directoryEntries) {        mDirectoryEntries = directoryEntries;    }    @Override    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {        View v = LayoutInflater.from(viewGroup.getContext())                .inflate(R.layout.directory_entry, viewGroup, false);        return new ViewHolder(v);    }    @Override    public void onBindViewHolder(ViewHolder viewHolder, final int position) {        viewHolder.fileName.setText(mDirectoryEntries.get(position).fileName);        viewHolder.mimeType.setText(mDirectoryEntries.get(position).mimeType);        if (DocumentsContract.Document.MIME_TYPE_DIR                .equals(mDirectoryEntries.get(position).mimeType)) {            viewHolder.imageView.setImageResource(R.drawable.ic_directory_grey600_36dp);        } else {            viewHolder.imageView.setImageResource(R.drawable.ic_description_grey600_36dp);        }    }    @Override    public int getItemCount() {        return mDirectoryEntries.size();    }    public void setDirectoryEntries(List<DirectoryEntry> directoryEntries) {        mDirectoryEntries = directoryEntries;    }    public class ViewHolder extends RecyclerView.ViewHolder {        public TextView fileName;        public TextView mimeType;        public ImageView imageView;        public ViewHolder(View v) {            super(v);            fileName = (TextView) v.findViewById(R.id.textview_filename);            mimeType = (TextView) v.findViewById(R.id.textview_mimetype);            imageView = (ImageView) v.findViewById(R.id.imageview_entry);        }    }}然后是适配器的布局文件:<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="@dimen/directory_item_height"    android:layout_centerVertical="true"    android:gravity="center_vertical"    android:orientation="horizontal">    <ImageView        android:id="@+id/imageview_entry"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/ic_directory_grey600_36dp" />    <LinearLayout        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginLeft="@dimen/margin_medium"        android:orientation="vertical">        <View            android:id="@+id/divisor"            android:layout_width="match_parent"            android:layout_height="1dp"            android:background="#aaaaaa" />        <TextView            android:id="@+id/textview_filename"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:textColor="#000000" />        <TextView            android:id="@+id/textview_mimetype"            android:layout_width="wrap_content"            android:layout_height="wrap_content" />    </LinearLayout></LinearLayout>

代码基本上就是这样子。

下面再给一个运行的图片




GitHub地址:点击打开链接
















0 0
原创粉丝点击