Android 应用开发

注意!由于文章图片是通过typora一键上传图片实现,该功能还存在bug,容易导致图片顺序混乱,文章(1 of 2)开头提供了原版文章的 pdf 资源下载,推荐下载 pdf 后观看,或评论区联系我获取其他方式的下载链接。

文章目录

  • Android 应用开发
    • 第6章 Intent
      • 1 Intent简介
        • Intent简介
      • 2 使用Intent启动Activity【显示与隐式】
        • 显示启动
        • 隐式启动
      • 3 Activity间数据传递
        • 总体图
        • 单向传递数据
        • 双向传递数据
    • 第7章 Android广播机制
      • 1 什么是广播
        • 概述
        • BroadcastReceiver
      • 2 系统广播
        • 概述
        • 系统广播示例1:手机关机时播放关机音乐
        • 示例2:监听拨打电话(去电)
      • 3 自定义广播
        • 主要步骤
        • 自定义广播示例(静态注册)
      • 附录:短信黑名单示例
        • 概述
        • MainActivity界面(activity_main.xml)
        • SMSReceiver代码
        • 获取短信说明
        • AndroidManifest.xml添加SMS权限
        • MainActivity主要代码
    • 第8章 Service
      • 1 什么是Service
      • 2 Service类型
        • Started启动的
        • Bound绑定的
        • Service生命周期
      • 3 本地服务示例
        • 概述
        • 准备工作
        • 创建MusicService
        • 主程序(主要代码)
        • 功能改进(自学)
      • 4 广播交互
    • 第9章 1+简单数据存储和访问(简单)(SharedPreference)
      • 0 简单数据存储
      • 1 简单存储
        • 概述
        • SharedPreferences
        • 示例
      • 2 文件存储
        • 概述
        • 内部存储
        • 外部存储
        • 资源文件
    • 第9章 2++数据存储和访问(SQLite示例)
      • 1 ListView显示数据库数据(ShowActivity)
        • ListView 2个关键点
      • 2 添加记录功能(InsertActivity)
      • 3 给ListView添加ContextMenu菜单:删除+编辑(UpdateActivity)
        • 主要步骤

第6章 Intent

1 Intent简介

解决的问题:如何启动其他的Activity并实现它们之间的单/双向通信

Intent简介

  1. Intent是一种组件之间消息传递机制,它是一个动作的完整描述:包含了动作产生组件、接收组件和传递的数据信息。

  2. Intent主要用途:启动Activity、Service,在Android系统上发布Broadcast消息。

2 使用Intent启动Activity【显示与隐式】

显示启动

  1. 概念:在Intent中指明要启动的Activity类。

  2. 示例:

隐式启动

  • 说明:

    • 无需指明具体启动哪一个Activity,而由Android系统根据Intent的动作和数据来决定启动哪一个Activity。

    • 例如:希望启动一个浏览器,却不知道具体应该启动哪一 个Activity,此时则可以使用Intent的隐式启动,由Android 系统决定启动哪一个Activity来接收这个Intent。

    • 隐式启动的可以是Android系统内置的Activity,也可是程序本身的Activity,还可是第三方应用程序的Activity。

  1. 隐式启动示例1:启动浏览器打开一个网址

  2. 隐式启动示例2:打开播放器播放音乐

    • 播放音乐例子在7.0报错问题的解决:

      • 报错:FileUriExposedException: …exposed beyond app throughIntent.getData()

      • 原因:按照Android N的要求,如果 file://格式的Uri的Intent离开应 用将导致 FileUriExposedException 异常。若要在应用间共享文件, 应发送content://格式的Uri,并授予Uri临时访问权限,实现此方法的 是FileProvider类。

      • 解决方法:不推荐

    • 常见的Intent动作

  3. 隐式启动示例3:程序拨打电话例子

    • 在AndroidManifest.xml添加权限:

      <uses-permission android:name="android.permission.CALL_PHONE" />
      
    • 核心程序代码:

      Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:18908643860"));
      startActivity(intent);
      
    • 权限申请 (6.0以后):代码见后

    • 添加v4依赖(在安卓开发中,添加 v4 依赖是为了使用 Android Support Library 中的类和方法。Android Support Library 是一组库,可帮助您在旧版 Android 平台上使用最新 API 功能。v4 库是其中的一个库,它包含了许多有用的类和方法,例如 Fragment、ViewPager、NotificationCompat 等等。),此处方法我觉得不会考

3 Activity间数据传递

总体图

