A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始





~爱上海,爱黑马~




Android基础

    布局介绍

    相对布局(RelativeLayout)

    特点:
    相对布局所有组件可以叠加在一起;各个组件的布局是独立的,互不影响;所有组件的默认位置都是在左上角(顶部、左部对齐)。

    属性:
    android:layout_toRightOf               在指定控件的右边
    android:layout_toLeftOf                 在指定控件的左边
    android:layout_above                     在指定控件的上边
    android:layout_below                     在指定控件的下边
    android:layout_alignBaseline          跟指定控件水平对齐
    android:layout_alignLeft                 跟指定控件左对齐
    android:layout_alignRight              跟指定控件右对齐
    android:layout_alignTop                 跟指定控件顶部对齐
    android:layout_alignBottom           跟指定控件底部对齐
    android:layout_alignParentLeft       是否跟父元素左对齐
    android:layout_alignParentTop        是否跟父元素顶部对齐
    android:layout_alignParentRight      是否跟父元素右对齐
    android:layout_alignParentBottom  是否跟父元素底部对齐
    android:layout_centerVertical           在父元素中垂直居中
    android:layout_centerHorizontal      在父元素中水平居中
    android:layout_centerInParent         在父元素中居中   

    示例1:   

    res\layout\activity_main.xml
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     tools:context=".MainActivity" >

  6.     <!-- android:layout_alignParentRight="true"表示与父元素右对齐(这里,父元素指的就是RelativeLayout,而RelativeLayout占满了整个屏幕) -->
  7.     <TextView
  8.         android:layout_width="wrap_content"
  9.         android:layout_height="wrap_content"
  10.         android:text="第一个"
  11.         android:layout_alignParentRight="true"/>
  12.    
  13.     <!-- android:layout_alignParentBottom="true"表示与父元素底部对齐(这里,父元素指的就是RelativeLayout,而RelativeLayout占满了整个屏幕) -->
  14.     <TextView
  15.         android:layout_width="wrap_content"
  16.         android:layout_height="wrap_content"
  17.         android:text="第二个"
  18.         android:layout_alignParentBottom="true"/>
  19.    
  20.     <!-- android:layout_centerVertical="true"表示在父元素中垂直居中(这里,父元素指的就是RelativeLayout,而RelativeLayout占满了整个屏幕) -->
  21.     <TextView
  22.         android:layout_width="wrap_content"
  23.         android:layout_height="wrap_content"
  24.         android:text="第三个"
  25.         android:layout_centerVertical="true"
  26.         />
  27.    
  28.     <!-- android:layout_centerHorizontal="true"表示在父元素中水平居中(这里,父元素指的就是RelativeLayout,而RelativeLayout占满了整个屏幕) -->
  29.     <TextView
  30.         android:layout_width="wrap_content"
  31.         android:layout_height="wrap_content"
  32.         android:text="第四个"
  33.         android:layout_centerHorizontal="true"
  34.         />
  35.    
  36.     <!-- android:layout_centerInParent="true"表示在父元素中水平垂直都居中(这里,父元素指的就是RelativeLayout,而RelativeLayout占满了整个屏幕) -->
  37.     <TextView
  38.         android:layout_width="wrap_content"
  39.         android:layout_height="wrap_content"
  40.         android:text="第五个"
  41.         android:layout_centerInParent="true"
  42.         />
  43. </RelativeLayout>
复制代码
    运行结果:



    示例2:

    res\layout\activity_main.xml
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     tools:context=".MainActivity" >

  6.     <TextView
  7.         android:id="@+id/tv1"
  8.         android:layout_width="wrap_content"
  9.         android:layout_height="wrap_content"
  10.         android:text="第一一一一个" />
  11.    
  12.     <!-- android:layout_alignRight="true"表示与指定组件右对齐。 -->
  13.     <!-- @+id/就是为组件添加id,@id就是通过id引用组件 -->
  14.     <TextView
  15.         android:layout_width="wrap_content"
  16.         android:layout_height="wrap_content"
  17.         android:text="第二个"
  18.         android:layout_centerVertical="true"
  19.         android:layout_alignRight="@id/tv1"
  20.         />
  21.    
  22.     <!-- 如果同时使用android:layout_alignRight="true",android:layout_alignLeft="true",组件就会被拉伸 -->
  23.     <TextView
  24.         android:layout_width="wrap_content"
  25.         android:layout_height="wrap_content"
  26.         android:text="第三个"
  27.         android:layout_alignParentBottom="true"
  28.         android:layout_alignRight="@id/tv1"
  29.         android:layout_alignLeft="@id/tv1"
  30.         />
  31. </RelativeLayout>
复制代码
   运行结果:



    示例3:

    res\layout\activity_main.xml
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     tools:context=".MainActivity" >

  6.     <TextView
  7.         android:id="@+id/tv1"
  8.         android:layout_width="wrap_content"
  9.         android:layout_height="wrap_content"
  10.         android:text="第一个"
  11.         android:layout_centerHorizontal="true"/>
  12.    
  13.     <!-- android:layout_below="@id/tv1"表示在对应组件的下面 -->
  14.     <TextView
  15.         android:id="@+id/tv2"
  16.         android:layout_width="wrap_content"
  17.         android:layout_height="wrap_content"
  18.         android:text="第二个"
  19.         android:layout_below="@id/tv1"
  20.         />
  21.    
  22.     <!-- android:layout_above="@id/tv2"表示在对应组件的上面 -->
  23.     <TextView
  24.         android:layout_width="wrap_content"
  25.         android:layout_height="wrap_content"
  26.         android:text="第三个"
  27.         android:layout_above="@id/tv2"
  28.         />
  29.    
  30.     <!-- android:layout_toRightOf="@id/tv2"表示在对应组件的右边 -->
  31.     <TextView
  32.         android:layout_width="wrap_content"
  33.         android:layout_height="wrap_content"
  34.         android:text="第四个"
  35.         android:layout_toRightOf="@id/tv2"
  36.         />
  37. </RelativeLayout>
