Android 应用开发学习笔记(2 of 2,from hitwh)
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简介
Intent是一种组件之间消息传递机制,它是一个动作的完整描述:包含了动作产生组件、接收组件和传递的数据信息。
Intent主要用途:启动Activity、Service,在Android系统上发布Broadcast消息。
2 使用Intent启动Activity【显示与隐式】
显示启动
概念:在Intent中指明要启动的Activity类。
示例:
隐式启动
说明:
无需指明具体启动哪一个Activity,而由Android系统根据Intent的动作和数据来决定启动哪一个Activity。
例如:希望启动一个浏览器,却不知道具体应该启动哪一 个Activity,此时则可以使用Intent的隐式启动,由Android 系统决定启动哪一个Activity来接收这个Intent。
隐式启动的可以是Android系统内置的Activity,也可是程序本身的Activity,还可是第三方应用程序的Activity。
隐式启动示例1:启动浏览器打开一个网址
隐式启动示例2:打开播放器播放音乐
播放音乐例子在7.0报错问题的解决:
报错:FileUriExposedException: …exposed beyond app throughIntent.getData()
原因:按照Android N的要求,如果 file://格式的Uri的Intent离开应 用将导致 FileUriExposedException 异常。若要在应用间共享文件, 应发送content://格式的Uri,并授予Uri临时访问权限,实现此方法的 是FileProvider类。
解决方法:不推荐
常见的Intent动作
隐式启动示例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间数据传递
总体图
单向传递数据
A 利用Bundle给 B 传递数据:★★★
关于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的值
Intent类的putExtras()、getExtras()方法
- putExtras(Bundle):往Intent中添加一个Bundle对象
- getExtras():从Intent中取出Bundle对象
单向传递数据示例1 – 传递普通数据
单向传递数据示例2 – 传递对象数据
针对前例,如何用一个user对象传递数据:
关键点在于Bundle如何传递对象数据。
Bundle可以传递对象,但前提是这个对象需要序列化。
什么是序列化:序列化是一种用来处理对象流的机制, 以解决如网络传播、磁盘读写等对对象流读写操作时所引发的问题。
Bundle的putSerializable()方法,可以存储已经序列化的对象数据(仍然是Key-Value形式);
接收数据时Bundle用getSerializable()方法,获得数据需要强制转化一下原来的对象类型。
具体过程如下:
(1)先将User类序列化(直接实现Serializable接口即可)
(2)发送端:RegisterActivity主要代码
(3)接收端:WelcomeActivity主要代码
双向传递数据
总图
A ↔ B 工作原理
- B 返回数据给 A 的核心代码框架 ★★★
双向传递数据示例1:A_Activity输入两个数,B_Activity求和并返回值
A_Activity主要代码1
B_Activity主要代码
A_Activity主要代码2 – 关键事件onActivityResult
双向传递数据示例2 – 将DatePicker控件单独作为一个activity(自学)
MainActivity主要代码1
MainActivity主要代码2
CalendarActivity主要代码1
CalendarActivity主要代码2
第7章 Android广播机制
1 什么是广播
概述
- 在Android中,广播(Broadcast)是一种广泛运用在应用程序之间传输信息的机制。
- 广播消息实质就是将一个Intent对象用sendBroadcast方法 发送出去 (详见7.3节自定义广播)。
- 两种类型广播:
- 系统广播:如系统启动完成了、拨打电话了、收到短信了、 手机没电了等系统发送的消息
- 自定义广播:将自定义的消息广播给应用程序
BroadcastReceiver
BroadcastReceiver是对发送出来的Broadcast进行过滤并响应的一类组件,是Android系统的四大组件之一。
BroadcastReceiver一般要在AndroidManifest.xml中注册
2 系统广播
概述
- 系统广播就是由Android系统发出的广播。
- 如系统启动完成了、系统关闭了、拨打电话了、收到短信 了、手机没电了、新安装了一个应用程序、在耳机口上插 入耳机、设备内存不足、屏幕关闭等等。
系统广播示例1:手机关机时播放关机音乐
准备工作:新建一个新Module(名为TestBroadcast)
在res文件夹下新建raw文件夹
将音乐文件复制到raw文件夹中
创建广播接收器BroadcastReceiver
生成的MyReceiver.java代码框架:
处理广播:在onReceive添加处理代码:
注册接收器:(静态注册)
注册:告诉系统这个BroadcastReceiver要接收哪种广播消息(Intent-filter)
在AndroidManifest.xml文件中添加注册信息(红色部分)
权限设置:有的广播需要权限支持,本例不需要。
如需添加权限,则在AndroidManifest.xml中添加,例如:
测试运行: 先运行一下MainActivity,将app安装到手机中(告诉系统有BroadcastReceiver);然后再锁屏,就有音乐放了。
部分系统广播
示例2:监听拨打电话(去电)
给Receiver添加接收拨打电话的广播
给app添加处理拨打电话的权限
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
补充:AS 6.0以后的模拟器
修改Receiver代码
3 自定义广播
主要步骤
发送广播消息
在广播发送端(如某个APP的Activity),把信息装入一个Intent对象(含一个自定义的消息标识串,值任意,能保证唯一性即可), 然后sendBroadcast(intent)把 Intent 广播出去。
接收广播
接收端创建Broadcast Receiver
静态注册:在AndroidManifest.xml中注册Receiver,添加intent-filter
动态注册:代码实现注册
接收端处理广播消息:onReceive()方法
关于消息广播标识串:
消息广播标识串,自定义值,具有唯一性即可
这个标识在后面有3个地方要用:
- 发送广播时:用于创建Intent对象,Intent intent = new Intent(“广播标识串”);
- manifest中注册时用:作为BroadcastReceiver的intent-filter的action name值
- 处理消息时:在onReceive()方法中作为消息类型的判断用
通常也可以把标识串定义为符号常量,如:
final String BROADCAST_ACTION_NAME = “如 wust.zz.mybroadcast";
自定义广播示例(静态注册)
总图
发送端app:MainActivity主要代码
接收端app:MyReceiver主要代码
MyReceiver配置 (静态注册)
AndroidManifest.xml文件:红色部分
补充:Android8.0自定义广播无法接收问题解决
方法1:使用动态广播代替静态广播
方法2:保留原来的静态广播,但intent但加入Component参数:
附录:短信黑名单示例
概述
监听SMS短信信息(SMS,Short Messaging Service)
- 如果对方发送的短信包含“@echo”串,就自动回发“denyyou!”信息,并将该号码列为黑名单
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
Service是Android系统四大组件之一,它是一种长生命周期的,没有可视化界面,运行于后台的一种服务程序。
2 Service类型
Started启动的
Started启动的:常用于应用程序内部
Started形式是指当一个应用组件(如Activity)通过startService()方法 开启的服务。一旦开启,该服务就可以无限期地在后台运行,哪怕开启它的组件被销毁。
基本特点:
在应用程序中定义service组件。
服务通过调用startService(intent)启动,stopService(intent)结束。
在服务内部可以调用stopSelf() 来自己停止。
通常,开启的服务执行一个单独的操作且并不向调用者返回一个结果。
无论调用了多少次startService(),只需调用一次stopService()来停止。
Bound绑定的
- Bound绑定的:用于应用程序之间
- Bound形式是指一个应用组件通过调用 bindService() 方法与服务绑定。调用 unbindService()关闭连接。
- Bound形式的服务一旦启用,调用者就与服务绑定在一起,调用者一旦退出,服务也就终止。
- 多个组件可以同时绑定到一个服务,但当全部绑定解除后,服务就被销毁
Service生命周期
3 本地服务示例
概述
示例图
主要步骤:
- 准备工作
- 创建MusicService
- 主程序
- 功能改进
准备工作
在res文件夹下新建raw文件夹
将音乐文件复制到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 简单数据存储
- 应用程序一般允许用户自己定义配置信息,如界面背景颜色、字体大小和字体颜色等。
- 使用SharedPreferences保存用户的自定义配置信息,并在程序启动时自动加载这些自定义的配置信息。
1 简单存储
概述
- 用户在界面上的输入的信息,在Activity关闭时进行保存。当应用程序重新开启时,保存信息将被读取出来,并重新呈现在用户界面上
SharedPreferences
SharedPreferences是一种轻量级的数据保存方式。
- 通过SharedPreferences可以将NVP(Name/Value Pair,名称/值对)保存在Android的文件系统中,而且SharedPreferences完全屏蔽的对文件系统的操作过程。
- 开发人员仅是通过调用SharedPreferences对NVP进行保存和读取。
SharedPreferences不仅能够保存数据,还能够实现不同应用程序间的数据共享
- SharedPreferences支持三种访问模式
- 私有(MODE_PRIVATE):仅有创建程序有权限对其进行读取或写入。
- 全局读(MODE_WORLD_READABLE):不仅创建程序可以对其进行读取或写入,其他应用程序也读取操作的权限,但没有写入操作的权限。
- 全局写(MODE_WORLD_WRITEABLE):创建程序和其他程序都可以对其进行写入操作,但没有读取的权限。
- SharedPreferences支持三种访问模式
在使用SharedPreferences前,先定义SharedPreferences的访问模式。
下面的代码将访问模式定义为私有模式:
public static int MODE = MODE_PRIVATE;
有的时候需要将SharedPreferences的访问模式设定为即可以全局读,也可以全局写,这样就需要将两种模式写成下面的方式:
public static int MODE = Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE;
定义SharedPreferences的名称
这个名称与在Android文件系统中保存的文件同名。因此,只要具有相同的SharedPreferences名称的NVP内容,都会保存在同一个文件中
public static final String PREFERENCE_NAME = "SaveSetting";
为了可以使用SharedPreferences,需要将访问模式和SharedPreferences名称作为参数,传递到getSharedPreferences()函数,并获取到SharedPreferences对象
SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCE_NAME, MODE);
修改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();
读取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的文件保存位置和保存格式。
下图是SimplePreferenceDemo示例的用户界面
用户在界面上的输入的信息,将通过SharedPreferences在Activity关闭时进行保存。当应用程序重新开启时,保存在SharedPreferences的信息将被读取出来,并重新呈现在用户界面上。
文件信息
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>
具体功能与相关代码
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示例的核心代码
访问其他应用程序的SharedPreferences必须满足三个条件:
- 共享者需要将SharedPreferences的访问模式设置为全局读或全局写。
- 访问者需要知道共享者的包名称和SharedPreferences的名称,以通过Context获得SharedPreferences对象。
- 访问者需要确切知道每个数据的名称和数据类型,用以正确读取数据。
2 文件存储
概述
- Android使用的是基于Linux的文件系统。
- 程序开发人员可以建立和访问程序自身的私有文件。
- 也可以访问保存在资源目录中的原始文件和XML文件。
- 还可以在SD卡等外部存储设备中保存文件。
内部存储
在内部存储器上进行文件写入和读取
Android系统允许应用程序创建仅能够自身访问的私有文件,文件保存在设备的内部存储器上,在Linux系统下的/data/data/<package name>/files目录中。
- Android系统不仅支持标准Java的IO类和方法,还提供了能够简化读写流式文件过程的函数。
- 主要介绍的两个函数:
- openFileOutput()
- openFileInput()
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()函数,将缓冲区内所有的数据写入文件。
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捕获可能产生的异常。
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”
外部存储
Android的外部存储设备指的是SD卡(Secure Digital Memory Card),是一种广泛使用于数码设备上的记忆卡。不是所有的Android手机都有SD卡,但Android系统提供了对SD卡的便捷的访问方法。
SD卡适用于保存大尺寸的文件或者是一些无需设置访问权限的文件,可以保存录制的大容量的视频文件和音频文件等。
- SD卡使用的是FAT(File Allocation Table)的文件系统,不支持访问模式和权限控制,但可以通过Linux文件系统的文件访问权限的控制保证文件的私密性。
- Android模拟器支持SD卡,但模拟器中没有缺省的SD卡,开发人员须在模拟器中手工添加SD卡的映像文件。
使用<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卡映像文件。
如果希望Android模拟器启动时能够自动加载指定的SD卡,还需要在模拟器的“运行设置”(Run Configurations)中添加SD卡加载命令。
SD卡加载命令中只要指明映像文件位置即可。
SD卡加载命令:
测试SD卡映像是否正确加载
在模拟器启动后,使用FileExplorer向SD卡中随意上传一个文件,如果文件上传成功,则表明SD卡映像已经成功加载。
向SD卡中成功上传了一个测试文件test.txt,文件显示在/sdcard目录下
编程访问SD卡
- 首先需要检测系统的/sdcard目录是否可用。
- 如果不可用,则说明设备中的SD卡已经被移除,在Android模拟器则表明SD卡映像没有被正确加载。
- 如果可用,则直接通过使用标准的Java.io.File类进行访问。
将数据保存在SD卡
- 通过“生产随机数列”按钮生产10个随机小数。
- 通过“写入SD卡”按钮将生产的数据保存在SD卡的目录下。
- SDcardFileDemo示例说明了如何将数据保存在SD卡。
SDcardFileDemo示例
用户界面
SDcardFileDemo示例运行后,在每次点击“写入SD卡”按钮后,都会在SD卡中生产一个新文件,文件名各不相同。
SD卡中生产的文件:
SDcardFileDemo示例的核心代码
资源文件
程序开发人员可以将程序开发阶段已经准备好的原始格式文件和XML文件分别存放在/res/raw和/res/xml目录下,供应用程序在运行时进行访问。
- 原始格式文件可以是任何格式的文件,例如视频格式文件、音频格式文件、图像文件和数据文件等等,在应用程序编译和打包时,/res/raw目录下的所有文件都会保留原有格式不变。
- /res/xml目录下的XML文件,一般用来保存格式化的数据,在应用程序编译和打包时会将XML文件转换为高效的二进制格式,应用程序运行时会以特殊的方式进行访问。
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个关键点
自定义layout布局;
使用SimpleCursorAdapter适配器填充:(用于显示数据库数据)
该适配器允许将一个Cursor(查询结果集)的数据列绑定到ListView自定 义布局中的TextView 或 ImageView组件上(详见后面代码)
代码详解:
ListView自定义layout布局,新建一个名为listview.xml布局:
使用SimpleCursorAdapter填充ListView,SimpleCursorAdapter基本方法:
ShowAcitvity的OnCreate()主要代码:
2 添加记录功能(InsertActivity)
ShowActivity“添加”按钮
InsertActivity“保存”按钮
ShowActivity接收回传信息(下面代码与onCreate并列)
3 给ListView添加ContextMenu菜单:删除+编辑(UpdateActivity)
主要步骤
第1步:新建菜单资源
在res下新建menu目录
在menu目录下新建一个manage.xml文件,代码:
第2步:创建上下文菜单(下面代码放在ShowActivity中,与onCreate并列)
第3步:添加上下文菜单选中项方法(下面代码放在ShowActivity中,与onCreateContextMenu并列)
第4步:将上下文菜单注册到ListView上(完)(下面代码放在ShowActivity中onCreate中)
后续删除、修改操作分析:
两个操作的关键点:
- 如何得到选中行的id值以及其他字段值(name、age)。
- 删除:根据id值作为删除记录的条件。
- 修改:将id值及其他字段的值传到UpdateActivity显示和修改。
关键点代码:
具体代码:
删除操作 delete(MenuItem item) 方法
修改操作
UpdateActivity:oncreat()代码
ShowActivity接收回传信息
Android 应用开发学习笔记(2 of 2,from hitwh)相关推荐
- Android底层开发学习笔记 第一天
今天,开始学习Android底层的开发.(注:我是新手小白,纯粹学习笔记,大神们可以直接略过了) 第一部分 编译运行我的第一个Android system. 准备工作: 下载源码:包括u-boot源码 ...
- android NFC 开发学习笔记(1)
由于工作需求,最近在研究android nfc开发,借鉴了很对大神的文章在此记录自己的学习过程: 大家学习android开发建议首选android开发文档,该文档在你下载的sdk中,路径:/sdk/d ...
- Android 应用开发学习笔记(1 of 2,from hitwh)
Android 应用开发 注意!由于文章图片是通过typora一键上传图片实现,该功能还存在bug,容易导致图片顺序混乱,文章开头提供了原版文章的 pdf 资源下载,推荐下载 pdf 后观看,或评论区 ...
- Android应用开发学习笔记之事件处理
作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz Android提供的事件处理机制分为两类:一是基于监听的事件处理:二是基于回调的事件处理.对于基于监听的事件处理,主 ...
- Android游戏开发学习笔记(三):视频的播放
一.在命令行下输入mksdcard 512M c:\sdcard.img命令,创建sdcard镜像文件. 二.单击Eclipse的菜单命令"Window/Preferences", ...
- android游戏开发学习笔记三(学习书籍 Android游戏编程之从零开始)
/** * 画笔 * * @author 岳振华 * */ @SuppressWarnings("unused") public class PaintSruface ...
- Android深度探索(卷1)HAL与驱动开发学习笔记(8)
Android深度探索(卷1)HAL与驱动开发学习笔记(8) 第八章 蜂鸣器驱动 L i n u x驱动的代码重用有很多种方法.可以采用标准C程序的方式.将要重用的代码放在其他的文件(在头文件中声 ...
- Android 开发学习笔记
Android 开发学习笔记 Lesson1 (2.28) android之父: Andy Rubin(安迪 鲁宾) Lesson2 (3.3) android 的优点: 开放.网络接入自由.丰富的硬 ...
- IOS开发学习笔记(一)
概述: iOS是苹果开发的手持设备操作系统(iPhone,iPad,iPod touch,iPad mini). 基于UNIX,层次架构:核心操作系统层(Core OS)-> 核心服务层(Cor ...
最新文章
- 【机器学习基础】数学推导+纯Python实现机器学习算法22:最大熵模型
- VTK:可视化算法之OfficeTube
- Java利用jacob实现文档格式转换
- Tip: char *和char*的区别
- 使用Mapnik生成地形图——thematicmapping.org译文(四)
- 系统学习机器学习之总结(三)--多标签分类问题
- 在JavaScript中仿真Java的enum
- 使用oledb读写excel出现“操作必须使用一个可更新的查询”的解决办法
- Origin8画图:将多个worksheet表画在同一张图
- 微信公众号与服务器ip,微信公众号服务器IP网段与实际IP不一致?无法通过微信公众号推送消息到自己的服务器...
- 翻出过去的一个多彩泡泡屏保特效(JS+CSS版)
- Android 11.0 12.0SystemUI修改状态栏电池图标样式为横屏显示
- JSHOP2学习1:环境配置(超详细教程)
- android 应用被系统回收,莫往Applicaotion存缓存/app被系统回收之后再打开发生了什么...
- 五种常见启发式算法求解TSP问题-总结篇
- python:shape和reshape函数基本讲解
- POJ 1950 Dessert DFS 搜索
- Java中tif转png,tif格式图片转换为gif、png、jpg格式(Java实战)
- mysql高级 tigger触发器 --[3]
- 怎样使用NetFlow分析网络异常流量一
热门文章
- 蜘蛛池对于SEO的作用
- HTML语言特殊字符对照表(ISO Latin-1字符集)
- html5视频播放器代码实例(含倍速、清晰度切换、续播)
- mui tap事件,mui.confirm弹窗出现两次
- 简单解释Ablation Study
- 桌面图标变成空白页如何处理?
- VIVADO仿真卡住(executing simulate step)
- 11. Python语言的核心编程 · 第十一章 Python语言的面向对象(上)
- 高级mysql数据库优化_MySQL数据库优化建议
- 一个屌丝程序员的青春(二二)