单向传递数据

  1. A 利用Bundle给 B 传递数据:★★★

  2. 关于Bundle

    • Bundle类是一个存储和管理key-value值对的类,多应用于Activity之间相互传递值。

    • 用法示例:

    • Bundle类的一些方法:

      clear():清除此Bundle映射中的所有保存的数据。

      clone():克隆当前Bundle

      containsKey(String key):返回指定key的值

      getString(String key):返回指定key的字符

      isEmpty():如果这个捆绑映射为空,则返回true

      putString(String key, String value):插入一个给定key的字符串值

      remove(String key):移除指定key的值

  3. Intent类的putExtras()、getExtras()方法

    • putExtras(Bundle):往Intent中添加一个Bundle对象
    • getExtras():从Intent中取出Bundle对象
  4. 单向传递数据示例1 – 传递普通数据

  1. 单向传递数据示例2 – 传递对象数据

    • 针对前例,如何用一个user对象传递数据:

    • 关键点在于Bundle如何传递对象数据。

    • Bundle可以传递对象,但前提是这个对象需要序列化

      什么是序列化:序列化是一种用来处理对象流的机制, 以解决如网络传播、磁盘读写等对对象流读写操作时所引发的问题。

    • Bundle的putSerializable()方法,可以存储已经序列化的对象数据(仍然是Key-Value形式);

    • 接收数据时Bundle用getSerializable()方法,获得数据需要强制转化一下原来的对象类型。

    • 具体过程如下:

      (1)先将User类序列化(直接实现Serializable接口即可)

      (2)发送端:RegisterActivity主要代码

      (3)接收端:WelcomeActivity主要代码

双向传递数据

  1. 总图

  2. A ↔ B 工作原理

  1. B 返回数据给 A 的核心代码框架 ★★★

  1. 双向传递数据示例1:A_Activity输入两个数,B_Activity求和并返回值

    • A_Activity主要代码1

    • B_Activity主要代码

    • A_Activity主要代码2 – 关键事件onActivityResult

  2. 双向传递数据示例2 – 将DatePicker控件单独作为一个activity(自学)

    • MainActivity主要代码1

    • MainActivity主要代码2

    • CalendarActivity主要代码1

    • CalendarActivity主要代码2

第7章 Android广播机制

1 什么是广播

概述

  1. 在Android中,广播(Broadcast)是一种广泛运用在应用程序之间传输信息的机制。
  2. 广播消息实质就是将一个Intent对象用sendBroadcast方法 发送出去 (详见7.3节自定义广播)。
  3. 两种类型广播:
    • 系统广播:如系统启动完成了、拨打电话了、收到短信了、 手机没电了等系统发送的消息
    • 自定义广播:将自定义的消息广播给应用程序

BroadcastReceiver

  1. BroadcastReceiver是对发送出来的Broadcast进行过滤并响应的一类组件,是Android系统的四大组件之一。

  2. BroadcastReceiver一般要在AndroidManifest.xml中注册

2 系统广播

概述

  1. 系统广播就是由Android系统发出的广播。
  2. 如系统启动完成了、系统关闭了、拨打电话了、收到短信 了、手机没电了、新安装了一个应用程序、在耳机口上插 入耳机、设备内存不足、屏幕关闭等等。

系统广播示例1:手机关机时播放关机音乐

  1. 准备工作:新建一个新Module(名为TestBroadcast)

    • 在res文件夹下新建raw文件夹

    • 将音乐文件复制到raw文件夹中

  2. 创建广播接收器BroadcastReceiver

    • 生成的MyReceiver.java代码框架:

  3. 处理广播:在onReceive添加处理代码:

  4. 注册接收器:(静态注册)

    注册:告诉系统这个BroadcastReceiver要接收哪种广播消息(Intent-filter)

    在AndroidManifest.xml文件中添加注册信息(红色部分)

  5. 权限设置:有的广播需要权限支持,本例不需要

    如需添加权限,则在AndroidManifest.xml中添加,例如:

  6. 测试运行: 先运行一下MainActivity,将app安装到手机中(告诉系统有BroadcastReceiver);然后再锁屏,就有音乐放了。

  7. 部分系统广播

示例2:监听拨打电话(去电)

  1. 给Receiver添加接收拨打电话的广播

  2. 给app添加处理拨打电话的权限

    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
    
  3. 补充:AS 6.0以后的模拟器

  4. 修改Receiver代码

3 自定义广播

主要步骤

  1. 发送广播消息

    在广播发送端(如某个APP的Activity),把信息装入一个Intent对象(含一个自定义的消息标识串,值任意,能保证唯一性即可), 然后sendBroadcast(intent)把 Intent 广播出去。

  2. 接收广播

    接收端创建Broadcast Receiver

    • 静态注册:在AndroidManifest.xml中注册Receiver,添加intent-filter

    • 动态注册:代码实现注册

  3. 接收端处理广播消息:onReceive()方法

  4. 关于消息广播标识串:

    • 消息广播标识串,自定义值,具有唯一性即可

    • 这个标识在后面有3个地方要用:

      • 发送广播时:用于创建Intent对象,Intent intent = new Intent(“广播标识串”);
      • manifest中注册时用:作为BroadcastReceiver的intent-filter的action name值
      • 处理消息时:在onReceive()方法中作为消息类型的判断用
    • 通常也可以把标识串定义为符号常量,如:

      final String BROADCAST_ACTION_NAME = “如 wust.zz.mybroadcast";
      

自定义广播示例(静态注册)

  1. 总图

  2. 发送端app:MainActivity主要代码

  3. 接收端app:MyReceiver主要代码

  4. MyReceiver配置 (静态注册)

    AndroidManifest.xml文件:红色部分

  5. 补充:Android8.0自定义广播无法接收问题解决

    • 方法1:使用动态广播代替静态广播

    • 方法2:保留原来的静态广播,但intent但加入Component参数:

