当用户做下载等操作时,SD卡的空间可能不足,所以需要提前获取SD卡剩余容量,给予用户提示信息。
在Android系统中,可以查看SD卡剩余容量,点击Setting-->Storage。
sdk文件夹中的sources文件夹中的源码是Android jar包的源码,Android系统源码则不同,一定要区分开。如下图。
其中,packages/apps路径为Android系统级应用程序所在的目录,可以看到settings应用程序。
1、导入settings应用程序到eclipse中。
①点击File-->New-->Other....。
②点击Android下的Android Project from Existing Code-->Next。
③点击Root Directory右侧的Browse...按钮,找到settings应用程序所在的目录,点击确定。
④下图中的tests为测试settings的应用程序,不勾。
之所以会报错,是因为普通应用开发是无法访问系统级API的(settings工程导入eclipse就成为了一个普通应用开发项目)。
2、查找实现查看SD卡剩余空间的源码。
①通过搜索关键字“Available space”开始查找。
②通过eclipse的“File Search”在整个工作空间中搜索“Available space”。
⑥再在本文件内搜索“MEMORY_SD_AVAIL”。
⑦再在本文件内搜索“mSdAvail”,可以看到,已经查找到了该段代码。
3、解析源码。
所有存储设备都会被划分成若干个区块,存储设备的总容量 = 每个区块大小 * 区块总数量。
其中的formatSize函数实际上就是将得出的字节数,转换成MB、GB、TB及PB显示给用户。
res\layout\activity_main.xml
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- tools:context=".MainActivity" >
- <TextView
- android:id="@+id/tv"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/hello_world" />
- </RelativeLayout>
复制代码
src/cn.itcast.getsdavail/MainActivity.java - package cn.itcast.getsdavail;
- import java.io.File;
- import android.os.Build;
- import android.os.Bundle;
- import android.os.Environment;
- import android.os.StatFs;
- import android.app.Activity;
- import android.text.format.Formatter;
- import android.view.Menu;
- import android.widget.TextView;
- public class MainActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- File path = Environment.getExternalStorageDirectory();
- StatFs stat = new StatFs(path.getPath());
-
- long blockSize;
- long availableBlocks;
-
- //下面的很多方法已经过时了,因为getBlockSize等方法的返回值都是int类型,如果设备较大,返回的blockSize数值可能超过int类型的范围,导致溢出。
- //改为使用最新的getBlockSizeLong等方法返回为long类型数据即可。由于,只有<span style="line-height: 30.7999992370605px;">4.3以上版本的API才支持这些方法。</span><span style="line-height: 2.2em;">因此,最好做一下判断。</span>
复制代码 运行结果:
Android的文件访问权限是从Linux继承来的。
第一个字母:如果是d,表示文件夹;如果是-,表示文件;如果是l,表示快捷方式。
三组rwx(r(read),w(write),x(exeute,执行))表示三种不同用户的权限。
在Android中,每个应用,都是一个独立的用户。也就是说,创建一个应用,就是创建了一个新的用户。删除一个应用,就是删除了一个用户。
第一组rwx:描述文件拥有者(owner)对文件的权限。例如,上图中的data/cn.itcast.rwinrom/cache/info.txt文件的创建者就是拥有者,也就是cn.itcast.rwinrom应用程序。
第二组rwx:描述与文件拥有者同一用户组(grouper)的用户对文件的权限。默认情况,各个应用程序彼此是独立的用户。可以手动设置同组用户,不过只有系统应用为了方便才会设置同组用户,我们不用管。
第三组rwx:描述其他用户(other)对文件的权限。其他应用程序就可以称为某一个应用程序的其他用户。
res\layout\activity_main.xml
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".MainActivity"
- android:orientation="vertical">
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:onClick="click1"
- android:text="按钮一" />
-
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:onClick="click2"
- android:text="按钮二" />
- </LinearLayout>
复制代码
src/cn.itcast.permission/MainActivity.java - package cn.itcast.permission;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- public class MainActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- }
- public void click1(View v){
-
- //Android中提供的openFileOutput方法可以直接获取FileOutputStream,文件会被写在内部文件空间中(data/data/报名文件夹/files/)
- try {
- //MODE_PRIVATE表示拥有者和同组用户可以读写,其他用户无法访问
- FileOutputStream fos = openFileOutput("info1.txt", MODE_PRIVATE);
- fos.write("haha".getBytes());
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public void click2(View v){
-
- try {
- //MODE_WORLD_READABLE表示任何用户都对其可读,MODE_WORLD_WRITEABLE表示任何用户都对其可写
- FileOutputStream fos = openFileOutput("info2.txt", MODE_WORLD_READABLE|MODE_WORLD_WRITEABLE);
- fos.write("hehe,你来读我啊".getBytes());
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
复制代码
创建新的名为“其他用户”的应用程序,代码如下:
res\layout\activity_main.xml
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- tools:context=".MainActivity" >
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="读取"
- android:onClick="click"/>
- </RelativeLayout>
复制代码
src/cn.itcast.other/MainActivity.java - package cn.itcast.other;
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.Toast;
- public class MainActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- }
-
- public void click(View v){
-
- File file = new File("data/data/cn.itcast.permission/files","info2.txt");
-
- try {
- FileInputStream fis = new FileInputStream(file);
- BufferedReader br = new BufferedReader(new InputStreamReader(fis));
- Toast.makeText(this,br.readLine(),Toast.LENGTH_LONG).show();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
复制代码 运行结果:
点击按钮一、按钮二,生成文件info1.txt、info2.txt。
可以看到info1.txt为拥有者和同一用户组具备读写权限,info2.txt则为任何用户都具备读写权限。
运行“其他用户”应用程序,点击按钮,可以看到读取info2.txt文件成功。
在真实开发中,类似于账号及密码保存功能等持久化保存比较零散、简单数据的情况使用SharedPerferences比较方便,它是以键值对的方式将数据存储进xml文件中。
示例:修改保存用户登录名,密码的案例,用SharedPreferences保存数据的方式实现。
src/cn.itcast.sharedpreference/MainActivity.java
- package cn.itcast.sharedpreference;
- import android.app.Activity;
- import android.content.SharedPreferences;
- import android.content.SharedPreferences.Editor;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.CheckBox;
- import android.widget.EditText;
- import android.widget.Toast;
- public class MainActivity extends Activity {
- private EditText et_name;
- private EditText et_pass;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- et_name = (EditText) findViewById(R.id.et_name);
- et_pass = (EditText) findViewById(R.id.et_pass);
-
- readAccount();
- }
- public void login(View v){
-
- String name = et_name.getText().toString();
- String pass = et_pass.getText().toString();
-
- CheckBox cb = (CheckBox) findViewById(R.id.cb);
- if(cb.isChecked()){
-
- //SharedPreferences是接口,通过getSharedPreferences方法获取对象,第一个参数为文件名,第二个参数控制访问权限。
- //在路径为data/data/包名文件夹/shared_prefs目录下保存生成的xml文件。
- SharedPreferences sp = getSharedPreferences("info", MODE_PRIVATE);
-
- //获取编辑器
- Editor ed = sp.edit();
- ed.putString("name", name);
- ed.putString("pass", pass);
- //提交
- ed.commit();
- }
- Toast.makeText(this, "登陆成功", Toast.LENGTH_LONG).show();
- }
-
- public void readAccount(){
-
- SharedPreferences sp = getSharedPreferences("info", MODE_PRIVATE);
-
- //第二个参数表示如果没有对应第一个参数的value值返回的默认值,这里设置为空字符串。
- String name = sp.getString("name", "");
- String pass = sp.getString("pass", "");
-
- et_name.setText(name);
- et_pass.setText(pass);
- }
- }
复制代码 运行结果:
点击“生成xml文件”按钮,可以看到成功生成了sms.xml文件。
上面拼接字符串的方法过于麻烦,Android中有一个xml序列化器可以帮助我们解决这个问题。
示例:将上面示例中拼接字符串的方式修改为通过xml序列化器生成xml文件。
src/cn.itcast.createxml/MainActivity.java
- package cn.itcast.createxml;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.util.ArrayList;
- import java.util.List;
- import org.xmlpull.v1.XmlSerializer;
- import android.app.Activity;
- import android.os.Bundle;
- import android.util.Xml;
- import android.view.View;
- public class MainActivity extends Activity {
- List<Sms> smsList;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- smsList = new ArrayList<Sms>();
-
- for(int i = 0; i < 10; i++){
- Sms sms = new Sms("云鹤" + i + "号","138" + i + i,System.currentTimeMillis(),1);
- smsList.add(sms);
- }
- }
-
- public void click(View v){
-
- //获取xml序列化器
- XmlSerializer xs = Xml.newSerializer();
-
- try{
- //初始化,指定生成的xml文件路径和文件名
- File file = new File("sdcard/sms2.xml");
- FileOutputStream fos = new FileOutputStream(file);
- //编码:xml文件使用什么编码生成
- xs.setOutput(fos,"utf-8");
-
- //开始生成xml文件
- //生成头结点
- //两个参数分别用来定义XML文件的头部<?xml version="1.0" encoding="utf-8" standalone="yes"?>中encoding和standalone的值
- xs.startDocument("utf-8", true);
- //开始节点,第一个参数为名称空间,用不到,设置为null。
- xs.startTag(null, "smss");
-
- for(Sms sms : smsList){
- xs.startTag(null, "sms");
-
- xs.startTag(null, "body");
- xs.text(sms.getBody());
- xs.endTag(null, "body");
-
- xs.startTag(null, "address");
- xs.text(sms.getAddress());
- xs.endTag(null, "address");
-
- xs.startTag(null, "date");
- xs.text(sms.getDate() + "");
- xs.endTag(null, "date");
-
- xs.startTag(null, "type");
- xs.text(sms.getType() + "");
- xs.endTag(null, "type");
-
- xs.endTag(null, "sms");
- }
-
- //结束节点
- xs.endTag(null, "smss");
-
- //告知序列化器xml文件生成完毕
- xs.endDocument();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- }
复制代码 运行结果:
可以看到,生成xml文件成功。
使用xml序列化器生成xml文件还有一个好处,那就是会自动对特殊字符进行转义。
对上面示例中加上如下代码,其中“<”及“>”都是特殊字符。
可以看到成功生成xml文件,但是其中的特殊字符已经转义了。