android应用程序的四大组件
-
activity 界面
-
content provider 内容提供者 暴露应用程序私有的数据
-
broadcast receiver 接受广播消息
-
service 后台的服务
四大组件都要在清单文件配置,特殊广播接受者(代码,清单文件)
Service
一个组件长期后台运行,没有界面。 简单的理解:service理解成一个没有界面长期运行的activity。
配置一个服务
第一步 创建一个类,然后继承Service类,在创建的类中写服务的功能
第二步 因为是服务,所以要在配置文件中进行声明
<service android:name="c.c.c.c.MyService"></service>
第三步 开启服务
Intent intent = new Intent(this, MyService.class); startService(intent);
服务的生命周期 (重要)
开启服务
onCreate() -->onStartCommand-->onStart(过时) -->ondestory(销毁) 如果服务已经开启了,就不会重新调用oncreate方法,服务只会被创建一次。
//开启服务 public void start(View view){ Intent intent = new Intent(this,MyService.class); startService(intent); } //停止服务 public void stop(View view){ Intent intent = new Intent(this,MyService.class); stopService(intent); } 停止服务业可以直接通过ddms,选中进程然后关掉
服务有两种开启方法
-
startService(); 直接开启服务,服务一旦启动跟调用者(开启者没有任何关系)
调用者activity退出了,服务还是继续运行活的好好的。 调用者activity,没法访问服务里面的方法。
-
bindService(); 绑定开启服务,服务和开启者(调用者)有密切的关系。
** 不求同时生,但求同时死。只要activity挂了,服务跟着挂了。** 调用者activity,可以调用服务里面的方法。
绑定方式开启服务,调用服务方法的流程 (重要)
绑定服务的生命周期 oncreate()-->onbind()--->onDestory(); 不会调用onstart()方法 和 onstartCommand()方法。
绑定的过程
在activity中
第一步 使用bindService的方式开启服务。
bindService(intent, new MyConn(), Context.BIND_AUTO_CREATE);
第二步 实现一个MyConn 服务与activity的通讯频道(中间人的联系渠道)
private class MyConn implements ServiceConnection{ /** * 当服务被成功绑定的时候执行的方法,得到中间人。 */ @Override public void onServiceConnected(ComponentName name, IBinder service) { binder = (MyBinder) service; } /** * 当服务失去绑定的时候调用的方法。当服务突然异常终止的时候 */ @Override public void onServiceDisconnected(ComponentName name) { } }
在MyService中
第三步 服务成功绑定的时候 会执行onBinde方法,返回中间人
public class MyBinder extends Binder{ /** * 内部人员帮助我们调用服务的方法。 */ public void callMethodInService(){ methodInService(); } }
第四步 在activity代码里面通过中间人调用服务的方法。
public void impl(View view){ mybinder.callMethodInService(); }
第五步 解绑服务
public void jiebang(View view){ unbindService(conn); }
抽取接口,隐藏私有方法。
将要让中间人能够执行的方法写进一个接口中,并且让中间人实现只能执行的方法的接口,然后调用者在创建中间人的时候,调用接口中的方法
见代码
调用者activity
public class MainActivity extends Activity { IService binder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } /** * 绑定服务 * @param view */ public void bind(View view){ Intent intent = new Intent(this,MyService.class); //1.开启服务的时候 必须使用 绑定的方式开启。 System.out.println("1. 第一步,开启服务 bind方式。"); bindService(intent, new MyConn(), Context.BIND_AUTO_CREATE); } private class MyConn implements ServiceConnection{ /** * 当服务被成功绑定的时候执行的方法 */ @Override public void onServiceConnected(ComponentName name, IBinder service) { //3.通讯频道得到服务成功绑定的消息,得到中间人 System.out.println("3. 第三步,成功绑定服务后,在通讯频道里面得到中间人"+service.toString()); binder = (IService) service; } /** * 当服务失去绑定的时候调用的方法。当服务突然异常终止的时候 */ @Override public void onServiceDisconnected(ComponentName name) { } } /** * 调用服务的方法 * @param view */ public void call(View view){ System.out.println("4.调用中间人的方法。"); binder.callMethodInService(3000); } }
对外提供服务的方法
public interface IService { public void callMethodInService(int money); }
服务本身的方法(服务本身有些敏感的方法不能让外部调用)
public class MyService extends Service { /** * 官员的小蜜 。潜规则 * * @author Administrator * */ //重点地方!!!!!!!!!!!!!!!!!!!!!!!!!!!!! private class MyBinder extends Binder implements IService{ /** * 内部人员帮助我们调用服务的方法。 * * @param money * 如果大于2000 执行,小于两千 ,给个提示 */ public void callMethodInService(int money) { if (money >= 2000) { System.out.println("5.中间人,调用服务的方法"); methodInService(); }else{ Toast.makeText(MyService.this, "再准备点,你懂的", 0).show(); } } public void playMajiang(){ System.out.println("一起打麻将"); } public void xisangna(){ System.out.println("一起洗桑拿"); } } /** * 官员内部的方法,为人民币服务,没有2000块钱是不会执行的。 */ public void methodInService() { Toast.makeText(this, "我是服务内部的方法,我被调用了。", 0).show(); } @Override public IBinder onBind(Intent intent) { MyBinder mybinder = new MyBinder(); System.out.println("2. 第二步 服务被成功绑定了。---onbind,返回IBinder代理人" + mybinder.toString()); return mybinder;// 返回中间人 } @Override public void onCreate() { System.out.println("服务被创建了---oncreate()"); super.onCreate(); } @Override public void onDestroy() { System.out.println("服务被销毁了"); super.onDestroy(); } }
远程服务
aidl: android interface definition language(安卓接口定义语言)
Local-side IPC implementation
本地内部进程通信的实现。
什么是远程服务:服务的代码在另外一个应用程序里面。 什么是本地服务:服务的代码在当前应用程序里面。
以上面的代码为例
服务端需要做的配置
1.远程服务修改接口文件的扩展名为aidl,删除访问修饰符public
IService.java 改为 IService.aidl
interface IService { void callMethodInService(int money); }
2.修改IBinder的实现类 extends IService.Stub
private class MyBinder extends IService.Stub{ /** * 内部人员帮助我们调用服务的方法。 * * @param money * 如果大于2000 执行,小于两千 ,给个提示 */ public void callMethodInService(int money) { if (money >= 2000) { System.out.println("5.中间人,调用服务的方法"); methodInService(); }else{ Toast.makeText(MyService.this, "再准备点,你懂的", 0).show(); } }
3,对外提供IService.aidl
4.对外提供服务
<service android:name="com.itheima.remoteservice.MyService"> <intent-filter > <action android:name="com.itheima.remote.service"/> </intent-filter> </service>
客户端配置
第一步.访问远程服务的时候必须使用绑定的方式开启(通过意图开启)
public void bind(View view){ //1.开启服务的时候 必须使用 绑定的方式开启。 System.out.println("1. 第一步,开启服务 bind方式。"); Intent intent = new Intent(); intent.setAction("com.itheima.remote.service"); bindService(intent, new MyConn(), Context.BIND_AUTO_CREATE); }
第二步.在调用者的工程里面,把远程服务的aidl文件拷贝过来,保证包名也完全一致。
第三步.在调用者里面强制类型转化
iService = com.itheima.remoteservice.IService.Stub.asInterface(service);
private class MyConn implements ServiceConnection{ /** * 当服务被成功绑定的时候执行的方法 */ @Override public void onServiceConnected(ComponentName name, IBinder service) { //3.通讯频道得到服务成功绑定的消息,得到中间人 System.out.println("3. 第三步,成功绑定服务后,在通讯频道里面得到中间人"+service.toString()); iService = com.itheima.remoteservice.IService.Stub.asInterface(service); } /** * 当服务失去绑定的时候调用的方法。当服务突然异常终止的时候 */ @Override public void onServiceDisconnected(ComponentName name) { } }
第四步.调用远程服务的方法
public void call(View view){ try { iService.callMethodInService(5000); } catch (RemoteException e) { e.printStackTrace(); } }