复制代码
    运行结果:



    练习:实现如下效果。



    代码:

    res\layout\activity_main.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <?xml version="1.0" encoding="utf-8"?>
  3. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  4.     android:layout_width="match_parent"
  5.     android:layout_height="match_parent" >
  6.    
  7.     <Button
  8.         android:id="@+id/center"
  9.         android:layout_width="wrap_content"
  10.         android:layout_height="wrap_content"
  11.         android:text="中间"
  12.         android:layout_centerInParent="true"/>
  13.    
  14.     <Button
  15.         android:layout_width="wrap_content"
  16.         android:layout_height="wrap_content"
  17.         android:text="上边"
  18.         android:layout_above="@id/center"
  19.         android:layout_alignLeft="@id/center"
  20.         android:layout_alignRight="@id/center"/>
  21.    
  22.     <Button
  23.         android:layout_width="wrap_content"
  24.         android:layout_height="wrap_content"
  25.         android:text="下边"
  26.         android:layout_below="@id/center"
  27.         android:layout_alignLeft="@id/center"
  28.         android:layout_alignRight="@id/center"/>
  29.    
  30.     <Button
  31.         android:layout_width="wrap_content"
  32.         android:layout_height="wrap_content"
  33.         android:text="左边"
  34.         android:layout_toLeftOf="@id/center"
  35.         android:layout_alignTop="@id/center"
  36.         android:layout_alignBottom="@id/center"
  37.         android:layout_alignParentLeft="true"/>
  38.    
  39.     <Button
  40.         android:layout_width="wrap_content"
  41.         android:layout_height="wrap_content"
  42.         android:text="右边"
  43.         android:layout_toRightOf="@id/center"
  44.         android:layout_alignTop="@id/center"
  45.         android:layout_alignBottom="@id/center"
  46.         android:layout_alignParentRight="true"/>
  47.    
  48.         <Button
  49.         android:layout_width="wrap_content"
  50.         android:layout_height="wrap_content"
  51.         android:text="左上"
  52.         android:layout_toLeftOf="@id/center"
  53.         android:layout_above="@id/center"
  54.         android:layout_alignParentLeft="true"/>
  55.         
  56.         <Button
  57.         android:layout_width="wrap_content"
  58.         android:layout_height="wrap_content"
  59.         android:text="左下"
  60.         android:layout_toLeftOf="@id/center"
  61.         android:layout_below="@id/center"
  62.         android:layout_alignParentLeft="true"/>
  63.         
  64.         <Button
  65.         android:layout_width="wrap_content"
  66.         android:layout_height="wrap_content"
  67.         android:text="右上"
  68.         android:layout_toRightOf="@id/center"
  69.         android:layout_above="@id/center"
  70.         android:layout_alignParentRight="true"/>
  71.         
  72.         <Button
  73.         android:layout_width="wrap_content"
  74.         android:layout_height="wrap_content"
  75.         android:text="右下"
  76.         android:layout_toRightOf="@id/center"
  77.         android:layout_below="@id/center"
  78.         android:layout_alignParentRight="true"/>
  79.    
  80. </RelativeLayout>
复制代码
   运行结果:



    帧布局(FrameLayout)

    特点:
    帧布局和相对布局一样,组件可以重叠;所有组件的默认位置是在左上角(顶部、左部对齐)。
   
    示例:

    res\layout\activity_main.xml
  1. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     tools:context=".MainActivity" >
  6.    
  7.     <!-- 帧布局中,修改组件的位置使用android:layout_gravity -->
  8.     <TextView
  9.         android:layout_width="wrap_content"
  10.         android:layout_height="wrap_content"
  11.         android:text="第一个"
  12.         android:layout_gravity="right"
  13.         />
  14.    
  15.     <!-- android:layout_gravity="bottom|right" ,表示组件的位置在右下角 -->
  16.     <TextView
  17.         android:layout_width="wrap_content"
  18.         android:layout_height="wrap_content"
  19.         android:text="第二个"
  20.         android:layout_gravity="bottom|right"
  21.         />
  22.    
  23.     <TextView
  24.         android:layout_width="wrap_content"
  25.         android:layout_height="wrap_content"
  26.         android:text="第三个"
  27.         android:layout_gravity="center"
  28.         />
  29.    
  30. </FrameLayout>
复制代码
   运行结果:



    练习:实现如下效果。


    代码:

    res\layout\activity_main.xml
  1. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     tools:context=".MainActivity" >
  6.    
  7.     <TextView
  8.         android:layout_width="240dp"
  9.         android:layout_height="240dp"
  10.         android:background="#ff0000"
  11.         android:layout_gravity="center"
  12.         />
  13.    
  14.     <TextView
  15.         android:layout_width="200dp"
  16.         android:layout_height="200dp"
  17.         android:background="#00ff00"
  18.         android:layout_gravity="center"
  19.         />
  20.    
  21.     <TextView
  22.         android:layout_width="160dp"
  23.         android:layout_height="160dp"
  24.         android:background="#0000ff"
  25.         android:layout_gravity="center"
  26.         />
  27.    
  28.     <TextView
  29.         android:layout_width="120dp"
  30.         android:layout_height="120dp"
  31.         android:background="#ffff00"
  32.         android:layout_gravity="center"
  33.         />
  34.    
  35.     <TextView
  36.         android:layout_width="80dp"
  37.         android:layout_height="80dp"
  38.         android:background="#ff00ff"
  39.         android:layout_gravity="center"
  40.         />
  41.    
  42.     <TextView
  43.         android:layout_width="40dp"
  44.         android:layout_height="40dp"
  45.         android:background="#ffffff"
  46.         android:layout_gravity="center"
  47.         />
  48.    
  49. </FrameLayout>
