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>
代码基本上就是这样子。
下面再给一个运行的图片
0 0
- Android之从特定目录读取和写入数据
- Android从文件目录中写入和读取图片
- Android基础之写入、读取数据
- Android 网络编程之HttpURLConnection(conn.getResponseCode() != 200,从url读取写入数据)
- android将对象写入文件和从文件中读取对象数据
- Java从.CSV文件中读取数据和写入
- 从PCD文件写入和读取点云数据
- Java从.CSV文件中读取数据和写入
- scandir读取特定的目录数据
- java从Excel文件读取数据到数据库和从读取数据库数据写入Excel
- json读取和写入数据
- R数据读取和写入
- Android应用程序本地数据的写入和读取
- Android应用程序对SD卡数据的写入和读取
- android读取写入SD卡文件夹和SharedPreferences数据
- XZ_Swift之加载本地json数据、将json数据写入磁盘、从磁盘读取json数据
- gams 从表格中读取 写入数据
- 从hdfs读取数据写入hbase
- 动态规划--2.矩阵链相乘
- volatile
- (41)Air Band OpenCV2.4.13_为轮廓创建包围盒与圆
- HTML标记
- 数组那些不为菜鸟所知的秘密(一)
- Android之从特定目录读取和写入数据
- TensorFlow 实战(一)—— 交叉熵(cross entropy)的定义
- 彻底解决Spring MVC 中文乱码 问题
- EF中查看上下文执行的Sql语句
- 一起Talk Android吧(第十二回:Java中的多态)
- [BZOJ4771][七彩树][可持久化线段树在线转离线+LCA+Set]
- Mac系统终端命令行不执行命令 总出现command not found解决方法
- 查看liunx 的问题
- VSCode Markdown PDF 导出成PDF报 phantomjs binary does not exist 错误的解决办法