标签:定义 menu lse 更新 选择 hand 目标 产生 利用
目录
二、生命周期
三、用户界面UI
四、组件通信与广播
五、后台服务
六、数据存储与访问
七、位置和地图
八、Widget组件开发
九、Android NDK
十、特效
十一、 附录
正文
一、构建Android开发环境
(1) 下载JDK的可执行文件并执行
(2) 下载adt的zip压缩包
(3) 下载较新的SDK并解压SDK
(4) 下载eclipse并运行,选择help->install new software->add->archive->下载完毕的adt压缩文件
(5) 重启eclipse后选择SDK解压后的位置
(6) Windows系统利用上vt技术的话,AVD的反应速度要快很多:启动BOIS启动vt,在sdk\extras\intel\Hardware_Accelerated_Execution_Manager下安装intel加速器,在此基础上建立一个intel驱动的AVD。
(7) 创建新项目
下面用的是SUMSUNG手机,这种办法只能看到当前应用的信息
(1)About phone->Software information
(2)连续点击Build number3次
(3)在Developer options中打开USB debugging,并选择适当设置
(4)用USB连接手机,就可以通过IDE选择这个手机做模拟设备,运行需要调试的应用
二、生命周期
程序在Android系统中从启动到终止的所有过程,程序不能控制自身的生命周期而受系统的调度和控制。
onSaveInstanceStae()用于保存activity界面的临时信息、信息一般放在Bundle中,onRestoreInstanceState()用于程序被销毁时恢复临时信息、比如程序遇到锁屏或者被系统中断,但是它们都不是生命周期的时间回调函数。
onCreate() |
用于activity的初始化、创建连接、绑定数据等,是第一个被调用的函数 |
onStart() |
activity显示在屏幕上时被调用 |
onRestart() |
activity重新启动时调用、之后调用onResume()继续和用户交互 |
onResume() |
获取屏幕焦点、接收用户输入时被调用 |
onPause() |
程序被其他窗口覆盖,系统调用函数“暂停”程序、之后调用onSaveInstanceStae()保存临时信息 |
onStop() |
用户不可见时,进入停止对activity更新 |
onDestroy() |
程序调用finish()函数或者被系统终结的时候调用 |
(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
模型、视图、控制器,控制器加工用户输入的数据、交给处理核心“模型”,最终由“模型”来更新视图。
用eclipse的layout设计界面制作静态的UI,用java控制动态的内容、先声明一个控件变量然后用findViewById引用xml中的资源进行初始化。具体的函数可以查阅android的API文档。
控件的属性在设计界面中有,也可以查阅android的手册。
(1)显示和编辑字符的控件
设计界面中双击控件,可以进入控件的xml文件
<TextView android:id=”@+id/TextView0”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”TextView0”/>
(2)按钮控件
Button、ImageButton
(3)提供选择的控件
CheckBox用于多选、RadioGroup和RadioButton用于单选。
(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);
(4)垂直显示的列表控件
ListView中如果内容很多,就会出现滚动条;如果没有内容,将不显示控件。
(4)设置监听器
监听器属于控件的方法,将使用内部类、如果出现错误可能是没有加上View.,在android_api.chm中也有具体的说明。比如OnClickListener、
① 控件独占一个监听器
比如列表控件中给每个子项设置监听器,listView.setOnItemClickListener(new AdapterView.OnIOnItemClickListener(){…});
② 多个控件共享一个监听器
方法是定义一个监听器,然后用v.getId()区分各个控件写上需要的代码,最后控件绑定这个监听器。如果一种类型的控件多次出现,尽量用这种方法设置监听器,消除一些不必要的冗余,。
布局之间可以相互嵌套,按常用的程度分为:
(1)线性布局
LinearLayout可以选择水平也可以选择垂直,还可以像html中table的行列组合使用、这样就灵活多了。
(4) 相对布局
RelativeLayout使用相对的位置以适应不同的屏幕尺寸,灵活而且比较稳定。
(5) 网格布局
和表格布局类似,但是网格布局中的元素可以占用多个网格,而表格布局中的元素不能跨行跨列。
(6) 表格布局
TableLayout默认控件独占一行,TableRow默认控件尽量放在一行。
(7) 绝对布局
在layout设计界面中已经找不到,但是在手动创建布局的xml文件的时候有这样一种布局,部件的位置像坐标一样严格的受到数值的控制、不同的设备上效果不一定好。
可以在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。
把页面中可能重复使用的部分做成Fragment,在一个activity中调用、提高了代码的可重用性。
(1)Fragment生命中的事件回调函数
(2)使用方法
① layout设计界面中添加需要的Fragment、创建继承自Fragment的类
② 设计Fragment对应的xml界面
③ 重载Fragment类中的函数onCreateView、改写return inflater.inflate(R.layout.bfragment, container, false);即可。
(1) 键盘事件setOnKeyListener
监听器中的函数的返回值为true将阻止事件传递给界面元素,界面元素就不会更新;程序中和事件有关的变量,它的信息可以类的声明中找到。
(2) 触摸事件setOnTouchListener
比较典型的函数 |
值的说明 |
函数的说明 |
getAction() |
ACTION_DOWN、ACTION_UP、ACTION_MOVE等 |
获取动作 |
getX()、getY() |
|
获取相对坐标,相对前一个位置 |
getRawX()、getRawY() |
|
获取绝对坐标 |
getPressure() |
|
触点的压力 |
getSize() |
|
触点的尺寸 |
getHistorical…() |
|
获取历史数据中的第几个数据 |
四、组件通信与广播
不论这些组件是否在一个应用程序中都可以用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数据;在函数中写需要的代码
这是隐式启动的匹配机制:当应用安装到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 |
指定的协议 |
(3) 使用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);
(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还可以用于进程间的通信。
boolean是java中的布尔值 |
java类中的变量声明马上就可以初始化,这点和CC++不同 |
null相当于CC++中的NULL |
(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);
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();
最简单的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);
这是除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();
}
在远程服务中,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的内部数据获取出来
六、数据存储与访问
七、位置和地图
八、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安卓调试桥,用于管理android设备或模拟器的工具;用命令行工具进入platform,下面的命令都需要在前面加上adb,才会有效
install .apk的完整路径 |
安装某个安卓文件 |
help |
帮助命令 |
version |
adb的版本信息 |
shell 命令 |
执行shell命令 |
push 本地文件 目标路径 |
上传本地文件 |
pull 目标路径 [本地路径] |
将设备上的文件下载下来,本地路径默认是adb的路径 |
4.avd命令
avd即安卓虚拟设备,进入tools目录下,可以用命令行创建和编译安卓程序;
android list targets |
镜像文件清单 |
android list avds |
avd的清单 |
|
|
标签:定义 menu lse 更新 选择 hand 目标 产生 利用
原文地址:https://www.cnblogs.com/guomc/p/10188724.html