附录:短信黑名单示例

概述

  1. 监听SMS短信信息(SMS,Short Messaging Service)

    • 如果对方发送的短信包含“@echo”串,就自动回发“denyyou!”信息,并将该号码列为黑名单
  2. BroadcastReceiver采用动态注册

MainActivity界面(activity_main.xml)

<ToggleButtonandroid:id="@+id/toggleButton1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_marginLeft="74dp" android:layout_marginTop="44dp"android:text="监控SMS" android:textOff="SMS监控已关闭" android:textOn="SMS监控已开启" />

SMSReceiver代码

获取短信说明

AndroidManifest.xml添加SMS权限

<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />

MainActivity主要代码

第8章 Service

1 什么是Service

  1. Service是Android系统四大组件之一,它是一种长生命周期的,没有可视化界面,运行于后台的一种服务程序。

2 Service类型

Started启动的

  1. Started启动的:常用于应用程序内部

  2. Started形式是指当一个应用组件(如Activity)通过startService()方法 开启的服务。一旦开启,该服务就可以无限期地在后台运行,哪怕开启它的组件被销毁。

  3. 基本特点:

    • 在应用程序中定义service组件。

    • 服务通过调用startService(intent)启动,stopService(intent)结束。

    • 在服务内部可以调用stopSelf() 来自己停止。

    • 通常,开启的服务执行一个单独的操作且并不向调用者返回一个结果。

    • 无论调用了多少次startService(),只需调用一次stopService()来停止。

Bound绑定的

  1. Bound绑定的:用于应用程序之间
  2. Bound形式是指一个应用组件通过调用 bindService() 方法与服务绑定。调用 unbindService()关闭连接。
  3. Bound形式的服务一旦启用,调用者就与服务绑定在一起,调用者一旦退出,服务也就终止。
  4. 多个组件可以同时绑定到一个服务,但当全部绑定解除后,服务就被销毁

Service生命周期

3 本地服务示例

概述

  1. 示例图

  2. 主要步骤:

    • 准备工作
    • 创建MusicService
    • 主程序
    • 功能改进

准备工作

  1. 在res文件夹下新建raw文件夹

  2. 将音乐文件复制到raw文件夹中

创建MusicService

  • MusicService代码框架

  • MusicService代码

主程序(主要代码)

功能改进(自学)

  • 增加暂停、重播、结束(停止服务)功能

  • 思路:通过在Intent传递参数值给Service

    • 假设参数值:

      • 1 – 播放
      • 2 – 暂停
      • 3 – 重播
      • 0 – 结束(内部结束服务)
      • -1 – 退出(外部结束服务和Activity)
  • 主界面activity_main.xml

  • MainActivity主要代码

  • MusicService主要代码

4 广播交互

  • 在Activity中点击Button后启动Service

    public void onClick(View v) {Intent intent = new Intent(this, CounterService.class);intent.putExtra("counter", counter); //counter用来计数startService(intent);
    }
    
  • CounterService.java

    public class CounterService extends Service { int counter; @Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;} @Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// TODO Auto-generated method stubcounter = intent.getIntExtra("counter", 0);new Timer().schedule(new TimerTask() {@Overridepublic void run() {// TODO Auto-generated method stubIntent counterIntent = new Intent();counterIntent.putExtra("counter", counter);counterIntent.setAction("com.example.counter.COUNTER_ACTION");sendBroadcast(counterIntent);counter++;}}return START_STICKY;}
    }
    
  • 在Service的onStartCommand()中启动一个定时器,每隔1秒钟counter计数加1,通过广播发送将counter发送出去,在Activity中的CounterReceiver收到广播后取出counter,将counter通过handler 发送出去

    // 广播接收器,定义在Activity中
    class CounterReceiver extends BroadcastReceiver {Handler handler;CounterReceiver(Handler handler){this. handler = handler;}@Overridepublic void onReceive(Context context, Intent intent) {counter = intent.getIntExtra("counter", 0);handler.sendEmptyMessage(counter);}
    }
    //运行程序,点击按钮开始计时
    
  • 在Activity中通过Handler设置到Button上,Button要设计为Activity的全局量, 并在onCreat中初始化:

    CounterReceiver receiver;
    Button start;
    Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg){start. setText(String.valueOf (msg.what)) super.handleMessage(msg); }
    }
    
  • 在Activity的onCreat中

    Receiver = new CounterReceiver(handler)
    start = (Button)findViewById(R.id.start)
    
  • 示例图:

  • 在程序运行过程遇到一个问题,在这里说明一下

    • 广播类是在Activity里定义的,是Activity的内部类,这个内部类在使用静态注册的时候,会发生程序运行崩溃,原因是内部广播类如果使用静态注册,必须是静态内部类。
    • 但是如果是静态内部类,只能访问外部类的静态成员变量,所以内部广播类推荐使用动态注册方式。
    • 而且这类广播一般只在程序内部使用,没有必须在进程结束以后继续接收广播。
  • 通过广播实现Activity和Service的交互简单容易实现。

    • 缺点是发送不广播受系统制约,系统会优先发送系统级的广播,自定义的广播接收器可能会有延迟。
    • 在广播里也不能有耗时操作,否则会导致程序无响应。
  • Activity中动态注册receiver ,如放在onCreat中:

    IntentFilter filter = new IntentFilter();
    filter.addAction("com.example.counter.COUNTER_ACTION ");
    BroadcastReceiver receiver = new MyReceiver();
    registerReceiver( receiver , filter);
    
  • 此外Activity销毁的时候,注销(关闭)广播:

    unregisterReceiver(receiver);
    
  • 进一步学习:有关远程服务的创建和调用

    参考:

    • http://www.apkbus.com/android-131250-1-1.html
    • http://liangruijun.blog.51cto.com/3061169/653344/