复制代码
   运行结果:


    表格布局(TableLayout)

    示例:

    res\layout\activity_main.xml
  1. <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     tools:context=".MainActivity" >
  6.    
  7.     <!-- 表格布局宽高可以不用设置,TableRow的宽度只能是match_parent,高度只能是wrap_content。调正宽度可以通过权重解决。-->
  8.     <TableRow>
  9.         
  10.         <TextView
  11.                 android:text="姓名:"/>
  12.         
  13.         <EditText
  14.             android:layout_weight="1"
  15.             />
  16.         
  17.     </TableRow>

  18.     <TableRow>
  19.         
  20.         <TextView
  21.                 android:text="年龄:"/>
  22.         
  23.         <EditText
  24.             android:layout_weight="1"
  25.             />
  26.         
  27.     </TableRow>
  28.    
  29. </TableLayout>
复制代码
   运行结果:


    绝对布局(AbsoluteLayout)

    绝对布局是直接使用android:layout_x,android:layout_y定位控件的坐标,做不了屏幕适配,所以不常使用。某些没有必要做屏幕适配的开发可以用绝对布局,例如:电视屏幕固定,做机顶盒开发。

    示例:

    res\layout\activity_main.xml
  1. <AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     tools:context=".MainActivity" >

  6.     <Button
  7.         android:id="@+id/button1"
  8.         android:layout_width="wrap_content"
  9.         android:layout_height="wrap_content"
  10.         android:layout_x="109dp"
  11.         android:layout_y="83dp"
  12.         android:text="Button" />
  13.    
  14. </AbsoluteLayout>
复制代码
   运行结果:


    LogCat

    Console只能显示Windows下运行的平台信息,例如:模拟器的运行状态(模拟器是运行在Windows平台上的程序)。但模拟器内的程序运行状态就不能显示在Console上了,因为这些程序不是运行到Windows上,这些信息会在LogCat中显示。

    LogCat分为5个等级,依次为:error(错误)、warn(情报)、info(信息)、debug(调试)、verbose(冗余)。



    示例:为LogCat添加过滤器,便于筛选信息。

    src/cn.itcast.logcat/MainActivity.java   
  1. package cn.itcast.logcat;

  2. import android.os.Bundle;
  3. import android.app.Activity;
  4. import android.util.Log;
  5. import android.view.Menu;

  6. public class MainActivity extends Activity {

  7.     @Override
  8.     protected void onCreate(Bundle savedInstanceState) {
  9.             
  10.         String tag = "黑马程序员";
  11.             
  12.         super.onCreate(savedInstanceState);
  13.         setContentView(R.layout.activity_main);
  14.         
  15.         System.out.println("云鹤,儿童节快乐");
  16.         
  17.         //tag表示标签,msg表示正文
  18.         //下面这种写法是在日志需要长期保留时使用。
  19.         Log.v(tag, "云鹤就业薪资13000");
  20.         Log.d(tag, "云鹤就业薪资13000");
  21.         Log.i(tag, "云鹤就业薪资13000");
  22.         Log.w(tag, "云鹤就业薪资13000");
  23.         Log.e(tag, "云鹤就业薪资13000");
  24.                                 
  25.    }
  26. }
复制代码
   运行结果:



    第一步:点击加号。



    第二步:填入过滤器设置信息。
   

    第三步:进行过滤。



    在内部存储中读写文件

    Android内存:
    RAM:运行内存,相当于电脑内存。关机,数据就会丢失。
    ROM:内部存储空间,Android系统必须的存储空间,持久化保持数据,相当于电脑的硬盘。
    SD卡/USB存储器(内置在手机内):外部存储空间,对于Android系统是可有可无的,相当于移动硬盘。
   
    内部存储路径:data/data/包名文件夹/,每个包名文件夹都是一个应用的专属空间。



    示例:

    res\layout\activity_main.xml
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     android:paddingBottom="@dimen/activity_vertical_margin"
  6.     android:paddingLeft="@dimen/activity_horizontal_margin"
  7.     android:paddingRight="@dimen/activity_horizontal_margin"
  8.     android:paddingTop="@dimen/activity_vertical_margin"
  9.     tools:context=".MainActivity"
  10.     android:orientation="vertical">

  11.     <EditText
  12.         android:id="@+id/et_name"
  13.         android:layout_width="match_parent"
  14.         android:layout_height="wrap_content"/>

  15.     <!-- android:inputType="textPassword"表示输入的是密码,显示时用密文代替 -->
  16.     <EditText
  17.         android:id="@+id/et_pass"
  18.         android:layout_width="match_parent"
  19.         android:layout_height="wrap_content"
  20.         android:inputType="textPassword"/>
  21.    
  22.     <RelativeLayout
  23.         android:layout_width="match_parent"
  24.         android:layout_height="wrap_content">
  25.         
  26.             <CheckBox
  27.                 android:id="@+id/cb"
  28.                 android:layout_width="wrap_content"
  29.                 android:layout_height="wrap_content"
  30.                 android:text="记住账号密码"
  31.                 android:layout_centerVertical="true"
  32.                 />
  33.             
  34.             <Button
  35.                 android:layout_width="wrap_content"
  36.                 android:layout_height="wrap_content"
  37.                 android:text="登陆"
  38.                 android:onClick="login"
  39.                 android:layout_alignParentRight="true"
  40.                 />
  41.             
  42.         </RelativeLayout>
  43.    
  44. </LinearLayout>
