黑马程序员技术交流社区

标题: 十年磨一剑【基哥笔记】Android基础—Day08-绑定服务 [打印本页]

作者: allen927    时间: 2015-12-8 08:41
标题: 十年磨一剑【基哥笔记】Android基础—Day08-绑定服务
本帖最后由 allen927 于 2015-12-8 08:55 编辑



同样的课程、老师、就业,更好的学习环境,更低的学习成本!
内地学员,选择长沙校区,靠谱!!!
报名热线:0731-85833115
  QQ  : 2355535415

android基础Day08(绑定服务)

资源总连接:http://bbs.itheima.com/thread-249703-1-1.html

《 如果感觉今天的知识点都会了,可以直接做作业,来进行检测》

•(了解)为什么需要绑定服务
绑定服务就是为了和服务进行通讯
可以调用服务里面的方法


•(掌握)绑定服务调用服务方法的流程


•(掌握)绑定服务抽取接口

接口的抽取:有什么样的行为,就抽取什么样的方法。





•(掌握)绑定本地服务
案例


总结


代码

1 订阅接口
/**
* 接口
*@author apple
*
*/
public interface IStudentListener {

       //根据学号查询学生的姓名
       publicString queryNameById(int id);

}              

2 服务
public class MyService extends Service {

       privateString[] names = new String[]{"张学友","刘德华","黎明","郭富城"};

       //增强版IBinder(真实的对象)
       private MyBinder ibinder = new MyBinder();
      
       @Override
       public IBinder onBind(Intent intent) {
              return ibinder;
       }
      
       //创建一个增强版的IBinder
       private class MyBinder extends Binder implementsIStudentListener{

              @Override
              publicString queryNameById(int id) {
                     //id只能是1 4
                     if(id<= 0 || id > names.length){
                            return"苍姐姐";
                     }else{
                            returnnames[id-1];
                     }
              }

       }
}

3 客户端
public class MainActivity extends Activity{

       privateEditText et_id;
       privateButton bt_query;
       privateTextView tv_name;
       privateMyServiceConnection conn;
       privateIStudentListener iStudentListener;

       @Override
       protectedvoid onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);

              et_id= (EditText) findViewById(R.id.et_id);
              bt_query= (Button) findViewById(R.id.bt_query);
              tv_name= (TextView) findViewById(R.id.tv_name);

              //绑定服务
              conn = new MyServiceConnection();
              bindService(new Intent(this,MyService.class), conn,BIND_AUTO_CREATE);
       }

       privateclass MyServiceConnection implements ServiceConnection{

              //绑定成功
              @Override
              public void onServiceConnected(ComponentName name, IBinderservice) {
                     bt_query.setEnabled(true);
                     //IBinder对象转化成接口对象
                     iStudentListener = (IStudentListener) service;
              }

              @Override
              publicvoid onServiceDisconnected(ComponentName name) {

              }

       }

       publicvoid query(View v){
              //绑定服务(为什么服务的绑定需要时间)
              StringidStr = et_id.getText().toString().trim();
              if(TextUtils.isEmpty(idStr)){
                     Toast.makeText(this,"姐姐 学号不能为空", 0).show();
              }else{
                     intid = Integer.parseInt(idStr);
                     //调用接口对象的方法(就是调用真实对象的方法)
                     String name = iStudentListener.queryNameById(id);
                     tv_name.setText(name);
              }
       }


       @Override
       protectedvoid onDestroy() {
              super.onDestroy();
              unbindService(conn);
       }
}

•(掌握)远程服务aidl
aidl:android interface  definelanguage
安卓接口定义语言。
他是一种新的语言。
这样的语言他可以被编译器自动编译为java语言。
作用:aidl
为了解决进程间通讯,定义了两个应用程序之间的通讯规则。
他和接口非常的相似,我们可以先定义接口,再把接口修改为aidl
.java -->  .aidl
aidl语言有自己的语法:
1 它可以识别java里面的基本数据类型
2 它无法识别访问修饰符 public private  
3 它无法识别domain  
   如果要让aidl识别domain
   1 class Student implementsParcelable
   2 写一个Student.aidl文件
       package  cn.itcast.domain;
      parcelable Student;              