第9章 1+简单数据存储和访问(简单)(SharedPreference)

0 简单数据存储

  1. 应用程序一般允许用户自己定义配置信息,如界面背景颜色、字体大小和字体颜色等。
  2. 使用SharedPreferences保存用户的自定义配置信息,并在程序启动时自动加载这些自定义的配置信息。

1 简单存储

概述

  1. 用户在界面上的输入的信息,在Activity关闭时进行保存。当应用程序重新开启时,保存信息将被读取出来,并重新呈现在用户界面上

SharedPreferences

  1. SharedPreferences是一种轻量级的数据保存方式。

    • 通过SharedPreferences可以将NVP(Name/Value Pair,名称/值对)保存在Android的文件系统中,而且SharedPreferences完全屏蔽的对文件系统的操作过程。
    • 开发人员仅是通过调用SharedPreferences对NVP进行保存和读取。
  2. SharedPreferences不仅能够保存数据,还能够实现不同应用程序间的数据共享

    • SharedPreferences支持三种访问模式

      • 私有(MODE_PRIVATE):仅有创建程序有权限对其进行读取或写入。
      • 全局读(MODE_WORLD_READABLE):不仅创建程序可以对其进行读取或写入,其他应用程序也读取操作的权限,但没有写入操作的权限。
      • 全局写(MODE_WORLD_WRITEABLE):创建程序和其他程序都可以对其进行写入操作,但没有读取的权限。
  3. 在使用SharedPreferences前,先定义SharedPreferences的访问模式。

    • 下面的代码将访问模式定义为私有模式:

      public static int MODE = MODE_PRIVATE;
      
    • 有的时候需要将SharedPreferences的访问模式设定为即可以全局读,也可以全局写,这样就需要将两种模式写成下面的方式:

      public static int MODE = Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE;
      
  4. 定义SharedPreferences的名称

    • 这个名称与在Android文件系统中保存的文件同名。因此,只要具有相同的SharedPreferences名称的NVP内容,都会保存在同一个文件中

      public static final String PREFERENCE_NAME = "SaveSetting";
      
    • 为了可以使用SharedPreferences,需要将访问模式和SharedPreferences名称作为参数,传递到getSharedPreferences()函数,并获取到SharedPreferences对象

      SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCE_NAME, MODE);
      
  5. 修改SharedPreferences

    • 在获取到SharedPreferences对象后,则可以通过SharedPreferences.Editor类对SharedPreferences进行修改,最后调用commit()函数保存修改内容。

    • SharedPreferences广泛支持各种基本数据类型,包括整型、布尔型、浮点型和长型等等。

      SharedPreferences.Editor editor = sharedPreferences.edit();
      editor.putString("Name", "Tom");
      editor.putInt("Age", 20);
      editor.putFloat("Height", 1.67);  //这里PPT没有float的内容,猜测是这样
      editor.commit();
      
  6. 读取SharedPreferences

    • 如果需要从已经保存的SharedPreferences中读取数据,同样是调用getSharedPreferences()函数,并在函数的第1个参数中指明需要访问的SharedPreferences名称,最后通过get<Type>()函数获取保存在SharedPreferences中的NVP。

      SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCE_NAME, MODE);
      String name = sharedPreferences.getString("Name","Default Name");
      int age = sharedPreferences.getInt("Age", 20);
      float height = sharedPreferences.getFloat("Height",);
      
      • get<Type>()函数的第1个参数是NVP的名称。
      • 第2个参数是在无法获取到数值的时候使用的缺省值。

示例