复制代码

    src/cn.itcast.rwinrom/MainActivity.java  
  1. package cn.itcast.rwinrom;

  2. import java.io.BufferedReader;
  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. import java.io.FileOutputStream;
  6. import java.io.InputStreamReader;

  7. import android.app.Activity;
  8. import android.os.Bundle;
  9. import android.view.View;
  10. import android.widget.CheckBox;
  11. import android.widget.EditText;
  12. import android.widget.Toast;

  13. public class MainActivity extends Activity {

  14.     private EditText et_name;
  15.     private EditText et_pass;

  16.     @Override
  17.     protected void onCreate(Bundle savedInstanceState) {
  18.         super.onCreate(savedInstanceState);
  19.         setContentView(R.layout.activity_main);
  20.         
  21.         et_name = (EditText) findViewById(R.id.et_name);
  22.         et_pass = (EditText) findViewById(R.id.et_pass);
  23.         
  24.         readAccount();
  25.     }

  26.     public void login(View v){
  27.             
  28.             //获取用户输入的数据
  29.             String name = et_name.getText().toString();
  30.             String pass = et_pass.getText().toString();
  31.             
  32.             CheckBox cb = (CheckBox) findViewById(R.id.cb);
  33.             if(cb.isChecked()){
  34.                     File file = new File("data/data/cn.itcast.rwinrom/info.txt");
  35.                     try{
  36.                             FileOutputStream fos = new FileOutputStream(file);
  37.                             fos.write((name + "##" + pass).getBytes());
  38.                             fos.close();
  39.                     }catch(Exception e){
  40.                             e.printStackTrace();
  41.                     }
  42.             }
  43.             //弹出吐司对话框
  44.             //Activity是Context的子类
  45.             //Toast.LENGTH_LONG表示显示5秒
  46.             //Toast.LENGTH_SHORT表示显示3秒
  47.             Toast.makeText(this, "登陆成功", Toast.LENGTH_LONG).show();
  48.     }
  49.    
  50.     public void readAccount(){
  51.             File file = new File("data/data/cn.itcast.rwinrom/info.txt");
  52.             if(file.exists()){
  53.                     try{
  54.                             FileInputStream fis = new FileInputStream(file);
  55.                             //把字节流转换成字符流
  56.                             BufferedReader br = new BufferedReader(new InputStreamReader(fis));
  57.                             String text = br.readLine();
  58.                             String[] s = text.split("##");
  59.                            
  60.                             et_name.setText(s[0]);
  61.                             et_pass.setText(s[1]);
  62.                         
  63.                             fis.close();
  64.                     }catch(Exception e){
  65.                             e.printStackTrace();
  66.                     }
  67.             }
  68.     }
  69. }
