Android的四大组件之一 Service
一 Service概念
- Service意为:服务,是一种运行时用户不可见的活动机制。可以理解为它是一个没有布局的Activity。
- 典型的场景:音乐后台播放、后台下载。
- 注意:Service不同于子线程,Service是运行在主线程中的,因此不能进行耗时操作。
二 创建Service
非绑定式:
在MyService类中
package com.example.service.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
public class MyService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d("666", "onBind: ");
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.d("666", "onCreate: ");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("666", "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
}
<service android:name=".service.MyService"></service> //注册Service
在xml布局文件中加入以下代码
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="创建Service"
android:textAllCaps="false"
android:onClick="startService"
/>
在MainActivity中加入以下代码
public void startService(View view) {
Intent intent = new Intent(this, MyService.class);
startService(intent);
}
成功创建Service的效果图
三 Service的类型
按启动方式分
绑定式:
在MyBindService类中
package com.example.service.service;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
public class MyBindService extends Service {
public void test(){
Log.d("000", "test: 这是MyBindService里的test方法");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d("000", "onBind: ");
return new MyBinger(this);
}
@Override
public void onCreate() {
super.onCreate();
Log.d("000", "onCreate: ");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("000", "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("000", "onDestroy: ");
}
@Override
public boolean onUnbind(Intent intent) {
Log.d("000", "onUnbind: ");
return super.onUnbind(intent);
}
public class MyBinger extends Binder{
private MyBindService mMyBindService;
public MyBinger(MyBindService bindService) {
mMyBindService = bindService;
}
public void test(){
Log.d("000", "test: MyBinder被调用了test方法");
mMyBindService.test();
}
}
}
在Manifest文件中注册这个Service
<service android:name=".service.MyBindService" />
在xml布局文件中加入以下代码
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="绑定Service"
android:textAllCaps="false"
android:onClick="bindService"
/>
在MainActivity中加入以下代码
private MyBindService.MyBinger mBinder = null;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinder = (MyBindService.MyBinger)service;
mBinder.test();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
public void bindService(View view) {
Intent intent = new Intent(this, MyBindService.class);
bindService(intent,conn,BIND_AUTO_CREATE);
}
四 Service的生命周期
- 非绑定式Service的生命周期
- 绑定式Service的生命周期
五 前台Service
概念:
使用场景:
启动:
一般是在一个普通Service的onCreate方法中将这个Service提升为前台Service
结束:
Android 的四大组件之一 Broadcast
一 Broadcase概念
是用来互相通信(传递信息)的一种机制
- 组件间(应用内)通信
- 进程间通信
二 Broadcase 组成部分
三 Broadcase基本使用方法
Activity内部之间进行通信示例:
在xml布局文件设置一个按钮,代码如下
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="32dp"
android:text="发送广播"
android:onClick="sendBroadTest"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
在MainActivity中,代码如下
package com.example.broadcase;
import androidx.appcompat.app.AppCompatActivity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static final String KEY_RESULT = "key_send1";
private String ACTION_UPLOAD_RESULT = "my_broadcast1";
private BroadcastReceiver mBroadcaseReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if(intent!=null){
String extra = intent.getStringExtra(KEY_RESULT);
Toast.makeText(context,"收到广播了:" + extra,Toast.LENGTH_SHORT).show();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_UPLOAD_RESULT);
registerReceiver(mBroadcaseReceiver,intentFilter);
}
public void sendBroadTest(View view) {
//创建Intent
Intent intent = new Intent();
intent.setAction(ACTION_UPLOAD_RESULT);
intent.putExtra(KEY_RESULT,"这是发送的广播1");
//发送广播
sendBroadcast(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mBroadcaseReceiver);
}
}
效果图如下
四 静态广播与动态广播
概念:
按广播接收器的注册方式划分的
注意:同时注册时,动态广播优先于静态广播
静态广播的注册与使用
注意:标签是用来过滤广播信息的,其值是一个字符串
动态广播的注册与使用
首先,也是创建广播接收器类:MyBroadcastReceiver.java
然后,在代码中注册,一般是在Activity的onCreate方法中
五 无序广播与有序广播
区别:
按广播接收顺序划分
无序广播的使用
一般发送的广播默认就是无序广播
在NormalBroadcastActivity中,代码如下
package com.example.broadcase.order;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import com.example.broadcase.R;
public class NormalBroadcastActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_normal_broadcast);
}
public void sendNormalBroadcast(View view) {
Intent intent = new Intent();
intent.setAction("my_broadcaster_action");
intent.setPackage(getPackageName());
sendBroadcast(intent);
}
}
在布局文件中设置一个按钮,代码如下
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/wuxu"
android:layout_margin="16dp"
android:text="无序广播测试"
android:textSize="15sp"
/>
在AndroidMabifest.xml中注册,代码如下
<receiver android:name=".receiver.MyBroadcastRecevier1">
<intent-filter>
<action android:name="my_broadcaster_action" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.MyBroadcastRecevier2">
<intent-filter >
<action android:name="my_broadcaster_action" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.MyBroadcastRecevier3">
<intent-filter >
<action android:name="my_broadcaster_action" />
</intent-filter>
</receiver>
创建了三个接收广播的类,分别为MyBroadcastRecevier1, MyBroadcastRecevier2, MyBroadcastRecevier3,代码如下
package com.example.broadcase.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class MyBroadcastRecevier1 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(intent != null){
Bundle extras = intent.getExtras();
String data = "";
if(extras != null){
data = extras.getString("name");
}
Log.d("888", " MyBroadcastRecevier1 onReceive: " + data);
}
}
}
package com.example.broadcase.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class MyBroadcastRecevier2 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(intent != null){
Bundle extras = intent.getExtras();
String data = "";
if(extras != null){
data = extras.getString("name");
}
Log.d("888", " MyBroadcastRecevier2 onReceive: " + data);
}
}
}
package com.example.broadcase.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class MyBroadcastRecevier3 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(intent != null){
Bundle extras = intent.getExtras();
String data = "";
if(extras != null){
data = extras.getString("name");
}
Log.d("888", " MyBroadcastRecevier3 onReceive: " + data);
}
}
}
效果图
结论:无序广播的信息同时被接收
有序广播的使用
1 设置优先级
2 注册
3 发送有序广播
效果图:
结论:
设置广播接收器的优先级,优先级越大越先收到广播
截断有序广播
在广播接收器里调用abortBroadcast()方法即可阻断有序广播的传递
在第2个广播接收器中调用aborBroadcast()方法,截断第1个广播接收器的信息,效果图如下
修改有序广播
- 通过setResultData(str)方法,向下游广播接收器传递额外字符串信息。
- 向下游广播接收器通过getResultData方法接受信息。
在第3个广播接收器中追加广播信息,代码如下
package com.example.broadcase.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class MyBroadcastRecevier3 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(intent != null){
Bundle extras = intent.getExtras();
String data = "";
if(extras != null){
data = extras.getString("name");
extras.putString("name","这是广播3");
setResultExtras(extras);
}
Log.d("888", " MyBroadcastRecevier3 onReceive: " + data);
}
}
}
在第2个广播接收器中接受信息,代码如下
package com.example.broadcase.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class MyBroadcastRecevier2 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(intent != null){
Bundle extras = intent.getExtras();
String data = "";
if(extras != null){
data = extras.getString("name");
}
Bundle extraResult = getResultExtras(true);
String newName = extraResult.getString("name");
Log.d("888", " MyBroadcastRecevier2 onReceive: " + data + ",newName:" + newName);
abortBroadcast();
}
}
}
在发送广播的Activity中,加入以下代码
public void sendOrderBroadcast(View view) {
Intent intent = new Intent();
intent.setAction("my_broadcaster_action");
intent.setPackage(getPackageName());
Bundle bundle = new Bundle();
bundle.putString("name","这是有序广播");
intent.putExtras(bundle);
sendOrderedBroadcast(intent,null);
}
效果图如下
六 本地广播与全局广播
按广播传播范围划分
- 本地广播,仅在本App内部传播,其他App收不到,保证了数据的安全性。
- 全局广播,可以在整个手机所有APP之间传播,会有安全性问题。普通广播默认就是全局广播。
本地广播的使用
- 广播接收器的创建,与正常广播一样,继承BroadcastReceiver
- 只能使用动态注册的方式,这里用到了一个类:LocalBroadcastManager
- 解除与发送也比较简单,使用LocalBroadcastManager调用原来的方法即可。