通过SimplePreferenceDemo示例介绍具体说明SharedPreferences的文件保存位置和保存格式。

  1. 下图是SimplePreferenceDemo示例的用户界面

    用户在界面上的输入的信息,将通过SharedPreferences在Activity关闭时进行保存。当应用程序重新开启时,保存在SharedPreferences的信息将被读取出来,并重新呈现在用户界面上。

  2. 文件信息

    • SimplePreferenceDemo示例运行后,通过FileExplorer查看/data/data下的数据,Android为每个应用程序建立了与包同名的目录,用来保存应用程序产生的数据,这些数据包括文件、SharedPreferences文件和数据库等。

    • SharedPreferences文件就保存在/data/data/<package name>/shared_prefs目录下。

    • 在本示例中,shared_prefs目录下生成了一个名为SaveSetting.xml的文件:

      • 这个文件就是保存SharedPreferences的文件,文件大小为170字节,在Linux下的权限为“-rw-rw-rw”

        在Linux系统中,文件权限分别描述了创建者、同组用户和其他用户对文件的操作限制。

        • x表示可执行,r表示可读,w表示可写,d表示目录,-表示普通文件。因此,“-rw-rw-rw”表示SaveSetting.xml可以被创建者、同组用户和其他用户进行读取和写入操作,但不可执行。
        • 产生这样的文件权限与程序人员设定的SharedPreferences的访问模式有关,“-rw-rw-rw”的权限是“全局读+全局写”的结果。
        • 如果将SharedPreferences的访问模式设置为私有,则文件权限将成为“-rw-rw —”,表示仅有创建者和同组用户具有读写文件的权限。
    • SaveSetting.xml文件是以XML格式保存的信息,内容如图如下

      <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
      <map><float name="Height" value="1.81" /><string name="Name">Tom</string><int name="Age" value="20" />
      </map>
      
  3. 具体功能与相关代码

    • SimplePreferenceDemo示例在onStart()函数中调用loadSharedPreferences()函数,读取保存在SharedPreferences中的姓名、年龄和身高信息,并显示在用户界面上。

      • 当Activity关闭时,在onStop()函数调用saveSharedPreferences(),保存界面上的信息

      • SimplePreferenceDemo.java的完整代码:

        package edu.hrbeu.SimplePreferenceDemo;import android.app.Activity;
        import android.content.Context;
        import android.content.SharedPreferences;
        import android.os.Bundle;
        import android.widget.EditText;public class SimplePreferenceDemo extends Activity {private EditText nameText;private EditText ageText;private EditText heightText;public static final String PREFERENCE_NAME = "SaveSetting";public static int MODE = Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);nameText = (EditText)findViewById(R.id.name);ageText = (EditText)findViewById(R.id.age);heightText = (EditText)findViewById(R.id.height);}@Overridepublic void onStart(){super.onStart();loadSharedPreferences();}@Overridepublic void onStop(){super.onStop();  saveSharedPreferences();}private void loadSharedPreferences(){SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCE_NAME, MODE);String name = sharedPreferences.getString("Name","Tom");int age = sharedPreferences.getInt("Age", 20);float height = sharedPreferences.getFloat("Height",);nameText.setText(name);ageText.setText(String.valueOf(age));heightText.setText(String.valueOf(height));      }private void saveSharedPreferences(){SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCE_NAME, MODE);SharedPreferences.Editor editor = sharedPreferences.edit();editor.putString("Name", nameText.getText().toString());editor.putInt("Age", Integer.parseInt(ageText.getText().toString()));editor.putFloat("Height", Float.parseFloat(heightText.getText().toString()));editor.commit();}
        }
        
    • 示例SharePreferenceDemo将说明如何读取其他应用程序保存的SharedPreferences数据。

      • 下图是SharePreferenceDemo示例的用户界面。

      • 示例将读取SimplePreferenceDemo示例保存的信息,并在程序启动时显示在用户界面上。

    • SharePreferenceDemo示例的核心代码

  4. 访问其他应用程序的SharedPreferences必须满足三个条件:

    • 共享者需要将SharedPreferences的访问模式设置为全局读或全局写。
    • 访问者需要知道共享者的包名称和SharedPreferences的名称,以通过Context获得SharedPreferences对象。
    • 访问者需要确切知道每个数据的名称和数据类型,用以正确读取数据。

2 文件存储

概述

  1. Android使用的是基于Linux的文件系统。
  2. 程序开发人员可以建立和访问程序自身的私有文件。
  3. 也可以访问保存在资源目录中的原始文件和XML文件。
  4. 还可以在SD卡等外部存储设备中保存文件。