复制代码
   运行结果:

    1、在模拟器上运行应用程序,输入用户名、密码,勾上记住账号密码,点击登陆。可以看到弹出吐司,登陆成功。



    2、在Android设备文件目录下,可以看到成功生成info.txt文件,点击右上角的“pull a file from the device”按钮,将info.txt提取出来,保存到桌面。



    3、打开info.txt文件,可以看到成功存入数据。



    4、重新运行应用程序,可以看到读取数据成功,用户名、密码成功显示。



    P.S.
    1、点击返回键,会摧毁当前Activity,重新点击应用图标,会重新创建Activity。
    2、点击HOME键,只会将Activity放到后台去,重新点击图标,只是重新提取出来。
    所以,上面的应用程序,即使是第一次运行,输入用户名、密码,并且不勾选“记住账户密码”。如果此时点击HOME键,Activity消失。然后,再点击应用程序图标,竟然可以看到Activity显示出了用户名、密码!然而,这根本不是回显,Activity只是暂时放到后台,然后重新提取出来罢了。
    3、在内部存储空间中读写不需要任何权限!

    使用API获取内部存储空间的路径

    如果将上面应用程序的MainActivity类中的代码进行如下修改,可以看到后台报警告。原因是不能访问其他应用程序的专属空间,只能访问自己的。





    为了防止内部存储空间不小心写错,API提供了获取内部存储空间路径的方法。修改后,代码如下:

   



    运行结果,如下:



    P.S.
    getFilesDir方法所在的类为上下文包装类,ContextWrapper。



    并且,Activity就是ContextWrapper的子类。



    所谓的上下文就是一个应用环境全局信息的接口,也就是说,通过上下文的API可以拿到应用环境的全局信息,例如:包名、版本号、内部存储等信息。
    Toast.makeText(this,"登陆成功",0).show();语句中的this就是上下文,表示吐司需要显示在哪个上下文中。
    Button bt = new Button(this);语句中的this也是上下文,表示该组件创建出来之后,显示在哪个上下文中。

    谷歌的API还提供了另一个方法获取内部存储空间路径:getCacheDir(),它返回的路径为data/data/cn.itcast.rwinrom/cache,得到的是缓存路径,也就是cache文件夹路径。修改后,代码如下:
   


    运行结果,如下:


   
    区别:
    getFilesDir方法返回的路径中的files文件夹是持久化保存数据的。
    getCacheDir方法返回的路径中的Cache文件夹是保存缓存数据的。当设备内存可用存储空间比较少时,Cache中的文件可能会被系统删除。

    在外部存储中读写文件

    SD卡路径为storage/sdcard(4.3版本),之所以还存在根目录sdcard(2.3版本之前)及mnt/sdcard(2.3版本~4.3版本),是因为早期版本的sd卡路径正是在根目录,后期移到了mnt/sdcard,为了与低版本兼容,所以现在他们还存在,其实只是快捷方式而已,指向的路径依然是storage/sdcard。



    往SD卡中写数据需要权限。而从SD卡中读取数据在4.0版本以前是不需要权限,后来谷歌在Android系统中添加了保护SD卡的选项(如下图)。如果勾选了,那么在真机上是有效的(也就是说,模拟器上是无效的)。不过,一般情况下,不勾选。因为,很多应用程序并没有申请读取SD卡的权限,一旦勾上,很多应用程序将无法读取SD卡。因此,为了向下兼容,一般不勾。



    示例:

    将上面“在内部存储中读取文件”中示例的MainActivity类中代码做一下修改,如下。





    为读写SD卡添加权限(读SD卡权限可加可不加):





    运行结果:





    检测SD卡状态

    很多手机厂商都修改了SD卡路径,因此,很多手机SD卡的路径不是storage/sdcard。但是,sdcard的快捷方式基本上都是存在的,并且指向真实的SD卡路径。因此,访问SD卡路径,可以通过获取SD卡快捷方式的方法。当然,也可以调用API中提供的相应方法获取SD卡路径:Environment.getExternalStorageDirectory()。

    P.S.
    外部存储空间对于手机来说并不一定是必须的。所以,在使用前,一定要做确认手机的SD卡是否存在。可以通过Environment.getExternalStorageState()确定SD卡的状态,此方法的常见返回值说明如下:
    MEDIA_REMOVED:sd卡被拔出。
    MEDIA_UNMOUNTED:sd卡未挂载(4.0版本以前,手机可以通过点击settings-->Storage-->Storage settings-->Unmounted SD card,使SD卡未挂载)。
    MEDIA_CHECKING:sd卡正在准备。
    MEDIA_MOUNTED:sd卡已挂载,当前可用。
    MEDIA_READ_ONLY:sd卡挂载可用,但是只读。

    示例:

    将上面“在内部存储中读取文件”中示例的MainActivity类中代码做一下修改,如下。



    运行结果:

    由于在4.0版本之前才有手动使SD卡未挂载的功能,这里使用2.3.3版本测试。

    首先,Unmounted SD card,观察效果,可以看到提示:sd不可用。




   
    然后,mounted SD card,观察效果,成功保存用户名、密码信息。





    P.S.
    当有多个模拟器运行时,想要观察某一个模拟器的文件目录,只需要在Devices选项卡中点击那个模拟器,即可在File Explorer选项卡中看到那个模拟器的文件目录。


    获取SD卡剩余容量

    当用户做下载等操作时,SD卡的空间可能不足,所以需要提前获取SD卡剩余容量,给予用户提示信息。

    在Android系统中,可以查看SD卡剩余容量,点击Setting-->Storage。



    sdk文件夹中的sources文件夹中的源码是Android jar包的源码,Android系统源码则不同,一定要区分开。如下图。



    其中,packages/apps路径为Android系统级应用程序所在的目录,可以看到settings应用程序。



    查看settings应用程序的源码

    1、导入settings应用程序到eclipse中。

         ①点击File-->New-->Other....。



        ②点击Android下的Android Project from Existing Code-->Next。



        ③点击Root Directory右侧的Browse...按钮,找到settings应用程序所在的目录,点击确定。



        ④下图中的tests为测试settings的应用程序,不勾。


        ⑤导入成功。



    P.S.
    之所以会报错,是因为普通应用开发是无法访问系统级API的(settings工程导入eclipse就成为了一个普通应用开发项目)。

    2、查找实现查看SD卡剩余空间的源码。

        ①通过搜索关键字“Available space”开始查找。



        ②通过eclipse的“File Search”在整个工作空间中搜索“Available space”。

   

        ③查找到以后,双击。





        ④再搜索“memory_available”。





        ⑤再搜索“memory_sd_avail”。





        ⑥再在本文件内搜索“MEMORY_SD_AVAIL”。



        再在本文件内搜索“mSdAvail”,可以看到,已经查找到了该段代码。



    3、解析源码。

        所有存储设备都会被划分成若干个区块,存储设备的总容量 = 每个区块大小 * 区块总数量。



        其中的formatSize函数实际上就是将得出的字节数,转换成MB、GB、TB及PB显示给用户。



    示例:我们自己写程序获取SD卡剩余容量。

    res\layout\activity_main.xml
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     android:paddingBottom="@dimen/activity_vertical_margin"
  6.     android:paddingLeft="@dimen/activity_horizontal_margin"
  7.     android:paddingRight="@dimen/activity_horizontal_margin"
  8.     android:paddingTop="@dimen/activity_vertical_margin"
  9.     tools:context=".MainActivity" >

  10.     <TextView
  11.         android:id="@+id/tv"
  12.         android:layout_width="wrap_content"
  13.         android:layout_height="wrap_content"
  14.         android:text="@string/hello_world" />

  15. </RelativeLayout>
