A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 allen927 于 2015-12-8 08:55 编辑



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

android基础Day08(绑定服务)


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

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


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


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

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





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


总结


代码

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笔记
课程视频代码
作业视频代码
点击下载
点击下载
点击下载




点评

l厉害  发表于 2015-12-9 21:26

280 个回复

倒序浏览
不明觉厉!!!
回复 使用道具 举报
好好好好,真不错
回复 使用道具 举报
哥们不错呀。真好                             
回复 使用道具 举报
vip003 来自手机 中级黑马 2015-12-9 21:10:36
报纸
回复 使用道具 举报
回复 使用道具 举报
虽然看不懂,但感觉好厉害的样子,等我学习到能看懂的时候再回来从看一次
回复 使用道具 举报
Id_820 中级黑马 2015-12-10 20:13:24
8#
给力,给力。。。。
回复 使用道具 举报
基哥,更新啊。等着看呢。
回复 使用道具 举报
孤独成瘾 来自手机 中级黑马 2015-12-10 21:42:33
10#
不错,虽然看不懂,但很激励人
回复 使用道具 举报
邓浩宸 来自手机 中级黑马 2015-12-11 12:36:43
11#
加油黑马黑马
回复 使用道具 举报
加油,基哥最棒。
回复 使用道具 举报
小欢 中级黑马 2015-12-11 16:40:41
13#
我去,好详细啊,厉害
回复 使用道具 举报
不明觉厉啊
回复 使用道具 举报
不明觉厉啊
回复 使用道具 举报
不明觉厉!!!
回复 使用道具 举报
孤独成瘾 来自手机 中级黑马 2015-12-11 21:30:15
17#
厉害啊,赞一个
回复 使用道具 举报
啊祥 来自手机 中级黑马 2015-12-11 22:45:47
18#
给力,虽然暂时还看不明白
回复 使用道具 举报
辛苦
回复 使用道具 举报
马克,收藏
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马