内部存储

  1. 在内部存储器上进行文件写入和读取

  2. Android系统允许应用程序创建仅能够自身访问的私有文件,文件保存在设备的内部存储器上,在Linux系统下的/data/data/<package name>/files目录中。

  • Android系统不仅支持标准Java的IO类和方法,还提供了能够简化读写流式文件过程的函数。
  • 主要介绍的两个函数:
    • openFileOutput()
    • openFileInput()
  1. openFileOutput()函数

    • openFileOutput()函数为写入数据做准备而打开的应用程序私文件,如果指定的文件不存在,则创建一个新的文件。

    • openFileOutput()函数的语法格式如下:

      public FileOutputStream openFileOutput(String name, int mode)
      
      • 第1个参数是文件名称,这个参数不可以包含描述路径的斜杠。
      • 第2个参数是操作模式。
    • 函数的返回值是FileOutputStream类型。

    • Android系统支持四种文件操作模式:

    • 使用openFileOutput()函数建立新文件的示例代码如下:

      String FILE_NAME = "fileDemo.txt";  //定义了建立文件的名称fileDemo.txt
      FileOutputStream fos = openFileOutput(FILE_NAME,Context.MODE_PRIVATE)  //使用openFileOutput()函数以私有模式建立文件
      String text = “Some data”;
      fos.write(text.getBytes());  //调用write()函数将数据写入文件
      fos.flush();  //调用flush()函数将所有剩余的数据写入文件
      fos.close();  //调用close()函数关闭FileOutputStream
      
      • 为了提高文件系统的性能,一般调用write()函数时,如果写入的数据量较小,系统会把数据保存在数据缓冲区中,等数据量累积到一定程度时再一次性的写入文件中。
      • 由上可知,在调用close()函数关闭文件前,务必要调用flush()函数,将缓冲区内所有的数据写入文件。
  2. openFileInput()函数

    • openFileInput()函数为读取数据做准备而打开应用程序私文件。

    • openFileInput()函数的语法格式如下:

      public FileInputStream openFileInput (String name)
      
      • 第1个参数也是文件名称,同样不允许包含描述路径的斜杠。
    • 使用openFileInput ()函数打开已有文件的示例代码如下:

      String FILE_NAME = "fileDemo.txt";
      FileInputStream fis = openFileInput(FILE_NAME);byte[] readBytes = new byte[fis.available()];
      while(fis.read(readBytes) != -1){}
      
      • 上面的两部分代码在实际使用过程中会遇到错误提示,因为文件操作可能会遇到各种问题而最终导致操作失败,因此代码应该使用try/catch捕获可能产生的异常。
  3. InternalFileDemo示例用来演示在内部存储器上进行文件写入和读取。

    • InternalFileDemo示例用户界面如图:

    • InternalFileDemo示例的核心代码:

      OnClickListener writeButtonListener = new OnClickListener() { @Overridepublic void onClick(View v) {FileOutputStream fos = null;   try {if (appendBox.isChecked()){fos = openFileOutput(FILE_NAME,Context.MODE_APPEND);}else {fos = openFileOutput(FILE_NAME,Context.MODE_PRIVATE);}String text = entryText.getText().toString();fos.write(text.getBytes());labelView.setText("文件写入成功,写入长度:"+text.length());entryText.setText("");} catch (FileNotFoundException e) {e.printStackTrace();}catch (IOException e) {e.printStackTrace();}finally{if (fos != null){try {fos.flush();fos.close();} catch (IOException e) {e.printStackTrace();}}}}
      };
      OnClickListener readButtonListener = new OnClickListener() {
      @Overridepublic void onClick(View v) {displayView.setText("");FileInputStream fis = null;try {fis = openFileInput(FILE_NAME);if (fis.available() == 0){return;}byte[] readBytes = new byte[fis.available()];while(fis.read(readBytes) != -1){}String text = new String(readBytes);displayView.setText(text);labelView.setText("文件读取成功,文件长度:"+text.length());} catch (FileNotFoundException e) {e.printStackTrace();}catch (IOException e) {e.printStackTrace();}}
      };
      
      • 程序运行后,在/data/data/edu.hrbeu.InternalFileDemo/files/目录下,找到了新建立的fileDemo.txt文件。

      • fileDemo.txt文件:

        • fileDemo.txt从文件权限上进行分析,“-rw-rw—”表明文件仅允许文件创建者和同组用户读写,其他用户无权使用。
        • 文件的大小为9个字节,保存的数据为“Some data”

外部存储

  1. Android的外部存储设备指的是SD卡(Secure Digital Memory Card),是一种广泛使用于数码设备上的记忆卡。不是所有的Android手机都有SD卡,但Android系统提供了对SD卡的便捷的访问方法。

  2. SD卡适用于保存大尺寸的文件或者是一些无需设置访问权限的文件,可以保存录制的大容量的视频文件和音频文件等。

    • SD卡使用的是FAT(File Allocation Table)的文件系统,不支持访问模式和权限控制,但可以通过Linux文件系统的文件访问权限的控制保证文件的私密性。
    • Android模拟器支持SD卡,但模拟器中没有缺省的SD卡,开发人员须在模拟器中手工添加SD卡的映像文件。
  3. 使用<Android SDK>/tools目录下的mksdcard工具创建SD卡映像文件,命令如下:

    mksdcard -l SDCARD 256M E:\android\sdcard_file
    
    • 第1个参数-1表示后面的字符串是SD卡的标签,这个新建立的SD卡的标签是SDCARD。
    • 第2个参数256M表示SD卡的容量是256兆。
    • 最后一个参数表示SD卡映像文件的保存位置,上面的命令将映像保存在E:\android目录下sdcard_file文件中。在CMD中执行该命令后,则可在所指定的目录中找到生产的SD卡映像文件。
  4. 如果希望Android模拟器启动时能够自动加载指定的SD卡,还需要在模拟器的“运行设置”(Run Configurations)中添加SD卡加载命令。

    • SD卡加载命令中只要指明映像文件位置即可。

    • SD卡加载命令:

  5. 测试SD卡映像是否正确加载

    • 在模拟器启动后,使用FileExplorer向SD卡中随意上传一个文件,如果文件上传成功,则表明SD卡映像已经成功加载。

    • 向SD卡中成功上传了一个测试文件test.txt,文件显示在/sdcard目录下

  6. 编程访问SD卡

    • 首先需要检测系统的/sdcard目录是否可用。
    • 如果不可用,则说明设备中的SD卡已经被移除,在Android模拟器则表明SD卡映像没有被正确加载。
    • 如果可用,则直接通过使用标准的Java.io.File类进行访问。
  7. 将数据保存在SD卡

    • 通过“生产随机数列”按钮生产10个随机小数。
    • 通过“写入SD卡”按钮将生产的数据保存在SD卡的目录下。
    • SDcardFileDemo示例说明了如何将数据保存在SD卡。
  8. SDcardFileDemo示例

    • 用户界面

    • SDcardFileDemo示例运行后,在每次点击“写入SD卡”按钮后,都会在SD卡中生产一个新文件,文件名各不相同。

      • SD卡中生产的文件:

    • SDcardFileDemo示例的核心代码