复制代码

    src/cn.itcast.getsdavail/MainActivity.java  
  1. package cn.itcast.getsdavail;

  2. import java.io.File;

  3. import android.os.Build;
  4. import android.os.Bundle;
  5. import android.os.Environment;
  6. import android.os.StatFs;
  7. import android.app.Activity;
  8. import android.text.format.Formatter;
  9. import android.view.Menu;
  10. import android.widget.TextView;

  11. public class MainActivity extends Activity {

  12.     @Override
  13.     protected void onCreate(Bundle savedInstanceState) {
  14.         super.onCreate(savedInstanceState);
  15.         setContentView(R.layout.activity_main);
  16.         
  17.         File path = Environment.getExternalStorageDirectory();
  18.         StatFs stat = new StatFs(path.getPath());
  19.         
  20.         long blockSize;
  21.         long availableBlocks;
  22.         
  23.         //下面的很多方法已经过时了,因为getBlockSize等方法的返回值都是int类型,如果设备较大,返回的blockSize数值可能超过int类型的范围,导致溢出。
  24.         //改为使用最新的getBlockSizeLong等方法返回为long类型数据即可。由于,只有<span style="line-height: 30.7999992370605px;">4.3以上版本的API才支持这些方法。</span><span style="line-height: 2.2em;">因此,最好做一下判断。</span>
复制代码
   运行结果:




    文件访问权限

    Android的文件访问权限是从Linux继承来的。



    drwxrwxrwx:
    第一个字母:如果是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
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     tools:context=".MainActivity"
  6.     android:orientation="vertical">

  7.     <Button
  8.         android:layout_width="wrap_content"
  9.         android:layout_height="wrap_content"
  10.         android:onClick="click1"
  11.         android:text="按钮一" />
  12.    
  13.     <Button
  14.         android:layout_width="wrap_content"
  15.         android:layout_height="wrap_content"
  16.         android:onClick="click2"
  17.         android:text="按钮二" />

  18. </LinearLayout>
复制代码

    src/cn.itcast.permission/MainActivity.java  
  1. package cn.itcast.permission;

  2. import java.io.FileNotFoundException;
  3. import java.io.FileOutputStream;

  4. import android.app.Activity;
  5. import android.os.Bundle;
  6. import android.view.View;

  7. public class MainActivity extends Activity {

  8.         @Override
  9.         protected void onCreate(Bundle savedInstanceState) {
  10.                 super.onCreate(savedInstanceState);
  11.                 setContentView(R.layout.activity_main);
  12.         }

  13.     public void click1(View v){
  14.             
  15.             //Android中提供的openFileOutput方法可以直接获取FileOutputStream,文件会被写在内部文件空间中(data/data/报名文件夹/files/)
  16.             try {
  17.                         //MODE_PRIVATE表示拥有者和同组用户可以读写,其他用户无法访问
  18.                         FileOutputStream fos = openFileOutput("info1.txt", MODE_PRIVATE);
  19.                         fos.write("haha".getBytes());
  20.                 } catch (Exception e) {
  21.                         e.printStackTrace();
  22.                 }
  23.     }
  24.    
  25.     public void click2(View v){
  26.             
  27.             try {
  28.                         //MODE_WORLD_READABLE表示任何用户都对其可读,MODE_WORLD_WRITEABLE表示任何用户都对其可写
  29.                         FileOutputStream fos = openFileOutput("info2.txt", MODE_WORLD_READABLE|MODE_WORLD_WRITEABLE);
  30.                         fos.write("hehe,你来读我啊".getBytes());
  31.                 } catch (Exception e) {
  32.                         e.printStackTrace();
  33.                 }        
  34.     }
  35. }
复制代码

    创建新的名为“其他用户”的应用程序,代码如下:



    res\layout\activity_main.xml
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     android:paddingBottom="@dimen/activity_vertical_margin"
  6.     android:paddingLeft="@dimen/activity_horizontal_margin"
  7.     android:paddingRight="@dimen/activity_horizontal_margin"
  8.     android:paddingTop="@dimen/activity_vertical_margin"
  9.     tools:context=".MainActivity" >

  10.     <Button
  11.         android:layout_width="wrap_content"
  12.         android:layout_height="wrap_content"
  13.         android:text="读取"
  14.         android:onClick="click"/>

  15. </RelativeLayout>
复制代码

    src/cn.itcast.other/MainActivity.java  
  1. package cn.itcast.other;

  2. import java.io.BufferedReader;
  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. import java.io.FileNotFoundException;
  6. import java.io.IOException;
  7. import java.io.InputStreamReader;

  8. import android.app.Activity;
  9. import android.os.Bundle;
  10. import android.view.View;
  11. import android.widget.Toast;

  12. public class MainActivity extends Activity {

  13.         @Override
  14.         protected void onCreate(Bundle savedInstanceState) {
  15.                 super.onCreate(savedInstanceState);
  16.                 setContentView(R.layout.activity_main);
  17.         }
  18.         
  19.         public void click(View v){
  20.                
  21.                 File file = new File("data/data/cn.itcast.permission/files","info2.txt");
  22.                
  23.                 try {
  24.                         FileInputStream fis = new FileInputStream(file);
  25.                         BufferedReader br = new BufferedReader(new InputStreamReader(fis));
  26.                         Toast.makeText(this,br.readLine(),Toast.LENGTH_LONG).show();
  27.                 } catch (Exception e) {
  28.                         e.printStackTrace();
  29.                 }
  30.         }
  31. }
复制代码
   运行结果:

    点击按钮一、按钮二,生成文件info1.txt、info2.txt。



    可以看到info1.txt为拥有者和同一用户组具备读写权限,info2.txt则为任何用户都具备读写权限。



    运行“其他用户”应用程序,点击按钮,可以看到读取info2.txt文件成功。





    SharedPreferences

    在真实开发中,类似于账号及密码保存功能等持久化保存比较零散、简单数据的情况使用SharedPerferences比较方便,它是以键值对的方式将数据存储进xml文件中。

    示例:修改保存用户登录名,密码的案例,用SharedPreferences保存数据的方式实现。

    src/cn.itcast.sharedpreference/MainActivity.java  
  1. package cn.itcast.sharedpreference;

  2. import android.app.Activity;
  3. import android.content.SharedPreferences;
  4. import android.content.SharedPreferences.Editor;
  5. import android.os.Bundle;
  6. import android.view.View;
  7. import android.widget.CheckBox;
  8. import android.widget.EditText;
  9. import android.widget.Toast;

  10. public class MainActivity extends Activity {

  11.     private EditText et_name;
  12.     private EditText et_pass;

  13.     @Override
  14.     protected void onCreate(Bundle savedInstanceState) {
  15.         super.onCreate(savedInstanceState);
  16.         setContentView(R.layout.activity_main);
  17.         
  18.         et_name = (EditText) findViewById(R.id.et_name);
  19.         et_pass = (EditText) findViewById(R.id.et_pass);
  20.             
  21.         readAccount();
  22.     }

  23.     public void login(View v){
  24.             
  25.             String name = et_name.getText().toString();
  26.             String pass = et_pass.getText().toString();
  27.             
  28.             CheckBox cb = (CheckBox) findViewById(R.id.cb);
  29.             if(cb.isChecked()){
  30.                
  31.                     //SharedPreferences是接口,通过getSharedPreferences方法获取对象,第一个参数为文件名,第二个参数控制访问权限。
  32.                     //在路径为data/data/包名文件夹/shared_prefs目录下保存生成的xml文件。
  33.                     SharedPreferences sp = getSharedPreferences("info", MODE_PRIVATE);
  34.                     
  35.                     //获取编辑器
  36.                     Editor ed = sp.edit();
  37.                     ed.putString("name", name);
  38.                     ed.putString("pass", pass);
  39.                     //提交
  40.                     ed.commit();
  41.             }
  42.             Toast.makeText(this, "登陆成功", Toast.LENGTH_LONG).show();
  43.     }
  44.    
  45.     public void readAccount(){
  46.             
  47.             SharedPreferences sp = getSharedPreferences("info", MODE_PRIVATE);
  48.    
  49.             //第二个参数表示如果没有对应第一个参数的value值返回的默认值,这里设置为空字符串。
  50.             String name = sp.getString("name", "");
  51.             String pass = sp.getString("pass", "");
  52.             
  53.             et_name.setText(name);
  54.             et_pass.setText(pass);
  55.     }
  56. }
复制代码
   运行结果:



    可以看到,数据成功保存到xml文件中。





    回显成功。



    生成xml文件

    虽然SharedPreferences可以实现保存数据到xml中,但是,对于类似于用户保存短信等Android应用程序来说还是不行的。例如,保存短信功能,需要保存内容、发送时间、接收人号码、短信类型(发送、接收)等等多种类型数据,尤其是数据组织结构比较复杂时,使用SharedPreferences会相当的麻烦。

    示例:通过xml方式保存短信。

    res\layout\activity_main.xml
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     android:paddingBottom="@dimen/activity_vertical_margin"
  6.     android:paddingLeft="@dimen/activity_horizontal_margin"
  7.     android:paddingRight="@dimen/activity_horizontal_margin"
  8.     android:paddingTop="@dimen/activity_vertical_margin"
  9.     tools:context=".MainActivity" >

  10.     <Button
  11.         android:layout_width="wrap_content"
  12.         android:layout_height="wrap_content"
  13.         android:text="生成xml文件"
  14.         android:onClick="click"
  15.         />

  16. </RelativeLayout>
复制代码

    src/cn.itcast.createxml/Sms.java
  1. package cn.itcast.createxml;

  2. public class Sms {

  3.         private String body;
  4.         private String address;
  5.         private long date;
  6.         private int type;
  7.         
  8.         public String getBody() {
  9.                 return body;
  10.         }
  11.         public void setBody(String body) {
  12.                 this.body = body;
  13.         }
  14.         public String getAddress() {
  15.                 return address;
  16.         }
  17.         public void setAddress(String address) {
  18.                 this.address = address;
  19.         }
  20.         public long getDate() {
  21.                 return date;
  22.         }
  23.         public void setDate(long date) {
  24.                 this.date = date;
  25.         }
  26.         public int getType() {
  27.                 return type;
  28.         }
  29.         public void setType(int type) {
  30.                 this.type = type;
  31.         }
  32.         
  33.         public Sms(String body, String address, long date, int type) {
  34.                 super();
  35.                 this.body = body;
  36.                 this.address = address;
  37.                 this.date = date;
  38.                 this.type = type;
  39.         }
  40. }
复制代码

    src/cn.itcast.createxml/MainActivity.java  
  1. package cn.itcast.createxml;

  2. import java.io.File;
  3. import java.io.FileNotFoundException;
  4. import java.io.FileOutputStream;
  5. import java.util.ArrayList;
  6. import java.util.List;

  7. import android.app.Activity;
  8. import android.os.Bundle;
  9. import android.view.View;

  10. public class MainActivity extends Activity {

  11.         List<Sms> smsList;
  12.         
  13.         @Override
  14.         protected void onCreate(Bundle savedInstanceState) {
  15.                 super.onCreate(savedInstanceState);
  16.                 setContentView(R.layout.activity_main);
  17.                
  18.                 smsList = new ArrayList<Sms>();
  19.                
  20.                 for(int i = 0; i < 10; i++){
  21.                         Sms sms = new Sms("云鹤" + i + "号","138" + i + i,System.currentTimeMillis(),1);
  22.                         smsList.add(sms);
  23.                 }
  24.         }
  25.         
  26.         public void click(View v){
  27.                
  28.                 StringBuffer sb = new StringBuffer();
  29.                
  30.                 sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
  31.                 sb.append("<smss>");
  32.                
  33.                 for(Sms sms : smsList){
  34.                         sb.append("<sms>");
  35.                         
  36.                         sb.append("<body>");
  37.                         sb.append(sms.getBody());
  38.                         sb.append("</body>");
  39.                         
  40.                         sb.append("<address>");
  41.                         sb.append(sms.getAddress());
  42.                         sb.append("</address>");
  43.                         
  44.                         sb.append("<date>");
  45.                         sb.append(sms.getDate());
  46.                         sb.append("</date>");
  47.                         
  48.                         sb.append("<type>");
  49.                         sb.append(sms.getType());
  50.                         sb.append("</type>");
  51.                         
  52.                         sb.append("</sms>");
  53.                 }
  54.                
  55.                 //备份数据的应用一般都存在外部存储空间中。因为,一旦应用程序被删,内部存储空间内的该应用程序就会被清除,而外部存储空间不会被清掉。
  56.                 File file = new File("sdcard/sms.xml");
  57.                
  58.                 try {
  59.                         FileOutputStream fos = new FileOutputStream(file);
  60.                         fos.write(sb.toString().getBytes());
  61.                         fos.close();
  62.                 } catch (Exception e) {
  63.                         e.printStackTrace();
  64.                 }
  65.         }
  66. }
复制代码
   运行结果:



    点击“生成xml文件”按钮,可以看到成功生成了sms.xml文件。





    xml序列化器

    上面拼接字符串的方法过于麻烦,Android中有一个xml序列化器可以帮助我们解决这个问题。

    示例:将上面示例中拼接字符串的方式修改为通过xml序列化器生成xml文件。

    src/cn.itcast.createxml/MainActivity.java  
  1. package cn.itcast.createxml;

  2. import java.io.File;
  3. import java.io.FileOutputStream;
  4. import java.util.ArrayList;
  5. import java.util.List;

  6. import org.xmlpull.v1.XmlSerializer;

  7. import android.app.Activity;
  8. import android.os.Bundle;
  9. import android.util.Xml;
  10. import android.view.View;

  11. public class MainActivity extends Activity {

  12.         List<Sms> smsList;
  13.         
  14.         @Override
  15.         protected void onCreate(Bundle savedInstanceState) {
  16.                 super.onCreate(savedInstanceState);
  17.                 setContentView(R.layout.activity_main);
  18.                
  19.                 smsList = new ArrayList<Sms>();
  20.                
  21.                 for(int i = 0; i < 10; i++){
  22.                         Sms sms = new Sms("云鹤" + i + "号","138" + i + i,System.currentTimeMillis(),1);
  23.                         smsList.add(sms);
  24.                 }
  25.         }
  26.         
  27.         public void click(View v){
  28.                
  29.                 //获取xml序列化器
  30.                 XmlSerializer xs = Xml.newSerializer();
  31.                
  32.                 try{
  33.                         //初始化,指定生成的xml文件路径和文件名
  34.                         File file = new File("sdcard/sms2.xml");
  35.                         FileOutputStream fos = new FileOutputStream(file);
  36.                         //编码:xml文件使用什么编码生成
  37.                         xs.setOutput(fos,"utf-8");
  38.                         
  39.                         //开始生成xml文件
  40.                         //生成头结点
  41.                         //两个参数分别用来定义XML文件的头部<?xml version="1.0" encoding="utf-8" standalone="yes"?>中encoding和standalone的值
  42.                         xs.startDocument("utf-8", true);
  43.                         //开始节点,第一个参数为名称空间,用不到,设置为null。
  44.                         xs.startTag(null, "smss");
  45.                         
  46.                         for(Sms sms : smsList){
  47.                                 xs.startTag(null, "sms");
  48.                                 
  49.                                 xs.startTag(null, "body");
  50.                                 xs.text(sms.getBody());
  51.                                 xs.endTag(null, "body");
  52.                                 
  53.                                 xs.startTag(null, "address");
  54.                                 xs.text(sms.getAddress());
  55.                                 xs.endTag(null, "address");
  56.                                 
  57.                                 xs.startTag(null, "date");
  58.                                 xs.text(sms.getDate() + "");
  59.                                 xs.endTag(null, "date");
  60.                                 
  61.                                 xs.startTag(null, "type");
  62.                                 xs.text(sms.getType() + "");
  63.                                 xs.endTag(null, "type");
  64.                                 
  65.                                 xs.endTag(null, "sms");
  66.                         }
  67.                         
  68.                         //结束节点
  69.                         xs.endTag(null, "smss");
  70.                         
  71.                         //告知序列化器xml文件生成完毕
  72.                         xs.endDocument();
  73.                 }catch(Exception e){
  74.                         e.printStackTrace();
  75.                 }
  76.         }
  77. }
复制代码
   运行结果:

    可以看到,生成xml文件成功。





    P.S.
    使用xml序列化器生成xml文件还有一个好处,那就是会自动对特殊字符进行转义。

    示例:

    对上面示例中加上如下代码,其中“<”及“>”都是特殊字符。



    运行结果:
   
    可以看到成功生成xml文件,但是其中的特殊字符已经转义了。





~END~



~爱上海,爱黑马~


135 个回复

倒序浏览
学习吧,学习了!!
回复 使用道具 举报
赞一个!
回复 使用道具 举报
做的挺不错的,真心学习了
回复 使用道具 举报
真心做出来的东西呀
回复 使用道具 举报
黑马真的乃是业界的一匹黑马呀,赞
回复 使用道具 举报
很好的笔记
回复 使用道具 举报
好屌!!阳哥威武~
回复 使用道具 举报
收藏收藏
回复 使用道具 举报
真的,这个笔记真是没谁了。
回复 使用道具 举报
不错不错,刚好可以学习
回复 使用道具 举报
不错不错哦。。。
回复 使用道具 举报
不错不错哦
回复 使用道具 举报
还停留在java基础阶段呢
回复 使用道具 举报
不错  加油很详细
回复 使用道具 举报
java基础刚开始学,感觉要学的真多
回复 使用道具 举报
java基础开学完了,感觉学的迷迷糊糊的!不知道能不能考上黑马,为自己加油吧!!
回复 使用道具 举报
加油加油一定能考得上
回复 使用道具 举报
生命是用来纪念的,而不是用来怀念的.加油.相信自己.
回复 使用道具 举报
我要为自己加油
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马