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 个回复

正序浏览
坚持就是胜利,爱拼才会赢
回复 使用道具 举报
唉!!!!!!!!!!!!!!!!!
回复 使用道具 举报
感谢分享啊  好好学习一下
回复 使用道具 举报
学海无涯!~!!!!
回复 使用道具 举报
huhemingtiancai 来自手机 中级黑马 2016-5-2 15:45:26
275#
一起学习。
回复 使用道具 举报
虽然看不懂,但是依旧感觉很牛B
回复 使用道具 举报
虽然看不懂,但是依旧感觉很牛B
回复 使用道具 举报
看眼界 长见识。我还是基础班!
回复 使用道具 举报
总感觉好厉害的样子
回复 使用道具 举报
学习了。。。。
回复 使用道具 举报

虽然看不懂,但感觉好厉害的样子,等我学习到能看懂的时候再回来从看一次
回复 使用道具 举报
谢谢分享
回复 使用道具 举报
不错不错 赞一个 很给力
回复 使用道具 举报
必须顶!!!!
回复 使用道具 举报
win10设置SDK环境变量不成功
首先在用户变量设置:
新建一个变量名ANDROID_SDK_HOME,地址是E:\adt-bundle-windows-x86_64-20140702\sdk
环境变量下在path中添加%ANDROID_SDK_HOME%\build-tools和%ANDROID_SDK_HOME%\tools
win10系统下 ; 号似乎是自动添加的试过用分号也试过没用分号。cmd下输adb 显示不是内部命令
求助如何设置
回复 使用道具 举报
success560 来自手机 中级黑马 2016-4-29 12:35:06
264#
好好干好好刚
回复 使用道具 举报
赞赞赞!!!
回复 使用道具 举报
真不错~~~
回复 使用道具 举报
好帖 顶一下
回复 使用道具 举报
lrx 中级黑马 2016-4-26 23:46:41
260#
厉害厉害佩服佩服
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马