资源文件

  1. 程序开发人员可以将程序开发阶段已经准备好的原始格式文件和XML文件分别存放在/res/raw和/res/xml目录下,供应用程序在运行时进行访问。

    • 原始格式文件可以是任何格式的文件,例如视频格式文件、音频格式文件、图像文件和数据文件等等,在应用程序编译和打包时,/res/raw目录下的所有文件都会保留原有格式不变。
    • /res/xml目录下的XML文件,一般用来保存格式化的数据,在应用程序编译和打包时会将XML文件转换为高效的二进制格式,应用程序运行时会以特殊的方式进行访问。
  2. ResourceFileDemo示例

    • ResourceFileDemo示例演示了如何在程序运行时访问资源文件。

      • 当用户点击“读取原始文件”按钮时,程序将读取/res/raw/raw_file.txt文件,并将内容显示在界面上。

      • 当用户点击“读取XML文件”按钮时,程序将读取/res/xml/people.xml文件,并将内容显示在界面上。

    • 读取原始格式文件,首先需要调用getResource()函数获得资源对象,然后通过调用资源对象的openRawResource()函数,以二进制流的形式打开指定的原始格式文件。在读取文件结束后,调用close()函数关闭文件流。

      • ResourceFileDemo示例中关于读取原始格式文件的核心代码如下:

        Resources resources = this.getResources();
        InputStream inputStream = null;
        try {inputStream = resources.openRawResource(R.raw.raw_file);    byte[] reader = new byte[inputStream.available()]; while (inputStream.read(reader) != -1) { }displayView.setText(new String(reader,"utf-8"));
        } catch (IOException e) {Log.e("ResourceFileDemo", e.getMessage(), e);
        } finally {if (inputStream != null) { try {inputStream.close(); } catch (IOException e) { } }
        }
        
        • 代码第8行的new String(reader,“utf-8”),表示以UTF-8的编码方式,从字节数组中实例化一个字符串。
      • 程序开发人员需要确定/res/raw/raw_file.txt文件使用的是UTF-8编码方式,否则程序运行时会产生乱码。确认的方法:

        • 右击raw_file.txt文件。

        • 选择“Properties”打开raw_file.txt文件的属性设置框。

        • 在Resource栏下的Text file encoding中,选择“Other:UTF-8”。

    • /res/xml目录下的XML文件会转换为一种高效的二进制格式

      • 如何在程序运行时读取/res/xml目录下的XML文件

        • 首先在/res/xml目录下创建一个名为people.xml的文件。
        • XML文件定义了多个<person>元素,每个<person>元素都包含三个属性name、age和height,分别表示姓名、年龄和身高。
      • /res/xml/people.xml文件代码如下:

        <people> <person name="李某某" age="21" height="1.81" /> <person name="王某某" age="25" height="1.76" /> <person name="张某某" age="20" height="1.69" />
        </people>
        
    • 读取XML格式文件,首先通过调用资源对象的getXml()函数,获取到XML解析器XmlPullParser。XmlPullParser是Android平台标准的XML解析器,这项技术来自一个开源的XML解析API项目XMLPULL。

      • ResourceFileDemo示例中关于读取XML文件的核心代码如下:

      • XmlPullParser的XML事件类型

第9章 2++数据存储和访问(SQLite示例)

1 ListView显示数据库数据(ShowActivity)

ListView 2个关键点

  1. 自定义layout布局;

  2. 使用SimpleCursorAdapter适配器填充:(用于显示数据库数据)

    该适配器允许将一个Cursor(查询结果集)的数据列绑定到ListView自定 义布局中的TextView 或 ImageView组件上(详见后面代码)

  3. 代码详解:

    • ListView自定义layout布局,新建一个名为listview.xml布局:

    • 使用SimpleCursorAdapter填充ListView,SimpleCursorAdapter基本方法:

    • ShowAcitvity的OnCreate()主要代码:

2 添加记录功能(InsertActivity)

  1. ShowActivity“添加”按钮

  2. InsertActivity“保存”按钮

  3. ShowActivity接收回传信息(下面代码与onCreate并列)

3 给ListView添加ContextMenu菜单:删除+编辑(UpdateActivity)