aidl 自动生成.java文件后,我们使用什么?
Stub  
  asInterface(IBinder)  IStudent
底层其实走的是代理机制。

aidl 就是一个合同  一式两份  
写完aidl之后,把aidl所有的内容带包一起复制到客户端  



•(掌握)绑定远程服务
案例

总结


实现
服务器

定义接口 .java 修改为.aidl  删除public修饰符

/**
* 远程的服务(在其他应用程序里面的服务)
*@author apple
*
*/
public class MyService extends Service {

       privateString[] names = new String[]{"张学友","刘德华","黎明","郭富城"};

       privateMyBinder ibinder = new MyBinder();

       @Override
       publicIBinder onBind(Intent intent) {
              returnibinder;
       }

       //增强版的IBinder
       privateclass MyBinder extends Stub{

              @Override
              publicString queryNameById(int id) throws RemoteException {
                     //id只能是1 4
                     if(id<= 0 || id > names.length){
                            return"苍姐姐";
                     }else{
                            returnnames[id-1];
                     }
              }

       }

}

客户端

从服务器端把aidl文件带包一起复制过来
public class MainActivity extends Activity{

       privateEditText et_id;
       privateTextView tv_name;
       privateMyServiceConnection conn;
       privateIStudentListener iStudentListener;

       @Override
       protectedvoid onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);

              et_id= (EditText) findViewById(R.id.et_id);
              tv_name= (TextView) findViewById(R.id.tv_name);
              //绑定服务
              Intentservice = new Intent();
              service.setAction("cn.itcast.action.studentquerysystem.server");
              conn= new MyServiceConnection();
              bindService(service,conn, BIND_AUTO_CREATE);
       }

       @Override
       protectedvoid onDestroy() {
              super.onDestroy();
              unbindService(conn);
       }

       privateclass MyServiceConnection implements ServiceConnection{

              //绑定的服务是一个  远程的服务   aidl语言   传递过来的对象   :代理对象  代理对象不能直接使用
              //需要使用Stub里面的一个方法 asInterface()把代理对象转化成真实对象  再使用
              @Override
              public void onServiceConnected(ComponentName name,IBinder service) {
                     //把代理对象转化成真实对象
                     iStudentListener = Stub.asInterface(service);
              }

              @Override
              publicvoid onServiceDisconnected(ComponentName name) {

              }

       }

       publicvoid query(View v){
              StringidStr = et_id.getText().toString().trim();
              if(TextUtils.isEmpty(idStr)){
                     Toast.makeText(this,"姐姐 学号不能为空", 0).show();
              }else{
                     intid = Integer.parseInt(idStr);
                     //调用接口对象的方法(就是调用真实对象的方法)
                     try{
                            Stringname = iStudentListener.queryNameById(id);
                            tv_name.setText(name);
                     }catch (RemoteException e) {
                            e.printStackTrace();
                            Toast.makeText(this,"服务器端出现了错误",0).show();
                     }
              }
       }


}

•(掌握)绑定远程服务(服务返回对象)
实现
服务器:




public classStudent implementsParcelable {
     public int id;
     public String name;
     public int age;
     public Student() {
         super();
     }
     public Student(int id, String name, int age) {
         super();
         this.id = id;
         this.name = name;
         this.age = age;
     }
     @Override
     public int describeContents() {
         return 0;
     }
     //把属性写入到Parcel对象
     @Override
     public void writeToParcel(Parceldest, intflags) {
         dest.writeInt(id);
         dest.writeString(name);
         dest.writeInt(age);
     }
     public static finalParcelable.Creator<Student> CREATOR = newParcelable.Creator<Student>() {
         public StudentcreateFromParcel(Parcel in) {
              return new Student(in);
         }
         public Student[] newArray(int size) {
              return new Student[size];
         }
     };
     private Student(Parcel in) {
         id = in.readInt();
         name = in.readString();
         age = in.readInt();
     }
}
Student.aidl   
                                                                     
IStudent.aidl


•(掌握)服务综合案例-音乐播放器

