课本学习
第三十九章 偏好
1.SharePreference
android.content.SharePreferences接口提供了用于排序和读取应用程序设置的方法。
SharedPreferences保存数据,其背后是用xml文件存放数据
一个简单的存储代码如下:
SharedPreferences sharedPreferences = getSharedPreferences("wujay", Context.MODE_PRIVATE); //私有数据
Editor editor = sharedPreferences.edit();//获取编辑器
editor.putString("name", "wujaycode");
editor.putInt("age", 4);
editor.commit();//提交修改
生成的wujay.xml文件内容如下:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="name">wujaycode</string>
<int name="age" value="4" />
</map>
2.Preference API
使用Android Preference API来创建一个用户界面
主要类android.preference.Preference子类包括:
- CheckBoxPreference
- EditTextPreference
- ListPreference
- DialogPreference
3.使用Prefence
Android.Manifest.xml文件
AndroidManifest.xml 是每个android程序中必须的文件。它位于整个项目的根目录,描述了package中暴露的组件(activities, services, 等等),他们各自的实现类,各种能被处理的数据和启动位置。 除了能声明程序中的Activities, ContentProviders, Services, 和Intent Receivers,还能指定permissions和instrumentation(安全控制和测试)
元素:在所有的元素中只有
和 是必需的,且只能出现一次。如果一个元素包含有其他子元素,必须通过子元素的属性来设置其值。处于同一层次的元素,这些元素的说明是没有顺序的。
属性:按照常理,所有的属性都是可选的,但是有些属性是必须设置的。那些真正可选的属性,即使不存在,其也有默认的数值项说明。除了根元素的属性,所有其他元素属性的名字都是以android:前缀的;
定义类名:所有的元素名都对应其在SDK中的类名,如果你自己定义类名,必须包含类的数据包名,如果类与application处于同一数据包中,可以直接简写为“.”;
多数值项:如果某个元素有超过一个数值,这个元素必须通过重复的方式来说明其某个属性具有多个数值项,且不能将多个数值项一次性说明在一个属性中;
资源项说明:当需要引用某个资源时,其采用如下格式:@[package :]type :name 。 例如 <activity android:icon=”@drawable/icon ” . . . >
字符串值:类似于其他语言,如果字符中包含有字符“”,则必须使用转义字符“”;
第一层():(属性)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.woody.test"
android:sharedUserId="string"
android:sharedUserLabel="string resource"
android:versionCode="integer"
android:versionName="string"
android:installLocation=["auto" | "internalOnly" | "preferExternal"] >
</manifest>
一个AndroidManifest.xml中必须含有一个Application标签,这个标签声明了每一个应用程序的组件及其属性(如icon,label,permission等)
<application android:allowClearUserData=["true" | "false"]
android:allowTaskReparenting=["true" | "false"]
android:backupAgent="string"
android:debuggable=["true" | "false"]
android:description="string resource"
android:enabled=["true" | "false"]
android:hasCode=["true" | "false"]
android:icon="drawable resource"
android:killAfterRestore=["true" | "false"]
android:label="string resource"
android:manageSpaceActivity="string"
android:name="string"
android:permission="string"
android:persistent=["true" | "false"]
android:process="string"
android:restoreAnyVersion=["true" | "false"]
android:taskAffinity="string"
android:theme="resource or theme" >
</application>
A、android:allowClearUserData('true' or 'false')
用户是否能选择自行清除数据,默认为true,程序管理器包含一个选择允许用户清除数据。当为true时,用户可自己清理用户数据,反之亦然
B、android:allowTaskReparenting('true' or 'false')
是否允许activity更换从属的任务,比如从短信息任务切换到浏览器任务
C、android:backupAgent
这也是Android2.2中的一个新特性,设置该APP的备份,属性值应该是一个完整的类名,如com.project.TestCase,此属性并没有默认值,并且类名必须得指定(就是个备份工具,将数据备份到云端的操作)
D、android:debuggable
这个从字面上就可以看出是什么作用的,当设置为true时,表明该APP在手机上可以被调试。默认为false,在false的情况下调试该APP,就会报以下错误:
Device XXX requires that applications explicitely declare themselves as debuggable in their manifest.
Application XXX does not have the attribute 'debuggable' set to TRUE in its manifest and cannot be debugged.
E、android:description/android:label
此两个属性都是为许可提供的,均为字符串资源,当用户去看许可列表(android:label)或者某个许可的详细信息(android:description)时,这些字符串资源就可以显示给用户。label应当尽量简短,之需要告知用户该许可是在保护什么功能就行。而description可以用于具体描述获取该许可的程序可以做哪些事情,实际上让用户可以知道如果他们同意程序获取该权限的话,该程序可以做什么。我们通常用两句话来描述许可,第一句描述该许可,第二句警告用户如果批准该权限会可能有什么不好的事情发生
F、android:enabled
Android系统是否能够实例化该应用程序的组件,如果为true,每个组件的enabled属性决定那个组件是否可以被 enabled。如果为false,它覆盖组件指定的值;所有组件都是disabled。
G、android:hasCode('true' or 'false')
表示此APP是否包含任何的代码,默认为true,若为false,则系统在运行组件时,不会去尝试加载任何的APP代码
一个应用程序自身不会含有任何的代码,除非内置组件类,比如Activity类,此类使用了AliasActivity类,当然这是个罕见的现象
(在Android2.3可以用标准C来开发应用程序,可在androidManifest.xml中将此属性设置为false,因为这个APP本身已经不含有任何的JAVA代码了)
H、android:icon
这个很简单,就是声明整个APP的图标,图片一般都放在drawable文件夹下
I、android:killAfterRestore
J、android:manageSpaceActivity
K、android:name
为应用程序所实现的Application子类的全名。当应用程序进程开始时,该类在所有应用程序组件之前被实例化。
若该类(比方androidMain类)是在声明的package下,则可以直接声明android:name="androidMain",但此类是在package下面的子包的话,就必须声明为全路径或android:name="package名称.子包名成.androidMain"
L、android:permission
设置许可名,这个属性若在
M、android:presistent
该应用程序是否应该在任何时候都保持运行状态,默认为false。因为应用程序通常不应该设置本标识,持续模式仅仅应该设置给某些系统应用程序才是有意义的。
N、android:process
应用程序运行的进程名,它的默认值为
O、android:restoreAnyVersion
同样也是android2.2的一个新特性,用来表明应用是否准备尝试恢复所有的备份,甚至该备份是比当前设备上更要新的版本,默认是false
P、android:taskAffinity
拥有相同的affinity的Activity理论上属于相同的Task,应用程序默认的affinity的名字是
Q、android:theme
是一个资源的风格,它定义了一个默认的主题风格给所有的activity,当然也可以在自己的theme里面去设置它,有点类似style。
第四十章 操作文件
1.概览
- 内部存储:注意内部存储不是内存。内部存储位于系统中很特殊的一个位置,如果你想将文件存储于内部存储中,那么文件默认只能被你的应用访问到,且一个应用所创建的所有文件都在和应用包名相同的目录下。也就是说应用创建于内部存储的文件,与这个应用是关联起来的。当一个应用卸载之后,内部存储中的这些文件也被删除。从技术上来讲如果你在创建内部存储文件的时候将文件属性设置成可读,其他app能够访问自己应用的数据,前提是他知道你这个应用的包名,如果一个文件的属性是私有(private),那么即使知道包名其他应用也无法访问。 内部存储空间十分有限,因而显得可贵,另外,它也是系统本身和系统应用程序主要的数据存储所在地,一旦内部存储空间耗尽,手机也就无法使用了。所以对于内部存储空间,我们要尽量避免使用。Shared Preferences和SQLite数据库都是存储在内部存储空间上的。内部存储一般用Context来获取和操作。
- 外部存储:2.外部存储:
最容易混淆的是外部存储,如果说pc上也要区分出外部存储和内部存储的话,那么自带的硬盘算是内部存储,U盘或者移动硬盘算是外部存储,因此我们很容易带着这样的理解去看待安卓手机,认为机身固有存储是内部存储,而扩展的T卡是外部存储。比如我们任务16GB版本的Nexus 4有16G的内部存储,普通消费者可以这样理解,但是安卓的编程中不能,这16GB仍然是外部存储。所有的安卓设备都有外部存储和内部存储,这两个名称来源于安卓的早期设备,那个时候的设备内部存储确实是固定的,而外部存储确实是可以像U盘一样移动的。但是在后来的设备中,很多中高端机器都将自己的机身存储扩展到了8G以上,他们将存储在概念上分成了"内部internal" 和"外部external" 两部分,但其实都在手机内部。所以不管安卓手机是否有可移动的sdcard,他们总是有外部存储和内部存储。最关键的是,我们都是通过相同的api来访问可移动的sdcard或者手机自带的存储(外部存储)。
2.创建一个Notes应用程序
FileDemo1应用程序是一个简单的应用,用于管理备忘。
有两个活动MainActivity和AddNoteActivity
应用程序的AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.filedemo1"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.filedemo1.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category
android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name="com.example.filedemo1.AddNoteActivity"
android:label="@string/title_activity_add_note" >
</activity>
</application>
</manifest>
主活动的活动类MainActvity
package com.example.filedemo1;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity {
private String selectedItem;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView) findViewById(
R.id.listView1);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
listView.setOnItemClickListener(
new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView,
View view, int position, long id) {
readNote(position);
}
});
}
@Override
public void onResume() {
super.onResume();
refreshList();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.action_add:
startActivity(new Intent(this,
AddNoteActivity.class));
return true;
case R.id.action_delete:
deleteNote();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void refreshList() {
ListView listView = (ListView) findViewById(
R.id.listView1);
String[] titles = fileList();
ArrayAdapter<String> arrayAdapter =
new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_activated_1,
titles);
listView.setAdapter(arrayAdapter);
}
private void readNote(int position) {
String[] titles = fileList();
if (titles.length > position) {
selectedItem = titles[position];
File dir = getFilesDir();
File file = new File(dir, selectedItem);
FileReader fileReader = null;
BufferedReader bufferedReader = null;
try {
fileReader = new FileReader(file);
bufferedReader = new BufferedReader(fileReader);
StringBuilder sb = new StringBuilder();
String line = bufferedReader.readLine();
while (line != null) {
sb.append(line);
line = bufferedReader.readLine();
}
((TextView) findViewById(R.id.textView1)).
setText(sb.toString());
} catch (IOException e) {
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
}
}
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e) {
}
}
}
}
private void deleteNote() {
if (selectedItem != null) {
deleteFile(selectedItem);
selectedItem = null;
((TextView) findViewById(R.id.textView1)).setText("");
refreshList();
}
}
}
可以使用一个Cursor来实现ListView的自动刷新
3.访问公共存储
KeyValue类:保存了一对字符串,用来将选择的键和Environment类中定义的目录进行配对
ListView还有一个监听器,用来监听其OnltemClick事件,当其中目录被选中时候调用ListDir方法。
第四十一章
1.Database API
1)SQLiteOpenHelper类:帮助创建数据库和表
提供构造方法,调用自己的超类,传入context和数据名称。
覆盖OnCreate方法和onUpgrade方法
public SubClassOfSQLiteOpenHelper(Context context) {
super(context,
"mydatabase", // database name
null,
1 // db version
);
}
初次访问一个表必须调用onCreate方法,应该在SQLLiteDatebase上调用exeSQL方法,传入SQL语句。
2)SQLiteDatabase类
Android提供了一个名为 SQLiteDatabase的类(SQLiteOpenHelper 类中的 getWritableDatabase()和getReadableDatabase()方法返回这个类的对象)。SQLiteDatabase类封装了一些操作数据库的API,使用该类可以完成对数据进行添加(Create)、查询(Retrieve)、更新(Update)和删除(Delete)操作(这些操作简称为CRUD)。
execSQL()方法可以执行insert、delete、update和CREATE TABLE之类有更改行为的SQL语句;rawQuery()方法用于执行select语句。
3)Cursor接口
在SQLiteDatabase上调用qyery方法将返回一个Cuesor。提供了对数据库查询所返回结果的读和写访问。
将Cursor移动到一个数据行,通过调用Cursor的getInt、getFloat、getLong、getString、getShort或getDouble方法传入索引,,从一行中读取列。
遇到的问题
查询Random的时候出现了这种情况
项目学习
菜单的使用:使用xml定义Menu
菜单资源文件必须放在res/menu目录中。菜单资源文件必须使用