Android开发--入门经典
Android Android Android Android学习笔记 一 一 一
一 . . . .Android Android Android Android基础 基础 基础 基础
一. Android 的体系结构图
四层 , 底层 linux 内核(驱动) , 程序包(C 或 c++)和 Android 运行时(java 类似) ,应用程序框
架 (基本 API) , 应用程序层 .. 向下调用关系 .
二 , 王国历史
05 年 google 收购成立仅 22 个月的 android 公司 ,
07 年 11 月 google 为首的 34 家公司成立了开放手机联盟
08 年 9 月 T-moblie usa 发布第一款手机 T-moblic G1
三 , 开发精神 (随时随地为每个人提供信息)
开发平台普及 (pc,mac,linux) 以 linux 为基础 , java 语言,, 支持 web 下载应用
四 , 开发中的四大天王
Activity (构造应用程序界面的) 门面
Intent (程序传递数据)
Service (处理大部分数据工作)
Content provider (提供数据的接口)
五 , 开发的工具 SDK , eclipse (插件支持 ADT)
六 , 环境搭建
1 . Android SDK 安装 developer.android.com
2. ADT 安 装 www.ecplise.org 在 ecplise 中 软 件 更 新 一 栏 填 入
https://dl-ssl.google.com/android/eclipse
3. 在 eclipse 的首选项 android 中选择 android 的 location 填入本地 android SDK 的安装路径
4. 创建一个新的 android 的虚拟机 打开 android SDK and AVD manager
介绍一个很好的视频网站及资料站
www.mars-droid.com(作者网站)
二 二 二 二 . . . . 工程创建及目录结构 工程创建及目录结构 工程创建及目录结构 工程创建及目录结构
一 , 新建 project
New -> android project -> project name -> build target (开发的版本选择)-> apllcation name
-> package name -> create activity(显示界面) -> min sdk version(最低兼容 sdk 版本)
二 , android 程序的目录结构
Src ==> 编写的源文件
Gen ==> 引用程序的资源文件 (不要修改)
Android ==> 源文件 jar 文件
Assets ==> 放置任何文件
Res ==> 此处放置会在 gen 中生成相应 ID
Drawable 放置图片 分为多个分辨率图片 hdpi,ldpi,mdpi 高中低
Layout 布局方式
Values
adnroidManifest.xml 全局配置文件
三 三 三 三 . . . .Activity Activity Activity Activity初步 初步 初步 初步
1 . Activity 的主要作用(UI) 应用程序组件
创建一个 activity 类
创建 Activity 要点
1. 一个 activity 就是一个类, 并且这个类要继承 activity
2. 需要从写 onCreate 方法(程序运行首先调用)
3. 在配置文件中注册每一个 activity
4. 要为 activity 中添加必要的控件
5. 对应布局文件 一个布局文件对应一个 activity
得到控件 例 findViewById(R.id.MyButton);
四 四 四 四 . . . .Activity Activity Activity Activity和 和 和 和intent intent intent intent
多个 Activity 之间的关系
跳转关键 startActivity(Intent intent)
在 onClickListener 监听器的 onClick 方法中
内部类继承 OnClickListener
Intent intent = new Intent();
intent.putExtra(key , value); // 设置传参数据
intent.setClass(this,class); // 设置跳转参数
Activity.this.startActivity(intent);
事件绑定
myButton = (Button)findViewById(R.id.myButton);
myButton.setOnClickListener(new 内部类名()); // 注册成功
Intent 对象的获取
Intent intent = getIntent();
String value = intent.getStringExtra(key);
TextView = (TextView)findViewById(R.id.myTextView);
TextView.setText(value);
Intent 的基本作用
Intent 对象包含了一组信息 相当于一个请求
1. Component name (欲启动 Activity 的名称等等)
2. Action (另一个 Activity 的动作) ACTION_CALL EDIT , MAIN, SYNC, BATTERY_LOW , SCREEN_ON
等等
3. Data (传递的数据)
4. Category
5. Exreas (额外的键值对信息)
6. Flags
启动另一个 Activity
例 Url url = Url.parse("smsto://08000000123");
Intent intent = new Intent(Intent.ACTION_SENDTO,url);
intent.putExtra("sms_body","The SMS text");
startActivity(intent); 五 五 五
五 . . . .Android Android Android Android开发时常用控件 开发时常用控件 开发时常用控件 开发时常用控件( ( ( (一 一 一 一) ) ) )
TextView , Button , EditText , Menu
例 , 实现一个简单的计算器功能
实现过程一 1 . 在第一个 Activity 中,声明 4 个控件 (2 个编辑框 , 1 个文本域 , 1 个按钮)
2. 要为其中的两个空间设置显示的值 (文本域 和 按钮)
3. 创建一个监听器 . 监听按钮事件
4. 将监听器对象绑定到按钮对象上
在布局的 xml 文件中添加控件 例:
在使用空间的 Activity 页面中取出控件
例: public class Activity extends Activity {
Private EditText eText1;
Private EditText eText2;
Private TextView tView;
Privete Button bBtn;
@override
Public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 根据控件的 ID 来取得代表控件的对象
eText1 = (EditText)findViewById(R.id.eText1);
eText2 = (EditText)findViewById(R.id.eText2);
tView = (TextView)findViewById(R.id.tView);
tView,setText("乘以");
bBtn = (Button)findViewById(R.id.bBtn);
bBtn.setText("计算"); // 为 button 设置值
// 或设置在 res/strings.xml 中设置
//例 : 计算
//bBtn.setText(R.string.bBtnText);
// 将监听器对象绑定按钮对象上去
bBtn.setOnClickLinstrener(new CalculateListener());
}
// 内部类监听器
Class CalculateListener implements OnClickListener {
@Override
Public void onClick(View v) {
// 取得两个编辑框的值
String eText1 = eText1.getText().toString();
String eText2 = eText2.getText().toString();
// 将两个值放入到 Intent 对象之中
Intent intent = new Intent();
// 使用这个 Intent 对象启动下一个 Activity
intent.putExtra("one",eText1 );
intent.putExtra("two",eText2);
intent.setClass(Activity.this , ResultActivity.class);
Activity.this.startActivity(intent);
}
}
}
实现过程二 :
1. 接受从 Activity 当中传递的值
2. 计算两个值的积
3. 将计算的结果显示在当前的 Activity 中
//在当前的 Activity 中的 xml 文件中添加一个文本域
在 onCreate 中执行语句 (不再累赘)
关键代码: // 取到 RestltView 的对象
Intent intent = getIntent();
String tText1 = intnet.getStringExtra("one");
String tText2 = intnet.getStringExtra("two");
Int tText1int = Integer.parseInt(tText1);
Int tText2int = Integer.parseInt(tText2);
Int result = tText1int * tText2int;
RestltView.setText(result + "");
Menu 对象的实现
复写函数 onCreateOptionMenu()
Public boolean onCreateOptionMenu(Menu menu) {
// 第二个参数就是 itemid
Menu.add(0,1,1,R.string.exit);
Menu.add(0,2,2,R.string.about);
Return super.onCreate
}
继续实现 menuitem 的事件方法
// 当用户点击菜单的某一选项时,会调用该方法
复写 onOPtionsItemSelected(MenuItem item);
Public boolean onOPtionsItemSelected(MenuItem item) {
If(item.getItemId() == 1) {
Finish();
}
Return super.onOptionsItemSelected(MenuItem item);
}
六 六 六 六 . . . .Activity Activity Activity Activity的生命周期 的生命周期 的生命周期 的生命周期
参考文档 : 安装目录/docs/index.html
Activity 的生命周期函数
onCreate (Activity 被第一个创建时), onReStart , onStart(Activity 可视的时候) , onDestroy ,
onPause (Activity 暂停状态), onResume (Activity 可被获得焦点的时候), onStop(Activity 不可见的
时候)
启动一个新的 Activity 会依次调用 onCreate , onStart , onResume
调用另外一个 Activity 会依次调用 onPause(第一个) , onCreate (第二个), onStart (第二个),
onResume(第二个) , onStop(第一个)
调用返回按钮 Activty 会依次调用 onPause (第二个) , onReStart(第一个) , onStart (第一个),
onResume(第一个), onStop(第二个) , onDestory (第二个)
onDestory()被调用的时机 1. 明确调用 finish 方法 2. 系统自适应释放
Task 基本概念 (栈中的所有 Activity) 栈 压栈,弹栈 (后进先出原则)
Task 运行过程 , 当应用程序启动之后,运行第一个 Activity 被压入栈中 (显示会时栈中最顶部的
Activity)
3 . 模态化窗体(对话框)
在 AndroidManifest.xml 文件中
可被杀死的方法 onStop , onPause , onDestory
七 七 七 七 . . . .Activity Activity Activity Activity的布局 的布局 的布局 的布局
LinearLayout TableLayout
<TextView android:id="@+id/firstView"
Android:text -- 指定文本内容
Android:grivity -- 基本位置 eng
Android:textSIze -- 文字大小 pt
Android:background -- 背景颜色 #fff
Android:width
Android:height
Android:padding --控件内边距 dip
Android:sigleLine -- 控件的内容是否在同一行显示 boolean
Android:weight -- 控件占 linearlayout 的比例
Android:layout_width
Android:layout_height
2 . // 指定列拉伸
// 填写控件
// 两行
3 . LinearLayout 高级布局
例 : 思想 3 个 LinearLayout
注 : 在 LinearLayout 中还可以嵌套 TableLayout
4 . RelativeLayout 相对布局
Relative 常见属性的概要
Android:layout_above -- 将该控件的底部至于给定 ID 的控件之上
Android:layout_Below -- 将该控件的底部至于给定 ID 的控件之下
Android:layout_toLeftOf -- 该控件的右边缘个给定 ID 的控件的左边缘对齐
Android:layout_toRightOf -- 该控件的左边缘个给定 ID 的控件的右边缘对齐
Layout_alignBaseline -- 该控件的 baseline 与给定 ID 的控件的 baseline 对齐
Layout_alignBottom -- 该控件的底部边缘与给定 ID 的控件的底部边缘对齐
Layout_alignLeft -- 该控件的左边缘个给定 ID 的控件的左边缘对齐
Layout_alignRight -- 该控件的右边缘个给定 ID 的控件的右边缘对齐
Layout_alignTop -- 该控件的顶部边缘与给定 ID 的控件的顶部边缘对齐
Layout_alignParentBottom , Layout_alignParentLeft , Layout_alignParentRight ,
Layout_alignParentTop 该值为 True 时 , 该控件的边与父控件的边的对齐方式
Layout_centerHorizontal , Layout_centerInParent , Layout_centerVertical
八 八 八
八 . . . .Android Android Android Android开发时常用控件 开发时常用控件 开发时常用控件 开发时常用控件( ( ( (二 二 二 二) ) ) )
RadioGroup , RadioButton
CheckBox
Toast
例 1 ,
代码 : 1. 控件对象声明
2. 取得对象控件
3. 设置监听器 ( 只为 RadioGroup 注册一个 )
Public void onCheckedChange(RadioGroup group , int checkedId) {
If (femaleButton.getId() == checkedId) {
System.out.println("Female");
}
Else if (maleButton.getId() == checkedId) {
System.out.println("Male");
}
}
4. 触发事件
// 为 RadioGroup 设置
RadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() )
例 2 .
代码 : 1. 控件对象声明
2. 取得对象控件
3. 设置监听器(为每一个 CheckBox 注册监听器)
Public void onCheckedChanged(CompoundButton buttonView , boolean isChecked) {
If(isChecked) {
System.out.println("yes");
}
Else {
System.out.println("NO");
}
}
4. 触发事件
CheckBox.setOnCheckedChangeLinstener(new CompoundButton.onCheckedChangeLinstener() {})
例 3 . Toast
Toast.makeText(this.class , displaystring , messageTime).show()
九 九 九 九 . . . .Android Android Android Android开发时常用控件 开发时常用控件 开发时常用控件 开发时常用控件( ( ( (三 三 三 三) ) ) )
ProgressBar
ListView
例 :
代码 : 1 . 声明变量
2 . 根据 ID 取得控件对象 findViewById
3 . 设置监听类
Class ButtonLinstener implements OnClickListener {
Public void onClick(View v) {
If (i == 0) {
pBar.setVisibility(View.VISIBLE);
}
Else if ( i < pBar.getMax() ) {
pBar.setProgress(i); -- 设置主进度条的当前值
pBar.setSecondaryProgress(i+10); -- 设置第二进度条的当前值
}
Else {
pBar.setVisbility(View.GONE);
}
I = i + 10;
}
}
4 . 绑定事件
myButton.setOnClickListener(new ButtonLinstener());
例 : main 布局文件
User 布局文件略 (两个 TextView)
代码 : public class Activity extends ListActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 用一个集合对象装数据
ArrayList<HashMap> list = new ArrayList<HashMap>();
HashMap Map1 = new HashMap();
HashMap Map2 = new HashMap();
HashMap Map3 = new HashMap();
Map1.put("user_name","zhangsan");
Map1put("user_ip","192.168.0.1");
Map2.put("user_name","lisi");
Map2.put("user_ip","192.168.0.2");
Map3.put("user_name","wangwu");
Map3.put("user_ip","192.168.0.3");
List.add(Map1);
List.add(Map2);
List.add(Map3);
// listActivity 对象 , map , 第二个布局文件 , 对应 hashMap 的值对(可想象成列) , 控件显示的位置
SimpleAdapter listAdapter = new SimpleAdapter(this , list , R.layout.user , new String[]
{"user_name","user_ip"} , new int[] {R.id.user_ip,R.id.user_name});
setListAdapter(listAdapter);
}
// 重写
Protected void onListItemClick(ListView lv , View v , int position , long id) {
super.onListItemClick(1, v , position , id);
System.out.println("id--------" + id);
System.out.println("position-------" + position)
}
十 十 十 十 . . . .Handler Handler Handler Handler的用法 的用法 的用法 的用法
Handler 的基本概念 (可以进行另外线程的处理程序 , 优化程序 , 类似于线程概念)
异步线程处理方案
Handler 基本的使用方法
代码 : 可以在事件中调用 Handler 的方法
例 : 在 Button 的单击事件中:
Handler.post(updateThread); // 线程对象加入到消息队列中, 此消息队列中只有一个线程对象
// 取消线程队列
handler.removeCallbacks(updateThread);
// 创建一个 Handler 对象
Handler handler = new Handler();
// java 中实现线程的方法 1 继承 thread 类 2.实现 runnable 接口
// 将要执行的操作写在线程对象的 run 方法中去
Runnable updateThread = new Runnable (){
Public void run() {
System.out.println("UpdateThread");
// 在 run 方法内部执行 postDelayed 或者 post 方法
handler.postDelayed(updateThread , 3000); // 延迟加入消息队列
}
}
// 消息队列(数据结构) 先进先出
使用 Handler 更新 ProgressBar
例 : main.xml 中的布局
Activity 中的代码:
Public class TestBarHandler extends Activity {
// 声明控件对象
ProgressBar bar = null;
Button startButton = null;
Public void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 得到控件对象
Bar = (ProgressBar)findViewById(R.id.bar);
startButton = (Button)findViewById(R.id.startButton);
// 为按钮设置监听器
startButton.setOnClickListener(new ButtonListener());
}
// 创建监听器
Class ButtonListener implements OnClickLinstener {
Public void onClick(View v) {
pBar.setVisibility(View.VISIBLE);
pBar.setMax = 200;
updateBarHandler.post(updateThread);
}
}
// 创建一个 Handler 对象 使用匿名内部类来复写 handler 的 handlerMessage 中
Handler updateBarHandler = new Handler() {
Public void handlerMessage(Message msg) {
bar.setProgress(mag.arg1);
updateBarHandler.post(updateThread); // 线程加入线程队列中
}
};
// 匿名内部线程类
Runnable updateThread = new Runnable(){
Int i = 0 ;
Public void run() { // 直接执行了当前 Activity 的线程
System.out.println("begin Thread");
I = i +10;
// 得到一个消息对象 , message 类是有 android 操作系统提供
Message msg = updateBarHandler.obtainMessage();
// 将 msg 对象的 arg1 参数的值设置为 i , 用 arg1 和 arg2 这两个成员变量传递消息,可以使系统的性能
消耗较小
Msg.arg1 = i;
Try {
Thread.sleep(1000);
} catch ( InterruptedException e) {
e.printStackTrace();
}
// 将 msg 加入消息队列中
updateBarHandler.sendMessage(msg);
If(i == pBar.getMax()) {
// 如果 i 的值到达最大值时,移除线程
updateBarHandler.removeCallbacks(updateThread);
}
}
};
}
4 . Handler 与线程 (默认情况下 Activity 与 Handler 共享一个线程)
例 : // 证明 Activity 与 Hnadler 共享一个线程
Public class HnadlerTest extends Activity {
private Handler handler = new Handler();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); // 执行完这一行代码 Activity 中才有控件
Handler.post(r);
//Thread t = new Thread(r); // 独立线程
//t.start();
// currentThread 得到当前运行线程对象
System.out.println("activity----->" + Thread.currentThread().getId());
System.out.println("activityname----->" + Thread.currentThread().getName());
}
Runnable r = new Runnable() {
Public void run () {
System.out.println("Handler----->" + Thread.currentThread().getId());
System.out.println("HandlerName----->" + Thread.currentThread().getName());
Try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
// 输出对比 需要等待 10 秒,Activity 中才会有控件
Activity----> 1
ActivityName ---> main
Handler----> 1
HandlerName ---> main
// 独立线程输出 无等待时间
Handler ---> 9
HandlerName ---> Thread-9
Activity----> 1
ActivityName ---> main
5 . Bundle 的用法(相对特殊的 map , key 一般为 string , value 为个个数据类型)
// Looper , handlerThread 都可以创建一个新的线程
例 : Public class HnadlerTest extends Activity {
private Handler handler = new Handler();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
System.out.println("Activity ----> " + Thread.currentThread().getId());
// 生成一个 HandlerThread 对象,实现了使用 looper 来处理消息队列的功能,这个类有 android 内部实现
HandlerThread handlerThread = new HandlerThread();
handlerThread.start();
MyHandler myHandler = new MyHandler(handlerThread.getLooper());
// 获取消息对象
Message msg = myHandler.obtainMessage();
msg.sendToTarget();
}
Class MyHandler extends Handler {
Public MyHandler () {
}
Public MyHnadler(Looper looper) {
// 调用父类的构造函数 , 有 looper 的方法
Super(looper);
}
Public void handleMessage(Message msg) {
System.out.println("handler---->" + Thread.currentThread().getId());
System.out.println("HandlerMessage");
}
}
}
6 . 在新线程当中处理消息的方法
// 首先创建 Message 对象
// 可以用 arg1 , arg2 (int) , obj (object) , setData(Bundle data) 赋值传递
// 取值 变量 = msg.arg1 等等
Bundler 例 : // 赋值
Bundle b = new Bundle();
b.putInt("age",20);
b.putString("name" , "zhangsan");
msg.setData(b);
// 取值
Bundle b = msg.getData();
Int age = b.getInt("age");
String name = b.getString("name");
十一 十一 十一 十一 . . . .SQLite SQLite SQLite SQLite使用方法 使用方法 使用方法 使用方法
SQLite 介绍
http://www.sqlite.org 官方网站
小型关系数据库
SQLiteOpenHelper 使用方法
getReadableDatabase()
getWritableDatabase()
onCreate(SQLiteDatabase db)
onOpen(SQLiteDatabase db)
onUpgrade(SQLiteDatabse db , int oldVersion , int newVersion)
Close();
// DatabaseHelper 所为一个访问 SQLite 的助手类, 提供两个方面的功能
// 第一, getReadableDatabase() 和 getWritableDatabasr() 可以获得 SQLiteDatabase 对象
// 第二, 提供 onCreate 和 onUpgrade 两个回调函数 , 允许我们在创建和升级数据库时, 进行操作
例 : public class DatabaseHelper extends SQLiteOpenHelper {
// 数据库版本号
Private static final int VERSION = 1;
// 必须的构造函数
Public DatabaseHelper (Context context , String name , CursorFactory factory , int version) {
Super(context , name , factory , version);
}
Public DatabaseHelper (Context context , String name , int version) {
Super(context , name , null , version);
}
Public DatabaseHelper (Context context , String name) {
Super(context , name , null , VERSION);
}
Public void onCreate(SQLiteDatabase db) {
System.out.println("create a database");
Db.execSQL("create table user(id int , name varchar(20))");
}
Public void onUpgrade(SQLiteDatabase db) {
System.out.println("update a database");
}
}
对 SQLite 的增 删 查 改
Activity 操作数据库 例 :
1 . 声明控件对象(略)
2 . 获得控件对象(略)
3 . 绑定事件(略)
4 . 创建监听器对象 (调用 DatabaseHelper)
// 创建一个数据库
Public void onClick(View v) {
// 当前的 activity , 还有数据名
DatabaseHelper dbHelper = new DatabaseHelper(SQLiteActivity.this , "test_db");
SQLiteDatabase db = dbHelper.getReadableDatabase(); // 此时才会创建一个数据库
}
// 修改一个数据库
Public void onClick(View v) {
// 当前的 activity , 还有数据名
DatabaseHelper dbHelper = new DatabaseHelper(SQLiteActivity.this , "test_db" , 2); // 版本号
变了
SQLiteDatabase db = dbHelper.getReadableDatabase();
}
// 插入操作
Public void onClick(View v) {
// 生成 ContentValues 对象
ContentValues values = new ContentValues();
// key 是列名 , value 是值 , 值必须对应数据库列数据类型
Values.put("id" , 1);
Values.put("name" , "zhangsan" );
// 当前的 activity , 还有数据名
DatabaseHelper dbHelper = new DatabaseHelper(SQLiteActivity.this , "test_db");
// 得到可写数据库
SQLiteDatabase db = dbHelper.getWritableDatabase();
// 1.表名 2,不允许空列 3, 值
Db.insert("user", null , values);
}
// 更新操作
Public void onClick(View v) {
// 当前的 activity , 还有数据名
DatabaseHelper dbHelper = new DatabaseHelper(SQLiteActivity.this , "test_db");
// 得到可写数据库
SQLiteDatabase db = dbHelper.getWritableDatabase();
// 1.表名 2,不允许空列 3, 值
// 生成 ContentValues 对象
ContentValues values = new ContentValues();
// key 是列名 , value 是值 , 值必须对应数据库列数据类型
Values.put("name" , "zhangsanfeng" );
// 1.表名 2. 值 , 3 , where 子句 (不包括 where) 4, 为占位符赋值
Db.update("user", values , "id=?" , new String[] {"1"});
}
// 查询数据库
Public void onClick(View v) {
// 当前的 activity , 还有数据名
DatabaseHelper dbHelper = new DatabaseHelper(SQLiteActivity.this , "test_db"); // 版本号变了
SQLiteDatabase db = dbHelper.getReadableDatabase();
// 1, 表名 2 所要查询的列名 3 , 筛选器 4 , 筛选器值 5 .groupby 6 . having //7 orderby
创建游标对象读取数据
Cursor cursor = db.query("user" , "new String[] {"id" , "name"}" , "id=?")
While (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
System.out.println("query--->" + name);
}
}
// 删除操作
Public void onClick(View v) {
// 当前的 activity , 还有数据名
DatabaseHelper dbHelper = new DatabaseHelper(SQLiteActivity.this , "test_db");
// 得到可写数据库
SQLiteDatabase db = dbHelper.getWritableDatabase();
// 1.表名 2. 值 , 3 , where 子句 (不包括 where) 4, 为占位符赋值
Db.delete("user", values , "id=?" , new String[] {"1"});
}
使用 adb 访问 SQLite (linux 命令行调试) abd shell = > ls -i = > cd data = > 创建了数据库之后 =
> 报名.数据库名 => 即可进入该 SQLite
SQLite 语句 .schema // 查看所有表
Linux 知识补习 : cd 目录 (进入目录) ls (查看当前目录)
十二 十二 十二 十二 . . . . 程序调试 程序调试 程序调试 程序调试
1 . DDMS 的使用
LogCat 的 Verbose Debug Info Warning Error 的功能
增加过滤器 create filter => system.out
通过 file explorer 功能实现文件的取出,放入
2 . 常见程序调试
A) 多多查看 DDMS 的 log 和 java 中的方式相同
B) 使用 Log 类输出各类信息
十三 十三 十三 十三 . . . . 文件下载 文件下载 文件下载 文件下载
1 . 使用 http 协议下载文件
// 步骤
A ) : 创建一个 HttpURLConection 对象
HttpURLConnection urlConn = (HttpURLConnection)url.openConnection();
B ) : 获取一个 InputStream
urlConn.getInputStream();
C ) : 访问网络的权限
android.permission.INTERNET
例 : 1 . 声明控件对象(略)
2 . 获得控件对象(略)
3 . 绑定事件(略)
4 . 创建监听器对象
// 封装方法 httpDownloader
Public class HttpDownloader {
Private URL url = null;
Public String download(String urlStr) {
StringBuffer sb = new StringBuffer();
String line = null;
BufferedReader buffer = null;
Try {
// 创建一个 URL 对象
Url = new URL(urlStr);
// 创建一个 Http 连接
HttpURLConnection urlConn = (HttpURLConnection)url.openConnection();
// 使用 IO 流读取数据
Buffer = new BufferedReader(new
InputStreamReader(urlConn.getInputStream()));
While ((line = buffer.readline()) != null) {
Sb.append(line);
} catch (Execption e) {
e.printStackTrace();
} finally {
Try {
Buffer.close();
} catch (Execption e) {
e.printStackTrace();
}
}
Return db.ToString();
}
}
// 返回值 -1 . 下载文件出错 0 下载成功 1 文件已存在
Public int downFile(String urlStr , String path , String fileName) {
InputStream inputStream = null;
Try {
FileUtils fileUtils = new FileUtils();
If(fileUtils.isFileExists(path + fileName)) {
Return 1;
} else {
InputStream = getInputStreamFromUrl(urlStr);
File resultFile = fileUtils.write2SDFromInput(path , fileName ,
inputStream);
If(resultFile == null) {
Return -1;
}
}
} catch (Exception e) {
e.printStackTrace();
Return -1;
} finally {
Try {
inputStream.close();
} catch (Execption e) {
e.printStackTrace();
}
}
Return 0;
}
// 根据 url 得到输入流
Public InputStream getInputStreamFromUrl (String urlStr)
Throws MalfromedURLExecption , IOExecption {
Url = new URL(urlStr);
HttpURLConnection urlConn = (HttpURLConnection)url.openConnection();
InputStream inputStream = urlConn.getInputStream();
Return inputStream;
}
}
Public void onClick(View v) {
HttpDownloader httpDownloader = new HttpDownloader();
String lrc = httpDownloader.download("http://192.168.0.1:8080/XXX.txt");
System.out.println(lrc);
}
2 . 将下载的文件写入 SDCARD
访问 SDCARD
// 得到当前设备 sdka 的目录
Environment.getExternalStorageDirectory();
// 访问 SD 卡的权限
Android.permission.WRITE_EXTERNAL_STORAGE
例 : // 一个完整的访问封装类
Public class FileUtils {
Private String SDPATH;
Public String getSDPATH() {
Return SDPATH;
}
Public FileUtils() {
SDPATH = Environment.getExternalStorageDirectory() + "/";
}
// 在 SD 卡上创建文件
Public File createSDFile(Stirng fileName) throws IOException {
File file = new File(SDPATH + fileName);
file.createNewFile();
Return file;
}
// 在 SD 卡上创建目录
Public File createSDDir(String dirName) {
File dir = new File(SDPATH + dirName);
Dir.mkdir();
Return dir;
}
// 判断 SD 卡上的文件夹是否存在
Public boolean isFileExist (String fileName) {
File file = new File(SDPATH + fileName);
Return file.exists();
}
// 将一个 inputStream 里面的数据写入到 SD 卡上
Public file write2SDFromInput(String path , string fileName , InputStream input) {
File file = null;
OutputStream output = null;
Try {
createSDDir(path);
File = createSDFile(path + fileName);
Output = new FileOutPutStream(file);
Byte buffer [] = new byte [4 * 1024];
While ((input.read(buffer)) != -1) {
Output.write(buffer);
}
Output.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
Try {
Output.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Return file;
}
}
最后在 AndroidManifest,xml 中加入标签
十四 十四 十四 十四 . . . .Content Content Content ContentProvider Provider Provider Provider
1.ContentProvider 基本概念 A:ContentProvider 提供为存储和获取数据提供了统一的接口 B: 使用 ContentProvider 可以在不同的应用程序之间共享数据 C:Android为常见的一些数据提供了ContentProvider(包括音频 , 视频,图片和通讯 录等等)
2.Uri A:每一个 ContnetProvider 都拥有一个公共的 URI,这个 URI 用于表示这 个 ContnetProvider 所提供的数据 B:Android 所提供的 ContentProvider 都存放在 android.provider 包当中 3.ContnetProvider 实现方法 Query Insert Update Delete getType onCreate 4. 实现 ContentProvider 的过程 A: 定义一个 Content_URI 常量 B: 定义一个类 , 继承 ContentProvider C: 实现 query,insertupdate,deletegetType,和 onCreate 方法; D: 在 AnroidManifest.xml 当中进行声明;
例 : // DatabaseHelper 所为一个访问 SQLite 的助手类, 提供两个方面的功能 // 第一, getReadableDatabase() 和 getWritableDatabasr() 可以获得 SQLiteDatabase 对象
// 第二, 提供 onCreate 和 onUpgrade 两个回调函数 , 允许我们在创建和升级数据库时, 进行操作
例 : public class DatabaseHelper extends SQLiteOpenHelper {
// 数据库版本号
Private static final int VERSION = 1;
// 必须的构造函数
Public DatabaseHelper (Context context , String name , CursorFactory factory , int version) {
Super(context , name , factory , version);
}
Public DatabaseHelper (Context context , String name , int version) {
Super(context , name , null , version);
}
Public DatabaseHelper (Context context , String name) {
Super(context , name , null , VERSION);
}
Public void onCreate(SQLiteDatabase db) {
System.out.println("create a database");
// 拼出了建表的语句 db..execSQL("create table" + FirstMetaData.USER_TABLE_NAME +"("+ FirstMetaData.UserTableMetaData._ID +"INTEGER PRIMARYKEYAUTOINCREMENT," +FirstMetaData.UserTableMetaData.USER_NAME +"varchar(20));"; }
Public void onUpgrade(SQLiteDatabase db) {
System.out.println("update a database");
}
}
ContentProviderActivity 例 : 1 . 声明控件对象(略) 2 . 获得控件对象(略)
3 . 绑定事件(略)
4 . 创建监听器对象
// insert
Public void onClick(View v) {
ContentValues values = new ContentValues (); Values.put(FirstMetaData.UserTableMetaData.USER_NAME , "zhangsan"); Uri uri = getContentesolver().insert(FirstMetaData.UserTableMetaData.CO NTENT_URI,values); System.out.println("uri ---->" + uri.toString());
}
// query
Public void onClick(View v) {
Cursor c= getContentResolver().query( FirstMetaData.UserTableMetaData.CONTENT_URI , null,null,null,null ) ;
While(c.moveToNext()) {
System.out.println(c.getString(c.getColumnIndex(UserTa
bleMeatData.USER_NAME)));
}
}
FirstContentProvider 继承 ContentProvider 例 :
PublicclassFirstContentProviderextendsContentProvider {
Publicstatic finalUriMatcheruriMatcher; Publicstatic finalintINCOMING_USER_COLLECTION =1; Publicstatic finalintINCOMING_USER_SINGLE =2; Private DatabaseHelper dh;
Static { uriMatcher= newUriMatcher(UriMatcher.NO_MATCH); //URI 限定名的添加验证 定义了一个验证的规则 uriMatcher.addURI(FirstMetaData.AUTHORTY , "/users", INCOMING_USER_COLLECTION); uriMatcher.addURI(FirstMetaData.AUTHORTY , "/users/#", INCOMING_USER_SINGLE); }
Public static HashMap userProjectionMap;
Static
{
userProjectionMap = new HashMap();
// ._ID 就是 baseColumns 实现的结果 userProjectionMap.put(FirstMetaData._ID,FirstMetaData._ID); userProjectionMap.put(FirstMetaData .USER_NAME , FirstMetaData.USER_NAME); }
@Override
Public int delete(Uri arg0 , String arg1 , String[] arg2) {
System.out.println("delete");
Return 0;
}
// 根据传入的 Uri,返回该 Uri 所表示的数据类型
@Override
Public String getType(Uri uri) {
System.out.println("getType");
Switch (uriMatcher.match(uri)) {
Case INCOMING_USER_COLLECTION: Return FirstMetaData.CONTENT_TYPE; CaseINCOMING_USER_SINGLE: ReturnFirstMetaData.CONTENT_TYPE_ITEM; Default: ThrownewIllegalArgumentExecption("Unknown URI"+uri);
}
}
// 该函数的返回值是一个 Uri , 这个 URi 表示的是刚刚使用这个函数所插入的数据 // content://com.android.FirstContentProvider/users/1 @Override
Public Uri insert(Uri uri , ContentValue values) {
System.out.println("insert");
SQLiteDatabase db = dh.getWrittableDatabase(); Long rowId = db.insert(FirstMetaData.TABLE_NAME,null,values); If(rowId > 0) {
// 以 Content 起头的 Uri 都可以用 ContentUris 来处理
Uri insertedUserUri = ContentUris.withAppendedId(UserTableMetaData.CONTENT_URI ,
rowId);
// 通知监听器 , 数据已经改变
getContext().getContentResolver().notifyChange(insertedUserUri , null);
Return insertedUserUri;
}
Throw new SQLExecption("Failed to insert row into " + uri);
}
@Override
Public boolean onCreate() { Dh = new DatabaseHelper(getContext() , FirstMetaData.DATABASE_NAME); System.out.println("onCreate");
Return true;
}
@Override
Public Cursor query(Uri uri , String[] projection , String selection , String[]
selectionArgs , String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder ();
Switch (uriMatcher.match(uri)) {
Case INCOMING_USER_COLLECTION: qb.setTables(FirstMetaData.TABLE_NAME); qb.setProjectionMap(userProjectionMap);
Break; CaseINCOMING_USER_SINGLE: qb.setTables(FirstMetaData.TABLE_NAME); qb.setProjectionMap(userProjectionMap);
// 取回了单条数据 list qb.appendWhere(FirstMetaData._ID + "="+uri.getPathSeqments().get(1)); Break;
}
String orderBy;
If (TextUtils.isEmpty(sortOrder)) { orderBy = FirstMetaData.DEFAULT_SORT_ORDER; } else {
orderBy = sortOrder;
}
SQLiteDatabase db = dh.getWritableDatabase();
Cursor c = qb.query(db , projection , selection , selectionArgs , null , null , orderBy);
c.setNotificationUri ( getContext().getContentResolver() , uri);
System.out.println("query");
Return c;
}
@Override
Public int update(Uri arg0 , ContentValues arg1 , String arg2 , String[] arg3) {
System.out.println("update");
}
}
FirstMetaData(一些静态常量) 例 :
PublicclassFirstMetaData { //URI 限定名的名称 包名 + 类名 Publicstatic finalStringAUTHORTY="com.android.FirstContentProvider"; // 数据库名称 Publicstatic finalStringDATABASE_NAME="FirstContentProvider.db"; // 数据库版本 Publicstatic finalintDATABASE_VERSION =1; // 表名 Publicstatic finalStrintUSERS_TABLE_NAME ="users";
//BaseColumns 实现了表的_id 列 Publicstatic finalclassUserTableMetaDataimplementsBaseColumns{ // 表名 Publicstatic finalStringTABLE_NAME= "users"; // 访问该 ContentProvider 的 URI Public static final Uri CONTENG_URI = Uri.parse("content://" + AUTHORY + "/users"); // 整张表的数据类型是 vnd.android.cursor.dir/vnd+name; Public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.FinrstContentProvider.ser"; // 单条数据类型定义 vnd.android.cursor.item/vnd+name Public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.FinrstContentProvider.user"; // 列名 Publicstatic finalStringUSER_NAME="name"; // 默认排序方法 Publicstatic finalStringDEFAULT_SORT_ORDER= "_iddesc"; }
}
最后在 androidMnaifest.xml 中注册 provider 与 Activity 同级 authorities 中的数据一定要 与 CONTENG_URI 的一致
十五 十五 十五 十五 . . . .XML XML XML XML文件解析 文件解析 文件解析 文件解析
1. 什么是 SAX
SimpleAPI forXML, 既是指一种接口 , 也是指一个软件包 作为接口 ,SAX 是事件驱动型 XML 解析的一个标准接口
2.SAX 基本原理
SAX 的哦给你工作原理简单地说就是对文档进行顺序扫描,当扫描到文档 (document)开始与结束,元素(element)开始与结束等地方时通知事件处理函数,由事件处 理函数做相应动作,然后继续同样的扫描,直至文档结束.
大多数 SAX 实现都会产生一下类型的事件 { 在文档的开始和结束时出发文档处理事件 在文档内每一 XML 元素接受解析的前后触发元素事件 任何元数据通常都由氮素的事件交付 在处理文档的 DTD 或 Schema 时产生 DTD 或 Schema 事件
产生错误事件用来通知主机应用程序解析错误
}
3.SAX 常用接口
ContentHandler 接口 ContentHandler是java类包中一个特殊的SAX接口,位于org.xml.sax包中.该接 口封装了一些对事件处理的方法,当XML解析器开始解析XML输入文档时,它会遇 到某些特殊的事件,比如文档的开头和结束,元素的开头和结束,以及元素中的字符 数据等事件.当遇到这些事件时,XML解析器会调用ContentHandler接口中相应的方 法来响应该事件
ContnetHandler 接口的方法有以下几种 { Void startDocument();
Void endDocument();
Void startElement(String uri,StringlocalName ,stringqName ,Attributesatts)
Void endElement(Stringuri,String localName,StringqName)
Void characters(char[]ch,intstart,intlength)
}
4.SAX 解析 解析文档过程 例 : HelloWorld! 在解析文档的过程中会产生如下一系列事件
Startdocument { Startelement:doc A: 创建事件处理程序 Startelement:para Characters:HelloWorld! B: 创建 SAX 解析器 Endelement:para Endelement:doc C: 将事件处理程序分配给解析 器 D: 对文档进行解析 , 将每个 事件发送给处理程序 Enddocument }
解析样例 : 1 . 声明控件对象(略) 2 . 获得控件对象(略)
3 . 绑定事件(略)
4 . 创建监听器对象
Public void onClick(View v) {
HttpDownloader hd = new HttpDownloader();
String resultStr = hd.download("XMLURL");
System.out.priintln(resultStr);
Try {
// 创建一个 SAXParseFactory
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLReader reader = factory.newSAXParser().getXMLReader();
// 为 XMLReader 设置内容处理器 MyContentHandler
reader.setContentHandler(new MyContenHandler());
// 开始解析文件 字符串构造成 reader 之后构造成 inputSource
Reader.parse(new InputSource(new StringReader(resultStr)));
} catch (Execption e) {
e.printStackTrace();
}
}
XML 文件写法 :
mark
male
manager
New York
$4000
lily
female
assists
H
$2000
tom
male
manager
F
$5000
MyContenHandler 的写法 例 :
Public class MyContenHandler Extends DefaultHandler { // 此处体现了适配器模式
String Name , Sex , Status , Address , Salary
String tagName;
// 开始 document
Public void startDocument() throws SAXExecption {
System.out.println("-------begin--------");
}
// 结束 document
Public void endDocument() throws SAXExecption {
System.out.println("-------end--------");
}
// 开始节点对象
Public void startElement(String namespaceURI , String localName , String qName ,
Attributes attr) throws SAXExecption {
tagName = localName ;
If (localName.equals("worker")) {
// 获取标签的全部属性
For (int i = 0 ; i " + Name);
System.out.println("name--->" + Sex);
System.out.println("name--->" + Status);
System.out.println("name--->" + Address);
System.out.println("name--->" + Salary);
}
}
十六 十六 十六 十六 . . . . 广播机制 广播机制 广播机制 广播机制
1.Adnroid 的广播机制
2.BroadcastReceiver 的作用
事件触发之后的一种解决方法
3.BroadcasrReceiver 的编写方法 在 AndroidManifest.xml 中注册广播
例 ://BroadcasrReceiver PublicclassTestReceiverextendsBroadcastReceiver { PublicTestReceiver(){ System.out.println("TestReceiver"); }
@override PublcvoidonReceive(Contextcontext,Intentintent){ System.out.println("OnReceiver"); // 对象会被销毁 TestReceiver }
}
Activity 中的写法 例: 1 . 声明控件对象(略) 2 . 获得控件对象(略)
3 . 绑定事件(略)
4 . 创建监听器对象
Publicvoid onClick(Viewv) { TestReceivertr= newTestReceiver(); Intentintent=newIntent(); intent.setAction(Intent.ACTION_EDIT); // 与 AndroidManifest 中的过滤内容 对比 TestActivity.this.sendBroadcast(intent); }
4.BroadcastReceiver 的生命周期
5. 注册 BroadcastReceiver 的方法
BroadcastReceiver 用 于 监 听 被 广 播 的 事 件 (Intent) 为 了 达 到 这 个 目 的,BroadcastReceiver 必须进行注册,以下是注册的两种方法
在应用程序的代码当中进行注册 注册 BroadcastReceiver registerReceiver(receiver,filter) 取消注册 UnregisterReceiver(receiver);
Activity 中代码 例 : 1 . 声明控件对象(略) 2 . 获得控件对象(略)
3 . 绑定事件(略)
4 . 创建监听器对象
// 绑定广播事件
Publicvoid onClick(Viewv) { // 生成 receiver 对象 smsReceiver=newSMSReceiver(); IntentFilterfilter=newIntentFilter(); filter.addAction("android.provider.Telephony.SMS_RECEIVED"); // 注册广播事件 TestActivity.this.registerReceiver(smsReceiver,filter); }
// 接触广播事件
Publicvoid onClick(Viewv) { TextActicity.this.unregisterReceiver(smsReceiver); }
PublicclassSMSReceiverextendsBroadcastReceiver { @override Publicvoid onReceive(Contextcontext, Intentintent){ System.out,println("receivemessage");
// 对接受的短消息进行处理 // 接受 Intent 对象中的数据 Bundlebundle=Intent.getExtras(); // 在 Bundle 对象当中有一个属性名为 pdus, 这个属性的值是一个 Object 数组 Object[]myObjects=(Object[]) bundle.get("pdus");
// 创建一个 SmsMessage 类型的数组 SmsMessage[]message=newSmsMessage(myObjects.length); System.out,println(message.length); For(inti=0;i<myObjects.length ;i++) { // 使用 Object 数组当中的对象创建 SmsMessage 对象 Message[i]= SmsMessage.createFromPdu((byte[])myObjects[i]); System.out,println(message[i].getDisplayMessageBody()); }
}
}
在 AndroidManifest.xml 中进行注册 (不论应用程序的开启或关闭)
6.Android 内置的 BroadcastActions
十七 十七 十七 十七 . . . .WIFI WIFI WIFI WIFI的操作 的操作 的操作 的操作
1. 什么是 WIFI WIFI 就是一种无线联网的技术 , 则又称为"热点" 2. 获取 WIFI 网卡的状态
0--> 正在关闭 1--> 关闭状态 2--> 正在打开 3--> 网卡可用 4--> 位置状态
3. 操作 WIFI 所需要的权限
4. 改变 WIFI 网卡的状态
例 : 1 . 声明控件对象(略) 2 . 获得控件对象(略)
3 . 绑定事件(略)
4 . 创建监听器对象
Public void onClick(View v ) {
WifiManager wifiManager =
(WifiManager)WifiActivity.this.getSystemService(Serivce.WIFI_SERVICE);
wifiManager.setWifiEnabled(true); // 打开 WIfi 网卡 false 关闭
System.out.println("wifi state --->" + wifiManager.getWifiState());
Toast.makeText(WifuActivity.this , " 当 前 的 WIFI 网 卡 状 态 为 " +
wifiManager.getWifiState());
}
十八 十八 十八 十八 . . . .Scoket Scoket Scoket Scoket编程 编程 编程 编程
1. 什么是 Socket
Socket 英文意为"插座"
所谓 Scoket 通常也称作"套接字",用于描述 IP 地址和端口,是一个通信链的句柄
应用程序通常通过"套接字"向网络发出请求或者应答网络请求
2.Socket 基本通信模型
3. 使用基于 TCP 协议的 Socket
ServerSocketActivity 代码 例 : 1 . 声明控件对象(略) 2 . 获得控件对象(略)
3 . 绑定事件(略)
4 . 创建监听器对象
Public void onClick(View v) {
New ServerThread().start();
}
// TCPserver
Class ServerThread extends Thread {
Public void run () {
// 声明一个 serverSocket 对象
ServerSocket serverSocket = null;
Try {
// 创建 serverSocket 对象并在 4567 端口监听
serverSocket = new ServerSocket(4567);
// 调用 serverSocket 的 accept 方法,接受客户端所发送的请求
Socket socket = serverSocket.accept(); // 阻塞函数
// 从 socket 当中得到 inputstream 对象
InputStream inputStream = socket.getInputStream();
Byte buffer [] new bute [1024 * 4];
Int temp = 0 ;
// 从 inputStream 当中读取客户端所发送的数据
While ((temp = inputStream.read(buffer)) != -1) {
System.out,println(new String(buffer , 0 ,temp));
}
} catch (Execption e) {
e.printStackTrace();
} finally {
Try {
serverSocket.close();
} catch (IOExecption e) {
e.printStackTrace();
}
}
}
}
TCPClient 代码 例 :
Public static void main (String [] args) {
Try {
// 创建一个 Socket 对象,指定服务器端的 ip 地址和端口号
Socket socket = new Socket("192.168.1.1" , 4567);
// 使用 InputStream 读取硬盘上的文件
InputStream inputStream = new FileInputStream("F://file/words.txt");
// 从 Socket 上得到 outputStream
outputStream outputStream = socket.getOutputStream();
Byte buffer [] = new byte[4*1024];
Int temp = 0;
// 将 inputStream 的数据取出并写入到 outputStream
While ((temp = inputStream.read(buffer)) != -1) {
outputStream.write(buffer , 0 ,temp);
}
outpurStream.flush();
} catch (Execption e) {
e.printStackTrace();
}
}
// UDPServer
Class ServerThread extends Thread {
Public void run () {
Try {
// 创建一个 DatagramSocket 对象,并制定监听端口号
DatagramSocket socket = new DatagramSocket(4567);
Byte data [] = new byte [1024];
// 创建一个空的 DatagramPacket 对象
DatagramPacket packet = new DatagramPacket (data , data.length);
// 使用 receive 方法接受客户端所发送的数据
Socket.receive(packet); // 阻塞方法
String result = new String(packet.getData() , packet.getOffset() ,
packet.getLength()); // 设置数据偏移量 , 得到该次数据的长度
System.out.println("result-->" + result);
} catch (Execption e) {
e.printStackTrace();
}
}
}
// UDPClient
Public static void main (String [] args) {
Try {
// 创建一个 DatagramSocket 对象,并制定监听端口号
DatagramSocket socket = new DatagramSocket(4567);
InetAddress serverAddress = InetAddress.getByName("192.168.1.1");
String str = "hello";
Byte data [] = str.getBytes();
DatagramPacket packet = new DatagramPacket(data , data.length ,
serverAddress , 4567);
Socket.send(packet);
} catch (Execption e) {
e.printStackTrace();
}
}
4 . 使用基于 UDP 协议的 Socket
十九 十九 十九 十九 . . . .Service Service Service Service初步 初步 初步 初步
1 . Service 是什么
是一个应用程序组件
没有图形化界面
通常处理一些耗时较长的操作
可以是使用 service 更新 ContnetProvider.发送 intnet 以及启动系统的通知等等
2 . Service 不是什么
不是一个单独的进程
不是一个线程
3 . Service 生命周期
4 . 启动和停止 Service 的方法
服务 例 : public class FirstService extends Service {
@Override
Public IBinder onBind(Intent intent) {
System.out.println("Service onBind");
Return null;
}
@Override
Public void onCreate() {
super.onCreate();
System.out.println("Service onCreate");
}
// 启动服务时方法
@Override
Public int onStartCommand(Intent intent , int flage , int startId) {
System.out.println("flags -->" + flags);
System.out.println("startId --> " + startId);
System.out.println("service onStartCommand");
Return START_NOT_STICKY;
}
@Override
Public void onDestroy() {
System.out.println("Service onDestroy");
super.onDestroy();
}
}
在 AndroidMnaifest.xml 中注册服务 :
在 Activity 中调用 Service 例: 1 . 声明控件对象(略)
2 . 获得控件对象(略)
3 . 绑定事件(略)
4 . 创建监听器对象
// 启动服务
Public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(Activity.this , FirstService.class);
startService(intent);
}
// 停止服务
Public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(Activity.this , FirstService.class);
stopService(intent);
}
二十 二十 二十 二十 . . . . 项目 项目 项目 项目