使用服务来播放音乐。
播放:放歌
暂停:暂停播放  点击暂停按钮:变为继续
停止:停止播放
准备:
1 MainActivity  
2MyService



单箭头:方法的调用
双箭头:监听回调
椭圆:状态
public class MainActivity extends Activity{

       privateEditText et_path;
       privateServiceConnection conn;
       privateIMusic iMusic;

       @Override
       protectedvoid onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);

              et_path= (EditText) findViewById(R.id.et_path);

              //绑定服务
              Intentservice = new Intent(this,MyService.class);
              conn= new MyServiceConnection();
              bindService(service,conn, BIND_AUTO_CREATE);
       }

       @Override
       protectedvoid onDestroy() {
              super.onDestroy();
              unbindService(conn);
       }

       privateclass MyServiceConnection implements ServiceConnection{

              @Override
              publicvoid onServiceConnected(ComponentName name, IBinder service) {
                     iMusic= (IMusic) service;
              }

              @Override
              publicvoid onServiceDisconnected(ComponentName name) {

              }

       }


       //播放
       publicvoid play(View v){
              //获取要播放的歌曲路径
              Stringpath = et_path.getText().toString().trim();
              if(TextUtils.isEmpty(path)){
                     Toast.makeText(this,"路径为空",0).show();
              }else{
                     iMusic.play(path);
              }
       }

       //暂停 继续
       publicvoid pause(View v){
              Buttonbt = (Button) v;
              Stringtext = bt.getText().toString();
              if("暂停".equals(text)){
                     iMusic.pause();
                     bt.setText("继续");
              }elseif("继续".equals(text)){
                     iMusic.moveon();
                     bt.setText("暂停");
              }
       }

       //停止
       publicvoid stop(View v){
              iMusic.stop();
       }

}

接口的抽取
public interface IMusic {
      
       //播放  path 歌曲的路径
       public void play(String path);
      
       //暂停
       public void pause();
      
       //继续
       public void moveon();
      
       //停止
       public void stop();
}

public class MyService extends Service {

       privateMyBinder ibinder = new MyBinder();
       @Override
       publicIBinder onBind(Intent intent) {
              returnibinder;
       }

       privateclass MyBinder extends Binder implements IMusic{

              private MediaPlayer mp;

              @Override
              publicvoid play(String path) {
                     try{
                            mp= new MediaPlayer();
                            mp.reset();//重置
                            mp.setDataSource(path);//设置播放的资源
                            mp.prepare();//准备
                            mp.start();//播放
                     }catch (Exception e) {
                            //TODO Auto-generated catch block
                            e.printStackTrace();
                     }

              }

              @Override
              publicvoid pause() {
                     mp.pause();//暂停播放
              }

              @Override
              publicvoid moveon() {
                     mp.start();//继续
              }

              @Override
              publicvoid stop() {
                     mp.stop();//停止播放
              }

       }

}

•(掌握)服务后台音乐播放器界面显示-notification




       //用户按下任意的键  该方法都会调用
       @Override
       publicboolean onKeyDown(int keyCode, KeyEvent event) {
              if(keyCode== KeyEvent.KEYCODE_BACK){
                     //按下的就是后退键
                     //弹出提示框
                     AlertDialog.Builderbuilder = new AlertDialog.Builder(this);
                     builder.setTitle("提示信息");
                     builder.setMessage("是否退出音乐播放器");
                     builder.setPositiveButton("退出", new OnClickListener() {

                            @Override
                            publicvoid onClick(DialogInterface dialog, int which) {
                                   //关闭当前的Activity
                                   finish();
                            }
                     });
                     builder.setNegativeButton("取消", null);
                     builder.setNeutralButton("隐藏", new OnClickListener() {

                            @Override
                            publicvoid onClick(DialogInterface dialog, int which) {
                                   //把当前的MainActivity放置在后台
                                   moveTaskToBack(true);
                            }
                     });
                     AlertDialogdialog = builder.create();
                     dialog.show();
              }
              returnsuper.onKeyDown(keyCode, event);
       }

•(掌握)服务注册广播接受者
Activity里面注册广播接收者   服务里面注册广播接收者

