使用eclipse开发Android
目录
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。正文
一、构建Android开发环境
1.用eclipse做Android的开发
(1) 下载JDK的可执行文件并执行
(2) 下载adt的zip压缩包
(3) 下载较新的SDK并解压SDK
(4) 下载eclipse并运行,选择help->install new software->add->archive->下载完毕的adt压缩文件
(5) 去掉“contact all update sites during install to find required software”选项,提高安装速度
(6) 重启eclipse后选择SDK解压后的位置
(7) Windows系统利用上vt技术的话,AVD的反应速度要快很多:启动BOIS启动vt,在sdk\extras\intel\Hardware_Accelerated_Execution_Manager下安装intel加速器,在此基础上建立一个intel驱动的AVD并启动
(8) 创建新项目
2.用手机做虚拟设备
下面用的是SUMSUNG手机,这种办法只能看到当前应用的信息
(1)About phone->Software information
(2)连续点击Build number3次
(3)在Developer options中打开USB debugging,并选择适当设置
(4)用USB连接手机,就可以通过IDE选择这个手机做模拟设备,运行需要调试的应用
二、生命周期
程序在Android系统中从启动到终止的所有过程,程序不能控制自身的生命周期而受系统的调度和控制。
1.用于调度和控制的事件回调函数
onSaveInstanceStae()用于保存activity界面的临时信息、信息一般放在Bundle中,onRestoreInstanceState()用于程序被销毁时恢复临时信息、比如程序遇到锁屏或者被系统中断,但是它们都不是生命周期的时间回调函数。
onCreate() |
用于activity的初始化、创建连接、绑定数据等,是第一个被调用的函数 |
onStart() |
activity显示在屏幕上时被调用 |
onRestart() |
activity重新启动时调用、之后调用onResume()继续和用户交互 |
onResume() |
获取屏幕焦点、接收用户输入时被调用 |
onPause() |
程序被其他窗口覆盖,系统调用函数“暂停”程序、之后调用onSaveInstanceStae()保存临时信息 |
onStop() |
用户不可见时,进入停止对activity更新 |
onDestroy() |
程序调用finish()函数或者被系统终结的时候调用 |
2.参考的调用顺序
当用户离开当前页面又重新回到这个页面时,会调用onStart()、onStop()
3.软件测试方法
(1)日志点
比如Log.i(String TAG,String cnt);,还可以选.w、.e等不同的日志信息等级,查看日志的方法是在Logcat中建立过滤器,输入Filter Name、Tag的内容(即字符串TAG),选择日志的级别确定即可。
(2)应用程序提示
比如Toast.makeText(MainActivity.this, "服务未绑定", Toast.LENGTH_SHORT).show();
(3)DevTools
作为前两种办法的补充,如果前面的办法还不能分析出错误原因,再考虑DevTools提供的信息。
三、用户界面UI
1.MVC模型
模型、视图、控制器,控制器加工用户输入的数据、交给处理核心“模型”,最终由“模型”来更新视图。
2.界面控件
用eclipse的layout设计界面制作静态的UI,用java控制动态的内容、先声明一个控件变量然后用findViewById引用xml中的资源进行初始化。具体的函数可以查阅android的API文档。
控件的属性在设计界面中有,也可以查阅android的手册。
(1)显示和编辑字符的控件
TextView
设计界面中双击控件,可以进入控件的xml文件
<TextView android:id=”@+id/TextView0”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”TextView0”/>
EditText常用函数
getText().toString() |
获取文本内容 |
setText() |
设置文本内容 |
selectAll() |
选中全部 |
findFocus() |
获取输入的焦点 |
(2)按钮控件
Button、ImageButton
(3)提供选择的控件
CheckBox用于多选、RadioGroup和RadioButton用于单选。
常用函数
isChecked() |
控件是否被选中 |
(4)微调选框
Spinner是一个类似下拉列表的东西,因为可能有不同的选项、存在动态的内容,需要java写适配器将要显示的内容和底层的数据统一起来。一个可行的例子是:
//spinner初始化
spinner = (Spinner) findViewById(R.id.spinner1);
//要显示的数据
List<String> li=new ArrayList<String>();
li.add("cnt0");
li.add("cnt1");
li.add("cnt2");
li.add("cnt3");
//适配器初始化
ArrayAdapter<String> ad=new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,li);
//适配器样式
ad.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
//给spinner设置适配器ad
spinner.setAdapter(ad);
(5)垂直显示的列表控件
ListView中如果内容很多,就会出现滚动条;如果没有内容,将不显示控件。
(6)设置监听器
监听器属于控件的方法,将使用内部类、如果出现错误可能是没有加上View.,在android_api.chm中也有具体的说明。比如OnClickListener、
① 控件独占一个监听器
比如列表控件中给每个子项设置监听器,listView.setOnItemClickListener(new AdapterView.OnIOnItemClickListener(){…});
② 多个控件共享一个监听器
方法是定义一个监听器,然后用v.getId()区分各个控件写上需要的代码,最后控件绑定这个监听器。如果一种类型的控件多次出现,尽量用这种方法设置监听器,消除一些不必要的冗余,。
3.界面布局
布局之间可以相互嵌套,按常用的程度分为:
(1)线性布局
LinearLayout可以选择水平也可以选择垂直,还可以像html中table的行列组合使用、这样就灵活多了。
(2)相对布局
RelativeLayout使用相对的位置以适应不同的屏幕尺寸,灵活而且比较稳定。
(3)网格布局
和表格布局类似,但是网格布局中的元素可以占用多个网格,而表格布局中的元素不能跨行跨列。
(4)表格布局
TableLayout默认控件独占一行,TableRow默认控件尽量放在一行。
(5)绝对布局
在layout设计界面中已经找不到,但是在手动创建布局的xml文件的时候有这样一种布局,部件的位置像坐标一样严格的受到数值的控制、不同的设备上效果不一定好。
(6)帧布局
一种类似坐标的自由布局FrameLayout
4.菜单(操作栏,由菜单组成)
可以在onCreate函数中用getActionBar().hide();隐藏操作栏的菜单,也可以通过修改app的主题styles做到同样的效果
(1)菜单资源
在menu目录中用layout设计菜单、onCreateOptionsMenu函数中用getMenuInflater().inflate方法映射成Menu对象,之后在onOptionsItemSelected函数中写入动态交互的内容即可;也可以用纯代码的方式实现,比如:
一级菜单 |
menu.add(0, menu0, 0, "打印").setIcon(R.drawable.ic_launcher); |
多级菜单 |
menu.addSubMenu(0, menu0, 0, "新建").setIcon(R.drawable.ic_launcher); |
说明:menu0是int对象要提前用Menu.FIRST初始化 |
(2)快捷菜单
具有快捷菜单的元素,如果按住它超过两秒,就会启动它的快捷菜单;和菜单资源类似,不同的是需要重载onCreateContextMenu函数,最后对需要的元素注册快捷菜单,方法是registerForContextMenu。
5.Fragment可重用模块
把页面中可能重复使用的部分做成Fragment,在一个activity中调用、提高了代码的可重用性。
(1)Fragment生命中的事件回调函数
(2)使用方法
① layout设计界面中添加需要的Fragment、创建继承自Fragment的类
② 设计Fragment对应的xml界面
③ 重载Fragment类中的函数onCreateView、改写return inflater.inflate(R.layout.bfragment, container, false);即可。
6.事件监听
(1)键盘事件setOnKeyListener
监听器中的函数的返回值为true将阻止事件传递给界面元素,界面元素就不会更新;程序中和事件有关的变量,它的信息可以类的声明中找到。
(2)触摸事件setOnTouchListener
比较典型的函数 |
值的说明 |
函数的说明 |
getAction() |
ACTION_DOWN、ACTION_UP、ACTION_MOVE等 |
获取动作 |
getX()、getY() |
获取相对坐标,相对前一个位置 |
|
getRawX()、getRawY() |
获取绝对坐标 |
|
getPressure() |
触点的压力 |
|
getSize() |
触点的尺寸 |
|
getHistorical…() |
获取历史数据中的第几个数据 |
四、组件通信与广播
1.Intent
不论这些组件是否在一个应用程序中都可以用Intent进行通信,显式通信需要指明组件具体的类,隐式通信发出动作即可、信息的接收方由系统决定。
(1)显式通信,比如用Intent启动一个activity(这两个activity都已经在Manifest中注册):
Intent intent=new Intent(IntentDemoActivity.this,NewActivity.class);
startActivity(intent);
(2)隐式通信,由动作触发:
Internt intent=new Intent(Intent.ACTION_VIEW,Uri.parse(“http://cn.bing.com/”));
startActivity(intent);
动作 |
说明 |
ACTION_VIEW |
提供浏览的activity,Uri“http://...”表示网页地址、“tel:..”是电话号码 |
(3)获取子activity的返回值
父activity中设置子activity的标签,之后发送消息,比如:
SubActivity1就是一个用于区分不同子activity的标签
Intent intent=new Intent(MainActivity.this, Activity1.class);
startActivityForResult(intent,SubActivity1);
子activity封装Uri信息,并设置结果,比如:
finish()可有可无
Uri data=Uri.parse(editText.getText().toString());
Intent result=new Intent(null, data);
setResult(RESULT_OK, result);
finish();
父activity接收消息,需要重载函数onActivityResult:
函数的参数依次是标签、设置的结果标记、Uri数据;在函数中写需要的代码
2.Intent过滤器
这是隐式启动的匹配机制:当应用安装到Android系统的时候,会注册自己组件和Intent过滤器,这样系统就可以通过Intent过滤器映射每一个Intent请求到相应的组件上;可以在Manifest配置文件中、特定的组件下定义<intent-filter>节点,得到组件的Intent过滤器
(1)Intent过滤器的标签
标签 |
属性 |
说明 |
|
<action> |
android:name |
动作,VIEW视图、包名 |
|
<category> |
android:category |
分类,LAUNCHER启动时最先被显示、DEFAULT默认 |
|
<data> |
android:host |
数据 |
指定主机名 |
android:mimetype |
指定activity能处理的文档类型 |
||
android:path |
Uri路径 |
||
android:port |
端口号 |
||
android:scheme |
指定的协议 |
(2)使用Intent过滤器
如果一个activity的过滤器是这样定义的:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="schemodemo" android:host="edu.hrbeu" />
</intent-filter>
那么可以用Intent这样调用activity:
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("schemodemo://edu.hrbeu/"));
startActivity(intent);
2.广播
(1)发出信号
需要一个区别于其他全局消息的标志,可以是程序包的名称,之后发送键值对形式的信号:
Intent intent=new Intent("com.example.demo0");
intent.putExtra("key", editText.getText().toString());
sendBroadcast(intent);
(2)接收信号
①Manifest文件下添加receiver,并声明它的过滤器(可以接收的消息类型),比如:
<receiver android:name=".Activity1">
<intent-filter>
<action android:name="com.example.demo0"/>
</intent-filter>
</receiver>
②定义一个activity,比如是Activity1、它继承自BroadcastReceiver,之后重载onReceive函数用来处理接收到的数据:
String value=intent.getStringExtra("key");
Toast.makeText(context, value, Toast.LENGTH_SHORT).show();
五、后台服务
指的是没有界面且长时间在后台运行的应用功能,很典型的是Service服务组件,比如MP3播放器,界面关闭后音乐还在播放,这就需要用到Service,此外Service还可以用于进程间的通信。
1.java和CC++易混淆的语法
boolean是java中的布尔值 |
java类中的变量声明马上就可以初始化,这点和CC++不同 |
null相当于CC++中的NULL |
2.Service的生命周期
3.本地服务
(1)显式使用Service
① Manifest中注册Service:
<service android:name=".RandomService"></service>
② 定义一个activity继承自Service,可以在onStart函数中、也可以其他合理的地方写需要的功能
③ 显式调用、停止Service:
final Intent intent=new Intent(MainActivity.this, RandomService.class);
startService(intent);
stopService(intent);
(2)隐式使用Service
④ Manifest中注册Service,不同的是需要添加过滤器(声明可以接收的数据类型,甚至可以精确到Service类的名字):
<service android:name=".RandomService">
<intent-filter>
<action android:name="com.example.demo0"/>
</intent-filter>
</service>
⑤ 定义一个activity继承自Service,可以在onStart函数中、也可以其他合理的地方写需要的功能
⑥ 隐式调用、停止Service,隐式调用的时候发出动作action即可:
final Intent intent=new Intent("com.example.demo0");
startService(intent);
stopService(intent);
4.多线程
Android系统中如果一个线程处理的时间过长,会降低用户界面的响应速度、甚至使界面失去响应,将耗时的处理过程分解到子线程上是一个可行的解决办法。
(1)在主线程activity中定义Handle变量,用来接收服务线程Runable中时刻变化的数据:
static Handle handle;
public static void updateGUI(服务线程传入的新数据){
handle.post(refreshLabel);
}
static Runable refreshLabel=new Runable(){
@Override
public void run() {
// TODO Auto-generated method stub
用新数据更新UI界面
}
}
(2)Service中运用多线程:
⑦ 定义用于事务处理的线程:
Thread serviceThread;
Runnable backgroundWork = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
while (!Thread.interrupted()) {
//过程代码,用于提供服务
double randNum = Math.random();
MainActivity.updateGUI(randNum);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
⑧ onCreate函数初始化这个线程:
serviceThread = new Thread(null, backgroundWork, "serviceThread");
⑨ onStart函数检查线程是否正常工作:
if (!serviceThread.isAlive()) {
serviceThread.start();
}
⑩ onDestory函数终止线程:
serviceThread.interrupt();
5.绑定服务
最简单的Service不接收参数也不返回参数,只接受调用;多线程的Service不接收参数自己产生变化,并通过调用主线程中的某些函数达到更新UI的目的;绑定服务的Service可以接收参数也可以返回参数,有Service的作用(避免界面失去响应、提供服务)、又可以像函数一样方便使用,这是很有意义的。
(1)新建一个继承自service的类,比如MathService并在类中写入需要提供服务的函数
(2)新建一个IBinder对象,重载onBind()和onUnbind()函数:
IBinder mBinder=new LocalBinder();
class LocalBinder extends Binder{
MathService getService() {
return MathService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
return false;
}
(3)主线程的activity中声明一个服务类的变量,重载一个ServiceConnection变量:
MathService mathService = null;
ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
//服务意外断开的时候,系统调用的函数
mathService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
mathService = ((MathService.LocalBinder) service).getService();
}
};
(4)绑定服务
Intent serviceIntent = new Intent(MainActivity.this, MathService.class);
bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
(5)取消绑定
//这个函数未必有用
unbindService(mConnection);
mathService = null;
(6)提供服务
int res = mathService.add(a, b);
2. 远程服务
这是除Intent外的另一种进程间的通信方式,可以将服务和调用者以不同应用的方式在一个系统中独立起来。
(1) 建立一个Service,之后用AIDL定义远程服务的接口,即写一个.aidl文件,比如:
AIDL即安卓接口定义语言,语法上类似java,但是AIDL允许参数有方向
package com.example.demo0;
interface IMathService{
int add(int a,int b);
}
(2) Service中需要一个Binder对象:
//也是这个Service提供的服务
IMathService.Stub mBinder=new IMathService.Stub() {
@Override
public int add(int a, int b) throws RemoteException {
// TODO Auto-generated method stub
return a+b;
}
};
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
return false;
}
(3) 新建一个调用者的工程,将Service中的AIDL连同包复制过来
(4) 需要一个ServiceConnection:
// 能够提供服务的对象
IMathService mathService;
ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
mathService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
mathService = IMathService.Stub.asInterface(service);
}
};
(5) 绑定服务
Intent serviceIntent = new Intent();
serviceIntent.setAction("top.guomc.demo0.MathService");
bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
(6) 取消绑定
unbindService(mConnection);
mathService = null;
(7) 提供服务
int res = 0;
try {
res = mathService.add(a, b);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
6.自定义数据的传输
在远程服务中,java基本数据类型的打包过程是自动完成的,但是自定义的数据(类)需要重载Parcelable接口来完成打包的过程
(1)自定义数据的.aidl文件,AllResult.aidl:
package top.guomc.demo0;
parcelable AllResult;
(2)提供服务函数的.aidl文件,IMathService.aidl:
package top.guomc.demo0;
import top.guomc.demo0.AllResult;
interface IMathService{
AllResult computeAll(int a,int b);
}
(3)自定义的类,这个类重载了Parcelable接口,AllResult.java
定义内部数据
//序列化
static Parcelable.Creator<AllResult> CREATOR = new Creator<AllResult>() {
@Override
public AllResult[] newArray(int size) {
// TODO Auto-generated method stub
return new AllResult[size];
}
@Override
public AllResult createFromParcel(Parcel source) {
// TODO Auto-generated method stub
return new AllResult(source);
}
};
定义构造函数
//内部数据写到包
@Override
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeInt(addRes);
dest.writeInt(subRes);
dest.writeInt(mulRes);
dest.writeDouble(divRes);
}
(4)定义Service,MathService.java:
IMathService.Stub mBinder = new IMathService.Stub() {
@Override
public AllResult computeAll(int a, int b) throws RemoteException {
// TODO Auto-generated method stub
int addRes = a + b;
int subRes = a - b;
int mulRes = a * b;
double divRes = (double) a / b;
AllResult res = new AllResult(addRes, subRes, mulRes, divRes);
return res;
}
};
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
return false;
}
(5)将服务方的自定义类型连同.aidl、目录复制到接收方
(6)ServiceConnection、绑定服务、取消服务和上面一样
(7)提供服务
AllResult allResult = null;
try {
allResult = mService.computeAll(a, b);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
用定义过的getter函数将allResult的内部数据获取出来
六、数据存储与访问
SharedPreferences用于存取应用临时产生的数据、文件用于存取应用的非结构化数据、资源用于存取应用的内置数据、数据库用于存取应用的结构化数据,数据库可以完成以上目标
1.SharedPreferences
简单的键值对读写,xml文件将保存在/data/data/包名/shared_prefs/下;如果面对的是复杂类型的数据或是要保存到SD卡上,这种方式还是有缺陷的
(1)声明SharedPreferenes的名字和模式:
static final String PREF_NAME="person";
static final int MODE=Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITEABLE;
访问模式:
MODE_PRIVATE |
私有 |
MODE_WORLD_READABLE |
全局读 |
MODE_WORLD_WRITEABLE |
全局写 |
(2)在onStart()中获取一个SharedPreferences,读取用户个性化的数据来做初始化(一般程序都会这么做):
SharedPreferences sp=getSharedPreferences(PREF_NAME, MODE);
editText1.setText(sp.getString("name", "Tom"));
(3)在onStop()中获取一个SharedPreferences,用来保存数据到xml
SharedPreferences sp=getSharedPreferences(PREF_NAME, MODE);
SharedPreferences.Editor editor=sp.edit();
editor.putString("name", editText1.getText().toString());
2.文件存储
打开文件准备写数据
FileOutputStream fos(String filename,Context.mode);
mode的选择是:
MODE_PRIVATE |
私有 |
MODE_APPEND |
追加 |
MODE_WORLD_READABLE |
全局可读 |
MODE_WORLD_WRITEABLE |
全局可写 |
写文件
String str=”Some data啊”;
fos.write(str.getBytes());
fos.flush();
fos.close();
打开文件准备读数据
FileInputStream fis=openFileInput(String filename);
读文件
byte[] readBytes=new byte[fis.available()];
while(fis.read(readBytes)!=-1);
String str=new String(readBytes);
3.外部存储
在SD卡T-Flash上存储的数据是没有访问权限的控制的,但是可以保存一些大文件而不占用内部存储器的空间,模拟器启动时会自动加载SD卡出现新的路径/mnt/sdcard/,文件会被存储在/storage/sdcard/下
在AndroidManifest.xml中设置加载卸载文件系统、向外部存储器读写数据的权限
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
写数据
String tmpFileName = "SdcardFile-" + System.currentTimeMillis() + ".txt";
File dir = new File("/sdcard/");
if (dir.exists() && dir.canWrite()) {
fileName = dir.getAbsolutePath() + "/" + tmpFileName;
File newFile = new File(fileName);
try {
newFile.createNewFile();
if (newFile.exists() && newFile.canWrite()) {
FileOutputStream fos = new FileOutputStream(newFile);
// str是要写入的String类型数据
fos.write(randNum.getBytes());
fos.flush();
fos.close();
stateView.setText(tmpFileName + "已写入SD卡");
randNumView.setText("");
}
} catch (Exception e) {
Toast.makeText(MainActivity.this, e.toString(), Toast.LENGTH_LONG).show();
}
}
读数据
File dir = new File("/sdcard/");
if (dir.exists() && dir.canWrite()) {
File newFile = new File(fileName);
try {
newFile.createNewFile();
if (newFile.exists() && newFile.canRead()) {
FileInputStream fis = new FileInputStream(newFile);
byte[] readBytes = new byte[fis.available()];
while (fis.read(readBytes) != -1);
String str = new String(readBytes);
randNumView.setText("读取的对应内容是:\n" + str);
}
} catch (Exception e) {
e.printStackTrace();
}
}
4.资源文件
视频、音乐、图片等原始文件放置在项目的/res/raw/下、在应用打包编译的时候不允许修改;xml作数据的文件放置在/res/xml/下,在打包编译的时候会被转换为二进制文件、以提高访问的效率;在项目中可以直接新建得到
(1)读取原始文件
Resources res=MainActivity.this.getResources();
try{
//raw_file是对应的原始文件名、不含后缀
InputStream ips=res.openRawResource(R.raw.raw_file);
byte[] readBytes=new byte[ips.available()];
while(ips.read(readBytes)!=-1);
ips.close();
//str是读出的String类型变量
String str=new String(readBytes,"utf-8");
}catch(Exception e){
e.printStackTrace();
}
读取二级xml文件,比如
<people>
<person name=”李” age=”21” height=”1.81”/>
<person name=”王” age=”25” height=”1.76”/>
<person name=”张” age=”20” height=”1.69”/>
</people>
//people是对应目录下的xml文件名、不含后缀
XmlPullParser parser = MainActivity.this.getResources().getXml(R.xml.people);
String str = "";
try {
while (parser.next() != XmlPullParser.END_DOCUMENT) {
//用于接收键值对中键的信息
String tmp = parser.getName(), name = null, age = null, height = null;
if (tmp != null && tmp.equals("person")) {
int i, count = parser.getAttributeCount();
for (i = 0; i < count; ++i) {
//获取键值对的信息
String attrName = parser.getAttributeName(i);
String attrValue = parser.getAttributeValue(i);
if (attrName != null && attrName.equals("name"))
name = attrValue;
if (attrName != null && attrName.equals("age"))
age = attrValue;
if (attrName != null && attrName.equals("height"))
height = attrValue;
if(name!=null && age!=null && height!=null)
str += "姓名:" + name + ",年龄:" + age + ",身高:" + height + "\r\n";
}
}
}
displayView.setText(str);
} catch (Exception e) {
Log.e("ResourceFileDemo", e.getMessage(), e);
}
5. 数据库存储
数据保存在/data/data/包名/databases/下,默认是私有的;sqlite3在sdk/platform-tools/下,可以通过同目录的adb.exe连接模拟器的Linux系统做进一步的shell操作
(1)手工建库
可以通过adb的shell命令创建对应目录下的文件夹databases、再创建.db文件,但是在shell状态下不能输入中文等unicode字符;也可以通过eclipse的DDMS创建对应的文件夹、再上传.db文件
(2)代码建库
使用多个DBAdapter就可以实现多数据集多表、单数据集单表的操作
①DBAdapter
//包名
package edu.hrbeu.SQLiteDemo;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
public class DBAdapter {
// 数据库的名称
private static final String DB_NAME = "people.db";
// 表的名称
private static final String DB_TABLE = "peopleinfo";
private static final int DB_VERSION = 1;
// 表中各属性的名称
public static final String KEY_ID = "_id";
public static final String KEY_NAME = "name";
public static final String KEY_AGE = "age";
public static final String KEY_HEIGHT = "height";
private SQLiteDatabase db;
private final Context context;
private DBOpenHelper dbOpenHelper;
public DBAdapter(Context _context) {
context = _context;
}
/** Close the database */
public void close() {
if (db != null) {
db.close();
db = null;
}
}
/** Open the database */
public void open() throws SQLiteException {
dbOpenHelper = new DBOpenHelper(context, DB_NAME, null, DB_VERSION);
try {
db = dbOpenHelper.getWritableDatabase();
} catch (SQLiteException ex) {
db = dbOpenHelper.getReadableDatabase();
}
}
// 添加新数据,People对数据进行了封装、返回-1表示失败否则成功
public long insert(People people) {
ContentValues newValues = new ContentValues();
// put可以接收不同类型的参数、显然用到了函数重载
newValues.put(KEY_NAME, people.Name);
newValues.put(KEY_AGE, people.Age);
newValues.put(KEY_HEIGHT, people.Height);
return db.insert(DB_TABLE, null, newValues);
}
// 查询所有的数据项
public People[] queryAllData() {
Cursor results = db.query(DB_TABLE, new String[] { KEY_ID, KEY_NAME, KEY_AGE, KEY_HEIGHT }, null, null, null,
null, null);
return ConvertToPeople(results);
}
// 查询指定的数据项,如果条件是ID返回值应该只是一个值、取下标为0的数据即可,换成其他条件就不见得是一个数据了
public People[] queryOneData(long id) {
Cursor results = db.query(DB_TABLE, new String[] { KEY_ID, KEY_NAME, KEY_AGE, KEY_HEIGHT }, KEY_ID + "=" + id,
null, null, null, null);
return ConvertToPeople(results);
}
// 将查询到的一个项转换为自定义的类
private People[] ConvertToPeople(Cursor cursor) {
int resultCounts = cursor.getCount();
if (resultCounts == 0 || !cursor.moveToFirst()) {
return null;
}
People[] peoples = new People[resultCounts];
for (int i = 0; i < resultCounts; i++) {
peoples[i] = new People();
peoples[i].ID = cursor.getInt(0);
peoples[i].Name = cursor.getString(cursor.getColumnIndex(KEY_NAME));
peoples[i].Age = cursor.getInt(cursor.getColumnIndex(KEY_AGE));
peoples[i].Height = cursor.getFloat(cursor.getColumnIndex(KEY_HEIGHT));
cursor.moveToNext();
}
return peoples;
}
// 删除所有数据
public long deleteAllData() {
return db.delete(DB_TABLE, null, null);
}
// 删除指定数据
public long deleteOneData(long id) {
return db.delete(DB_TABLE, KEY_ID + "=" + id, null);
}
// 对指定项进行更新
public long updateOneData(long id, People people) {
ContentValues updateValues = new ContentValues();
updateValues.put(KEY_NAME, people.Name);
updateValues.put(KEY_AGE, people.Age);
updateValues.put(KEY_HEIGHT, people.Height);
return db.update(DB_TABLE, updateValues, KEY_ID + "=" + id, null);
}
// 执行特定的SQL语句
public void DBAexecSQL(String sql) {
db.execSQL(sql);
}
/** 静态Helper类,用于建立、更新和打开数据库,初始化的时候会用到 */
private static class DBOpenHelper extends SQLiteOpenHelper {
public DBOpenHelper(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
}
private static final String DB_CREATE = "create table " + DB_TABLE + " (" + KEY_ID
+ " integer primary key autoincrement, " + KEY_NAME + " text not null, " + KEY_AGE + " integer,"
+ KEY_HEIGHT + " float);";
@Override
public void onCreate(SQLiteDatabase _db) {
_db.execSQL(DB_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase _db, int _oldVersion, int _newVersion) {
_db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);
onCreate(_db);
}
}
}
②People
//包名
package edu.hrbeu.SQLiteDemo;
public class People {
//属性
public int ID = -1;
public String Name;
public int Age;
public float Height;
@Override
public String toString(){
String result = "";
result += "ID:" + this.ID + ",";
result += "姓名:" + this.Name + ",";
result += "年龄:" + this.Age + ", ";
result += "身高:" + this.Height + ",";
return result;
}
}
七、位置和地图
八、Widget组件开发
九、Android NDK
十、特效
1.tab标签页
继承自Activity的类可以管理这些标签页,如果要实际使用,还需要在AndroidManifest<application/>下面注册这个类。
(1)在layout设计界面中制作tab标签页,并将标签页加入R的id资源中
(2)创建继承自TabActivity的类作为入口,用getTabHost()初始化tabHost
(3)将tab标签页转为java管理的对象,比如LayoutInflater.from(this).inflate(R.layout.tab1, tbHost.getTabContentView());
(4)tabHost添加上这些标签页,比如tbHost.addTab(tbHost.newTabSpec("tab3").setIndicator("FrameLayout").setContent(R.id.layout3));,其中“tab3”是程序中的标记,而“FrameLayout”是标签将显示的标题。
十一、附录
1.参考网址
www.oracle.com/ |
下载JDK |
2.eclipse快捷键
alt+shfit+n |
新建工程 |
alt+shift+r |
重命名 |
alt+shift+s |
选择内置函数,比如继承某些内置的方法 |
ctrl+d |
删除一行或者选中块 |
alt+/ |
关键字提示 |
alt+上下键 |
移动选中块代码 |
选中文件alt+shift+r |
重命名 |
ctrl+alt+上下键 |
复制选中块,可以在preference中设置 |
ctrl+shift+f |
快速格式化 |
选中,ctrl+shift+/或者\ |
注释、反注释 |
ctrl+/ |
快速注释、反注释一行 |
ctrl+l |
快速到某一行 |
ctrl+f11 |
运行代码 |
ctrl+点击 |
查看更详细的定义 |
3.adb命令
adb即Android Debug Bridge安卓调试桥,用于连接Linux系统、管理android设备或模拟器;用命令行工具进入platform,下面的命令都需要在前面加上adb,才会有效
install .apk的完整路径 |
安装某个安卓文件 |
help |
帮助命令 |
version |
adb的版本信息 |
devices |
正在运行的模拟器 |
shell 命令 |
执行shell命令 |
shell |
进入shell模式 |
push 本地文件 目标路径 |
上传本地文件 |
pull 目标路径 [本地路径] |
将设备上的文件下载下来,本地路径默认是adb的路径 |
4.avd命令
avd即安卓虚拟设备,进入tools目录下,可以用命令行创建和编译安卓程序;
android list targets |
镜像文件清单 |
android list avds |
avd的清单 |
5.模拟器设置中文
设置->语言和输入法;
语言,选择中文(中国);
键盘和输入法,选择谷歌拼音输入法;
默认,选择谷歌拼音输入法;
关闭硬件物理键盘
