4 本地服务的启动方式
4.1 第一种
- 通过start方式开启服务:
- 使用service的步骤:
- 定义一个类继承 service
- manifest.xml文件中配置 service (当然as一键创建不用配置)
- 使用context的startService(Intent)方法启动服务
- 不使用时,调用stopService(Intent)方法停止服务
使用start方式启动的生命周期
onCreate()->onStartCommand()->onDestory();
如果服务已经开启,不会重复回调 onCreate() 方法,如果再次调用 startService()方法,service 而是会调用 onstart或者 onStartCommand()。停止服务需要调用 stopService() 方法,服务停止的时候回调 onDestory被销毁。
4.2 第二种
采用 bind 的 方式开启服务
- 定义一个类继承 Service
- 在manifest.xml 文件中注册 service
- 使用 context 的 bindService(Intent,ServiceConnection,int )方法启动Service
- 不再使用时,调用unbindService()方法停止该服务
生命周期,只会绑定一次,当多次调用绑定服务时,只会多次调用 startService()方法
Demo
public class ServiceDemo extends Service { private MyBinder binder=new MyBinder(); @Override public void onCreate() { super.onCreate(); Log.e("demo","onCreate创建"); } @Override public boolean onUnbind(Intent intent) { Log.e("demo","解绑"); return super.onUnbind(intent); } @Override public void onDestroy() { super.onDestroy(); Log.e("demo","销毁"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.e("demo","onStartCommand服务启动"); return super.onStartCommand(intent, flags, startId); } class MyBinder extends Binder { private CountDownTimer count; public void start(){ count = new CountDownTimer(Integer.MAX_VALUE,1000) { @Override public void onTick(long millisUntilFinished) { Toast.makeText(ServiceDemo.this, "启动啦", Toast.LENGTH_SHORT).show(); } @Override public void onFinish() { } }.start(); } public void onstop(){ if (count != null) { count.cancel(); count=null; } } } @Override public IBinder onBind(Intent intent) { Log.e("Demo","bind"); return binder; } }
public class MyServerConnection implements ServiceConnection { private ServiceDemo.MyBinder myBinder; /** * 第二个参数是Server中的onBind方法返回的。 * * @param name * @param service */ @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e("demo","开始"); myBinder = (ServiceDemo.MyBinder) service; myBinder.start(); } @Override public void onServiceDisconnected(ComponentName name) { myBinder.onstop(); } }
public class Main2Activity extends AppCompatActivity { MyServerConnection myServerConnection=new MyServerConnection(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); findViewById(R.id.btn_start).setOnClickListener(v -> { Log.e("demo","startService启动服务"); Intent intent=new Intent(this,ServiceDemo.class); bindService(intent,myServerConnection,BIND_AUTO_CREATE); }); findViewById(R.id.btn_stop).setOnClickListener(v -> { Log.e("demo","stopService服务关闭"); unbindService(myServerConnection); }); } }
5. 远程服务
步骤1:新建定义AIDL文件,并该声明服务需要向客户端的提供的接口
步骤2:在服务子类中实现AIDL中定义的接口方法,并定义生命周期的方法(onCreat,onBind(),blabla)
步骤3:在AndroidMainfest.xml中注册服务&声明为远程服务
客户端(客户端)
步骤1:拷贝服务端的AIDL文件到目录下
步骤2:使用Stub.asInterface接口获取服务器的活页夹,根据需要调用服务提供的接口方法
步骤3:通过意图指定服务端的服务名称和所在包,绑定远程服务
6. IntentService
IntentService是Service的子类,比普通的Service增加了额外的功能。先看Service本身存在两个问题:
- Service不会专门启动一条单独的进程,Service与它所在应用位于同一个进程中;
- Service也不是专门一条新线程,因此不应该在Service中直接处理耗时的任务;
IntentService特征:
- 会创建独立的worker线程来处理所有的Intent请求;
- 会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;
- 所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service;
- 为Service的onBind()提供默认实现,返回null;
- 为Service的onStartCommand提供默认实现,将请求Intent添加到队列中;
BroadcastReceiver-广播
1. 分类:
1.1 标准广播(Normal brodcasts)
标准广播是完全异步的,可以在几乎同一时刻被所有接受者接受到。因此他们之间没有任何先后顺序科研。这种广播效率比较高,但同时也意味着它是无法被截断的。
1.2 有序广播(Ordered broadcasts)
是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播。
1.3 本地广播 (Lolcal Brodcast) :
本地广播,即只在APP内传播,安全性高。
2 发送广播
Context.sendBroadcast() 发送的是普通广播,所有订阅者都有机会获得并进行处理。
Context.sendOrderedBroadcast() 发送的是有序广播,系统会根据接收者声明的优先级别按顺序逐个执行接收者,前面的接收者有权终止广播(BroadcastReceiver.abortBroadcast()),如果广播被前面的接收者终止,后面的接收者就再也无法获取到广播。对于有序广播,前面的接收者可以将处理结果通过setResultExtras(Bundle)方法存放进结果对象,然后传给下一个接收者,通过代码:Bundle bundle =getResultExtras(true))可以获取上一个接收者存入在结果对象中的数据。 系统收到短信,发出的广播属于有序广播。如果想阻止用户收到短信,可以通过设置优先级,让你们自定义的接收者先获取到广播,然后终止广播,这样用户就接收不到短信了。
步骤:
1,自定义一个类继承BroadcastReceiver
2,重写onReceive方法
3,在manifest.xml中注册
需要注意的是:BrodcastReceiver生命周期很短
如果需要在onReceiver 完成一些耗时操作,应该考虑在Service中开启一个新线程处理耗时操作,不应该在 BrodcastReceiver中开启一个新的线程,因为BroadcstReceiver生命周期很短,在执行完 onReceiver 以后就结束,如果开启一个新的线程,可能出现 BroadcastRecevier 退出以后线程还在,而如果 BroadcastReceiver 所在的进程结束了,该线程就会被标记为一个空线程,根据 Android 的内存管理策略,在系统内存紧张的时候,会按照优先级,结束优先级低的线程,而空线程无异是优先级最低的,这样就可能导致 BroadcastReceiver启动的子线程不能执行完成。
Demo
2.1 静态注册
public class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.e("demo", "接收到一条消息"); } }
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main4); findViewById(R.id.btn_send_Nor).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent("xxx"); sendBroadcast(intent); } }); } }
//xml <receiver android:name=".BroadcstReceiver.MyReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="xxx"/> </intent-filter> </receiver>