1 在服务里面写一个class  
MyReceiver  extendsBroadcastReceiver {
    onReceive(){
    }
}

2 注册  onCreate() {
  registerReceiver(receiver,filter);
   }

3 取消注册
  onDestory(){
  unRegisterReceiver(receiver);
  }

public class MyService extends Service {

       privateMyReceiver receiver;

       @Override
       publicvoid onCreate() {
              super.onCreate();

              receiver= new MyReceiver();
              IntentFilterfilter = new IntentFilter();
              filter.addAction("");
              registerReceiver(receiver,filter);
       }

       @Override
       publicvoid onDestroy() {
              super.onDestroy();
              unregisterReceiver(receiver);
       }

       @Override
       publicIBinder onBind(Intent intent) {
              returnnull;
       }

       privateclass MyReceiver extends BroadcastReceiver{

              @Override
              publicvoid onReceive(Context context, Intent intent) {
                     //执行什么操作
              }

       }

}

(掌握)知识点补充
1 服务里面不能直接执行耗时的操作
  Service   和  Activity有什么区别:一个有界面 一个没有界面
2 如果要执行耗时的操作,开始子线程(android也提供了一个类IntentService对Service、Thread、Handler线程进行了封装:一般会出现在笔试题中)
3 服务如何和Activity进行通讯:在服务里面发出广播。
   activity要和服务进行通信:
       1 绑定服务 调用服务里面的方法
       2 在Activity里面发送广告给服务里面的广播接收者
  服务和Activity进行通讯
       1 发送广播

4 如果你希望服务处理完成事情后自动停止,可以在服务里面调用stopSelf();(这样的情况只针对于startService()启动的服务)


面试题      
1 请说说intentintentfilter有什么区别?
intent:意图  是用来串联3大组件:Activity  Service  BroadcastReceiver  
组成:
action 动作                                                                                                                                               
data 数据
category  类别
type  数据的类型
extra 携带的额外参数
component 组件
flag  标记 new_task 在activity的外部启动activity

IntentFilter
java registerReceiver(receiver,filter);
解析清单文件的时候:intent-filter节点

例子:
MainActivity要去激活OtherAcivity
startActivity(new Intent(this,OtherActivity.class));

当你发起激活操作的时候,其实是向操作系统发出了一个指令,操作系统去帮你查找OtherActivity ,如果有就使用ActivityManager把OtherActivity启动,
如果没有找到  报一个notfoundActivityException .
1 该应用里面根本没有OtherActivity
2 OtherActivity没有在清单中配置

例子:
IntentFilter对象是何时被解析?
应用程序安装的时候,android系统会使用Pull解析解析清单文件  并且把数据进行了面向对象的封装。

手机里面是不是会有很多的应用,很多的应用也就是很多的包。很多的应用是很多的用户。很多的应用是很多的进程。

android还设计了一个类来管理所有的应用。
PackageManager


2 aidl:  进程间通讯   
java里面是不支持的。
api:  IBinder   实现类 Binder  java  

linux kernel(内核)驱动   他是android工程师添加的。进程间通讯。ipc  c代码


作业

用服务来完成的下载器。
Activity和service在两个应用里面。

设计:
1 界面
注意:此图是Activity和Service在同一应用里面的处理方式




下载资源

Doc笔记
课程视频代码
作业视频代码
点击下载
点击下载
点击下载





作者: 袁文博老师    时间: 2015-12-8 08:58
不明觉厉!!!
作者: jzh    时间: 2015-12-9 12:10
好好好好,真不错
作者: mm2015    时间: 2015-12-9 20:10
哥们不错呀。真好                             
作者: vip003    时间: 2015-12-9 21:10

作者: Xiiian    时间: 2015-12-10 09:26