主要步骤

  1. 第1步:新建菜单资源

    • 在res下新建menu目录

    • 在menu目录下新建一个manage.xml文件,代码:

  2. 第2步:创建上下文菜单(下面代码放在ShowActivity中,与onCreate并列)

  3. 第3步:添加上下文菜单选中项方法(下面代码放在ShowActivity中,与onCreateContextMenu并列)

  4. 第4步:将上下文菜单注册到ListView上(完)(下面代码放在ShowActivity中onCreate中)

  5. 后续删除、修改操作分析:

    • 两个操作的关键点:

      • 如何得到选中行的id值以及其他字段值(name、age)。
      • 删除:根据id值作为删除记录的条件。
      • 修改:将id值及其他字段的值传到UpdateActivity显示和修改。
    • 关键点代码:

    • 具体代码:

      • 删除操作 delete(MenuItem item) 方法

      • 修改操作

        UpdateActivity:oncreat()代码

      • ShowActivity接收回传信息

Android 应用开发学习笔记(2 of 2,from hitwh)相关推荐

  1. Android底层开发学习笔记 第一天

    今天,开始学习Android底层的开发.(注:我是新手小白,纯粹学习笔记,大神们可以直接略过了) 第一部分 编译运行我的第一个Android system. 准备工作: 下载源码:包括u-boot源码 ...

  2. android NFC 开发学习笔记(1)

    由于工作需求,最近在研究android nfc开发,借鉴了很对大神的文章在此记录自己的学习过程: 大家学习android开发建议首选android开发文档,该文档在你下载的sdk中,路径:/sdk/d ...

  3. Android 应用开发学习笔记(1 of 2,from hitwh)

    Android 应用开发 注意!由于文章图片是通过typora一键上传图片实现,该功能还存在bug,容易导致图片顺序混乱,文章开头提供了原版文章的 pdf 资源下载,推荐下载 pdf 后观看,或评论区 ...

  4. Android应用开发学习笔记之事件处理

    作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz Android提供的事件处理机制分为两类:一是基于监听的事件处理:二是基于回调的事件处理.对于基于监听的事件处理,主 ...

  5. Android游戏开发学习笔记(三):视频的播放

    一.在命令行下输入mksdcard 512M c:\sdcard.img命令,创建sdcard镜像文件. 二.单击Eclipse的菜单命令"Window/Preferences", ...

  6. android游戏开发学习笔记三(学习书籍 Android游戏编程之从零开始)

    /**  * 画笔  *   * @author 岳振华  *   */ @SuppressWarnings("unused") public class PaintSruface ...

  7. Android深度探索(卷1)HAL与驱动开发学习笔记(8)

    Android深度探索(卷1)HAL与驱动开发学习笔记(8) 第八章 蜂鸣器驱动   L i n u x驱动的代码重用有很多种方法.可以采用标准C程序的方式.将要重用的代码放在其他的文件(在头文件中声 ...

  8. Android 开发学习笔记

    Android 开发学习笔记 Lesson1 (2.28) android之父: Andy Rubin(安迪 鲁宾) Lesson2 (3.3) android 的优点: 开放.网络接入自由.丰富的硬 ...

  9. IOS开发学习笔记(一)

    概述: iOS是苹果开发的手持设备操作系统(iPhone,iPad,iPod touch,iPad mini). 基于UNIX,层次架构:核心操作系统层(Core OS)-> 核心服务层(Cor ...

最新文章

  1. 【机器学习基础】数学推导+纯Python实现机器学习算法22:最大熵模型
  2. VTK:可视化算法之OfficeTube
  3. Java利用jacob实现文档格式转换
  4. Tip: char *和char*的区别
  5. 使用Mapnik生成地形图——thematicmapping.org译文(四)
  6. 系统学习机器学习之总结(三)--多标签分类问题
  7. 在JavaScript中仿真Java的enum
  8. 使用oledb读写excel出现“操作必须使用一个可更新的查询”的解决办法
  9. Origin8画图:将多个worksheet表画在同一张图
  10. 微信公众号与服务器ip,微信公众号服务器IP网段与实际IP不一致?无法通过微信公众号推送消息到自己的服务器...
  11. 翻出过去的一个多彩泡泡屏保特效(JS+CSS版)
  12. Android 11.0 12.0SystemUI修改状态栏电池图标样式为横屏显示
  13. JSHOP2学习1:环境配置(超详细教程)
  14. android 应用被系统回收,莫往Applicaotion存缓存/app被系统回收之后再打开发生了什么...
  15. 五种常见启发式算法求解TSP问题-总结篇
  16. python:shape和reshape函数基本讲解
  17. POJ 1950 Dessert DFS 搜索
  18. Java中tif转png,tif格式图片转换为gif、png、jpg格式(Java实战)
  19. mysql高级 tigger触发器 --[3]
  20. 怎样使用NetFlow分析网络异常流量一

热门文章

  1. 蜘蛛池对于SEO的作用
  2. HTML语言特殊字符对照表(ISO Latin-1字符集)
  3. html5视频播放器代码实例(含倍速、清晰度切换、续播)
  4. mui tap事件,mui.confirm弹窗出现两次
  5. 简单解释Ablation Study
  6. 桌面图标变成空白页如何处理?
  7. VIVADO仿真卡住(executing simulate step)
  8. 11. Python语言的核心编程 · 第十一章 Python语言的面向对象(上)
  9. 高级mysql数据库优化_MySQL数据库优化建议
  10. 一个屌丝程序员的青春(二二)