作者: xk10360108    时间: 2015-12-10 20:07
虽然看不懂,但感觉好厉害的样子,等我学习到能看懂的时候再回来从看一次
作者: Id_820    时间: 2015-12-10 20:13
给力,给力。。。。
作者: 744919632    时间: 2015-12-10 21:40
基哥,更新啊。等着看呢。
作者: 孤独成瘾    时间: 2015-12-10 21:42
不错,虽然看不懂,但很激励人
作者: 邓浩宸    时间: 2015-12-11 12:36
加油黑马黑马
作者: 744919632    时间: 2015-12-11 13:43
加油,基哥最棒。
作者: 小欢    时间: 2015-12-11 16:40
我去,好详细啊,厉害
作者: 梅子派    时间: 2015-12-11 18:46
不明觉厉啊
作者: 梅子派    时间: 2015-12-11 18:47
不明觉厉啊
作者: 梅子派    时间: 2015-12-11 18:49
不明觉厉!!!
作者: 孤独成瘾    时间: 2015-12-11 21:30
厉害啊,赞一个
作者: 啊祥    时间: 2015-12-11 22:45
给力,虽然暂时还看不明白
作者: 林子大了    时间: 2015-12-12 16:24
辛苦
作者: Endless_paradox    时间: 2015-12-12 16:41
马克,收藏
作者: zfl920817    时间: 2015-12-12 23:27
大家好,我是新来的,希望在的朋友加我号,多聊聊
作者: peiyanda    时间: 2015-12-13 22:55
mark一下!
作者: 15225018025    时间: 2015-12-14 07:33
赞一个,支持一下!赞一个,支持一下!赞一个,支持一下!
作者: xiaoxiao2015    时间: 2015-12-14 10:43

作者: not@good@enough    时间: 2015-12-14 19:41
以现在的基础,完全看不懂
作者: 周亚飞    时间: 2015-12-15 08:32
马克,等待进就业班
作者: 水瓶座    时间: 2015-12-15 23:02
赞一下!!!!!!
作者: ToSina    时间: 2015-12-15 23:15
顶顶 顶顶...............
作者: Mr.zhao    时间: 2015-12-16 00:48
要看的明白,估计还有段时间

作者: 乐林荫    时间: 2015-12-16 14:01
非常有用,望持续更新
作者: waihuiquan    时间: 2015-12-16 19:06
好人啊,。好人
作者: “不务正业”    时间: 2015-12-16 21:14
先搞下来。好好准备先。。。顶。。。。
作者: a944090777    时间: 2015-12-17 13:56
zanyige!!!!!
作者: 洪志豪1994    时间: 2015-12-17 20:03
很不错,楼主辛苦了
作者: laiyubin    时间: 2015-12-17 20:53
看都看不懂晕,不明觉厉!
作者: pantianfeng    时间: 2015-12-18 01:22
。。。。。,
作者: schubertw    时间: 2015-12-18 17:54
基哥威武!!!
作者: HMWL    时间: 2015-12-18 22:12
不错 不错 赞一个
作者: labozx    时间: 2015-12-19 00:30
坚持就是胜利,爱拼才会赢!
作者: lxg8136223    时间: 2015-12-19 21:46
我去,厉害
作者: 18338762337    时间: 2015-12-20 18:38
学习中,新技能get
作者: 乐林荫    时间: 2015-12-21 00:06
很牛逼 很有用
作者: labozx    时间: 2015-12-21 00:28
爱拼才会赢!加油赞一个为努力的人。
作者: labozx    时间: 2015-12-21 00:29
爱拼才会赢!加油赞一个为努力的人。
作者: 唐洪超    时间: 2015-12-21 21:20
此处省略几个字,你懂的
作者: 孤独成瘾    时间: 2015-12-21 21:38
哈尔滨是个美丽的城市,有机会一定去
作者: 行走在消逝间    时间: 2015-12-21 22:27
好贴,赞一个
作者: 鳌少宝    时间: 2015-12-21 22:46
加油 加油 努力学习
作者: 18338762337    时间: 2015-12-22 10:49

学习中,顶顶顶
作者: houbofly    时间: 2015-12-22 22:03
赞一个,收藏
作者: tang9137    时间: 2015-12-22 22:34
加油每一天
作者: 18338762337    时间: 2015-12-23 08:33

666666666666
作者: birdy    时间: 2015-12-23 11:23
给力,虽然暂时还看不明白
作者: 韦丹艳58    时间: 2015-12-24 14:07
真心好!很全面
作者: 韦丹艳58    时间: 2015-12-24 14:09
真心全面很有用
作者: 韦丹艳58    时间: 2015-12-24 14:10
真心喜欢
作者: 韦丹艳58    时间: 2015-12-24 16:50
真心有用
作者: YOUTA    时间: 2015-12-24 17:02
好用啊,感谢楼主
作者: WaterTheGreat    时间: 2015-12-24 19:00
学习了!!!!!
作者: duluhuang    时间: 2015-12-24 20:06
666666666666666666666666666
作者: 青菜市场    时间: 2015-12-24 20:19
太厉害了
作者: 程程程程程92    时间: 2015-12-25 13:14
哥们不错
作者: 手有键盘心不慌    时间: 2015-12-25 22:32
十分有用!以后学安卓更方便了
作者: yifuyue    时间: 2015-12-25 23:17
写的真好
作者: 云鱼    时间: 2015-12-26 21:31
就业班的大神么
作者: 王如是    时间: 2015-12-27 00:38
黑马威武
作者: bowllboy    时间: 2015-12-27 15:11
不错的东西
作者: 爱hao者    时间: 2015-12-27 20:19
将来会懂的
作者: zjh742672607    时间: 2015-12-27 20:55
赞一个。
作者: lh951329230    时间: 2015-12-28 09:22
赞赞赞赞赞赞
作者: 谢光智    时间: 2015-12-28 13:06
666666666赞一个!
作者: 小小菜菜    时间: 2015-12-29 01:13
真心得好贴
作者: Accoss-x    时间: 2015-12-29 01:37
加油一起来一起奋斗
作者: peiyanda    时间: 2015-12-29 22:37

顶贴是一种态度!!!
作者: s616622575    时间: 2015-12-29 23:42
好东西多多分享,好人一生平安
作者: bowllboy    时间: 2015-12-30 18:02
虽然只看了标题,但是还是得说谢谢
作者: until    时间: 2015-12-30 22:10
厉害啊    确实厉害  佩服
作者: 笨笨真棒    时间: 2016-1-1 00:35
厉害厉害,多东西
作者: 1050498188    时间: 2016-1-2 00:44
总结的很好  
作者: yehua1026    时间: 2016-1-4 19:13
非常好非常好!!!
作者: peiyanda    时间: 2016-1-4 23:04
对于这个,我只想说,先马
作者: li514620797    时间: 2016-1-5 21:31
666666666666666666666666666666
作者: 猜不得先生    时间: 2016-1-6 11:50
666666666666666
作者: 韦丹艳58    时间: 2016-1-6 22:20
牛!!!!!!!!!!!!!!!!!!!!!!!!!!
作者: Smile灬笨笨    时间: 2016-1-7 00:10
4324353621637
作者: pengjk    时间: 2016-1-7 14:04
666666666666
作者: aiheima    时间: 2016-1-9 00:47
不明觉厉啊
作者: 122347    时间: 2016-1-9 10:47
厉害啊,赞一个
作者: qxz394731688    时间: 2016-1-9 15:30
好详细    赞一个
作者: zhou402981948    时间: 2016-1-9 23:03
顶顶顶顶顶顶顶顶顶顶顶顶顶顶
作者: 明日蜕变    时间: 2016-1-11 07:48
顶一个顶一个,赞
作者: Tkight    时间: 2016-1-12 16:57
好大一串代码。。
作者: xiangning    时间: 2016-1-12 23:56
赞 赞 赞
作者: number0kaidi    时间: 2016-1-13 23:44
干货,很受用,谢谢啦
作者: 1066715808    时间: 2016-1-14 08:54
好厉害啊
作者: 苗超维    时间: 2016-1-15 20:33
写的真多啊 ,真全 自己也得努力了
作者: txw126    时间: 2016-1-16 00:15
6666666666666666666
作者: 杨兵1    时间: 2016-1-17 11:11
辛苦了 基哥
作者: black习    时间: 2016-1-17 23:38
厉害啊1111
作者: 阿蛮    时间: 2016-1-18 23:41
现在凡是看到谁的技术分25以上的我就会非常的羡慕!




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2