Service是四大组件之一。与Activity相似,但Service一直在后台运行,没有用户界面,具有自己的生命周期。
BroadcastReveiver是四大组件之一,就像一个全局事件的事件监听器,用于监听系统发出的Broadcast。通过使用BroadcastReceiver可在不同应用程序之间通信。
1.Service
创建配置Service
1.定义一个继承Service的子类
2.在AndroidManifest.xml中配置该Service
Service 与Activity都是从Context派生出来,都可以调用Context里定义的getResources()\getContentResolver()等方法。
Service中也定义了一些列生命周期。
- IBinder onBind(Intent intent):该方法是Service子类必须实现的方法。个i啊方法返回一个Ibinder对象,应用程序可通过该对象与Service组件通信。
- void onCreate():在该Service第一次被创建后将立即回调该方法
- void onDestory():再改Service被关闭之前会回调该方法
- void onStartCommand(Intent intent,int flags,int startId):该方法的早期版本是void onStart(Intent intent,Int StartId),每次客户端调用startService(Intent)方法启动该Service时都会调用该方法
- boolean onUnbind(Intent intent):当该Service上绑定的所有客户端都断开连接时将会返回该方法
配置Service使用<service../>元素可指定如下常用属性
- name:指定该Service的实现类类名
- exported:指定该Service是否能被其他APP启动。如果在配置该Service时指定了<intent-filter../>子元素,则该属性默认为true.
- permission:指定启动该Service所需的权限
- process:指定该Service所处的进程,该Service组件默认处于该App所在的进程中。
例子:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<service android:name=".FirstService"></service>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
启动和停止Service
代码:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button start = findViewById(R.id.button);
Button close = findViewById(R.id.button2);
Intent intent = new Intent(this, FirstService.class);
//java8支持lamdba
start.setOnClickListener(view -> startService(intent));
close.setOnClickListener(view ->stopService(intent));
}
}
注意:从安卓5.0开始,谷歌要气必须使用显式Intent启动Service组件。
绑定本地Service与之通信(实例)
如果Service和访问者之间需要进行方法调用或数据交换,则应该使用bindService()和unbindService()方法启动、关闭Service。
- bindService(Intent service,ServiceConnnection conn,int flags)
conn:该参数是一个ServiceConnection对象,用于监听访问者与Service之间的连接情况。
flags:制定绑定是否创建Service(如果Service未创建)。该参数可指定0(不自动创建)或BIND_AUTO_CREATE(自动创建)
实例:
Service生命周期
Service的生命周期随Service的启动方式。
IntentService
是Service子类。
Service存在的问题
- 不会专门启动一个单独的进程,Service与他所在应用位于同一个进程中。
- 不是一条新的线程,因此不应该在Service中直接处理耗时的任务。
IntentService弥补了Service的这两个不足,IntentService使用队列来管理请求Intent,每当客户端代码通过Intent请求启动IntentService时,IntentService会将该Intent假如队列中,然后开启一条worker线程来处理该Intent。对于异步的startService()请求,IntentService会按次序依次处理队列中的Intent,该线程保证同一时刻只处理一个Intent。
IntentService具有如下特征:
- 会创建单独的worker线程来处理所有的Intent请求
- 会创建单独的worker线程来处理onHandleintent()方法实现的代码,开发者无需处理多线程问题
- 当所有请求处理完成后,IntentService会自动停止,开发者无须调用stopSelf()方法来停止该Service
- 为Service的onBind()方法提供了默认实现,默认实现的onBind()方法返回null
- 为Service的onStartCommand()方法提供了默认实现,该实现会将请求Intent添加到队列中
实例
2.跨进程调用Service(AIDL Service)
简介
为了实现跨进程通信(Interprocess Communication,简称IPC),Android提供了AIDL Service.
AIDL Service与Java中的RMI(远程方法调用)存在一定的相似之处,都是先定义一个远程调用接口,然后为该接口提供一个实现类。
不同点:客户端访问Service时,Android并不是直接返回Service对象给客户端,Service将他的代理对象(IBinder对象)通过onBind()方法返回给客户端。本地Service的onBind()方法会直接把IBinder对象本身传给客户端的ServiceConnection的onServiceConnected方法的第二个参数;远程Service的onBind()方法只是将IBinder对象的代理传给客户端的ServiceConnection的onServiceConnection方法的第二个参数。
当客户端获取了远程Service的IBinder对象的代理之后,接下来可以通过该IBinder对象来回调远程Service的属性和方法了。
创建AIDL文件
Android需要AIDL(Android Interface Definition Language,Android接口定义语言)来定义远程接口。
AIDL定义接口的源代码必须以.aidl结尾
在AIDL接口中用到的数据类型,除基本类型、Spring、List、Map、CharSequence之外,其它类型的全都需要导包(即使在同一个包中也需要导包)
x.aidl
package xxxx.xxxx.xxxx;
interface Icat
{
Stinrg getColor();
String getWeight();
}
将接口暴露给客户端
public class AidlService extends Service
{
private CatBinder catBinder;
private Timer timer = new Timer();
private String[] colors = new String[]{"红色", "黄色", "黑色"};
private double[] weights = new double[]{2.3, 3.1, 1.58};
private String color;
private double weight;
// 继承Stub,也就是实现了ICat接口,并实现了IBinder接口
class CatBinder extends ICat.Stub
{
@Override
public String getColor()
{
return AidlService.this.color;
}
@Override
public double getWeight()
{
return AidlService.this.weight;
}
}
@Override public void onCreate()
{
super.onCreate();
catBinder = new CatBinder();
timer.schedule(new TimerTask()
{
@Override public void run()
{
// 随机改变Service组件内color、weight属性的值
int rand = (int) (Math.random() * 3);
color = colors[rand];
weight = weights[rand];
}
},0, 800);
}
@Override public IBinder onBind(Intent intent)
{
/* 返回catBinder对象
* 在绑定本地Service的情况下,该catBinder对象会直接
* 传给客户端的ServiceConnection对象
* 的onServiceConnected方法的第二个参数
* 在绑定远程Service的情况下,只将catBinder对象的代理
* 传给客户端的ServiceConnection对象
* 的onServiceConnected方法的第二个参数
*/
return catBinder; // ①
}
@Override public void onDestroy()
{
timer.cancel();
}
}
配置
<!-- 定义一个Service组件 -->
<service android:name=".AidlService" >
<intent-filter>
<action android:name="org.crazyit.aidl.action.AIDL_SERVICE" />
</intent-filter>
</service>
客户端访问AIDL Service
1.创建SerivceConnection对象
5.以ServiceConnection对象作为参数,调用Context的bindService()方法绑定原创Service
public class MainActivity extends Activity
{
private ICat catService;
private ServiceConnection conn = new ServiceConnection()
{
@Override public void onServiceConnected(ComponentName name, IBinder service)
{
// 获取远程Service的onBind方法返回的对象的代理
catService = ICat.Stub.asInterface(service);
}
@Override public void onServiceDisconnected(ComponentName name)
{
catService = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button getBn = findViewById(R.id.get);
TextView colorTv = findViewById(R.id.color);
TextView weightTv = findViewById(R.id.weight);
// 创建所需绑定的Service的Intent
Intent intent = new Intent();
intent.setAction("org.crazyit.aidl.action.AIDL_SERVICE");
// 设置要启动的Service所在包,也就是将该Intent变成所谓的显式Intent
intent.setPackage("org.crazyit.service");
// 绑定远程Service
bindService(intent, conn, Service.BIND_AUTO_CREATE);
getBn.setOnClickListener(view -> {
// 获取并显示远程Service的状态
try {
colorTv.setText("名字:" + catService.getColor());
weightTv.setText("重量:" + catService.getWeight());
} catch (RemoteException e) {
e.printStackTrace();
}
});
}
@Override public void onDestroy()
{
super.onDestroy();
// 解除绑定
this.unbindService(conn);
}
}
3.电话管理器(TelephonyManager)
略
4.短信管理器(SmsManager)
略
5.音频管理器(AudioManager)
略
6.震动器(Vibrator)
vibrate(VibrationEffect vibe):控制手机按VibrationEffect效果执行震动
vibrate(VibrationEffect vibe,AudioAttributes attributes):控制手机按VibrationEffect效果执行震动,并执行AudioAttributes指定的声音效果
cancel():关闭手机震动
7.手机闹钟服务(AlarmManager)
略
8.广播接收器
简介:
四大组件之一。用于监听系统全局的广播消息。Android8要求启动BroadcastReceiver的Intent必须是显式Intent。
程序启动BroadcastReceiver需要两步
1.创建需要启动的BroadcastReceiver的Intent
2.调用Context的sendBroadcast()或sendOrderedBroadcast()方法来启动制定的BroadcastReceiver
BroadcastReceiver属于系统级的监听器,拥有自己的进程,只要存在与之匹配的Intent被广播出来,BroadcastReceiver就会被激发。
实现BroadcastReceiver:重写BroadcastReceiver的onReceive(Context context,Intent intent)方法
接着指定该BroadcastReceiver能匹配的Intent
1.使用代码进行指定
Intent filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED")
IncomingSMSReceiver receiver = new IncomingSMSReceiver()
registerReceiver(receiver, filter)
2.按AndroidManifest.xml文件中配置
<receiver android:name=".MyReceiver" android:enabled="true"
android:exported="false">
<intent-filter>
<!-- 指定该BroadcastReceiver所响应的Intent的Action -->
<action android:name="org.crazyit.action.CRAZY_BROADCAST" />
</intent-filter>
</receiver>
在配置<reveiver.../>元素时可指定如下常用属性
- name
- exported
- label
- permission
- process
每次系统Broadcast事件发生后,系统都会创建对应的BroadcastReceiver实例,并自动触发他的onReceiver()方法,执行完该方法,BroadcastReceiver实例就会被销毁。
如果BroadcastReceiver的onReceiver()方法不能再10秒内完成,Android会认为该程序无响应,弹出ANR(Application No Response)对话框。
如果需要根据Broadcast完成比较耗时的操作,可以考虑通过Intent启动一个Service来完成,
如果BroadcastReceiver所在的进程结束了,虽然该进程内还有用户启动的新线程,但由于进程内部包含任何活动组件,系统可能在内存紧张时优先结束该进程,导致BroadcastReceiver启动的子线程无法完成,
发送广播
public class MainActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取程序界面中的按钮
Button sendBbn = findViewById(R.id.send);
sendBbn.setOnClickListener(view -> {
// 创建Intent对象
Intent intent = new Intent();
// 设置Intent的Action属性
intent.setAction("org.crazyit.action.CRAZY_BROADCAST");
intent.setPackage("org.crazyit.broadcast");
intent.putExtra("msg", "简单的消息");
// 发送广播
sendBroadcast(intent);
});
}
}
public class MyReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "接收到的Intent的Action为:" + intent.getAction()
+ "\n消息内容是:" + intent.getStringExtra("msg"),
Toast.LENGTH_LONG).show();
}
}
配置
<receiver android:name=".MyReceiver" android:enabled="true"
android:exported="false">
<intent-filter>
<!-- 指定该BroadcastReceiver所响应的Intent的Action -->
<action android:name="org.crazyit.action.CRAZY_BROADCAST" />
</intent-filter>
</receiver>
有序广播
Broadcast分为Normal Broadcast(普通广播)和Ordered Broadcast(有序广播)
Normal Broadcast(普通广播)
是完全异步的,可以在同一时刻(逻辑上)被所有接收者收到,消息的传递效率比较高。但接收者不能将处理结果传递给下一个接收者,并且无法终止Broadcast Intent的传播
Ordered Broadcast(有序广播)
Ordered Broadcast的接收者将按照预先声明的优先级依次接收Broadcast。优先接收到Broadcast的接收者可以通过setResultExtras(Bundle)方法将处理结果存入Broadcast中,然后传给下一个接收者,下一个接收者通过Bundle bundle = getResultExtras(true)获取上一个接收者存入的数据。优先接收到Broadcast的接收者可以调用BroadcastReceiver的abortBroadcast()方法终于Broadcast。后面的广播接收者无法收到。
public class MainActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取程序中的send按钮
Button sendBn = findViewById(R.id.send);
sendBn.setOnClickListener(view -> {
// 创建Intent对象
Intent intent = new Intent();
intent.setAction("org.crazyit.action.CRAZY_BROADCAST");
intent.setPackage("org.crazyit.broadcast");
intent.putExtra("msg", "简单的消息");
// 发送有序广播
sendOrderedBroadcast(intent, null);
});
}
}
public class MyReceiver1 extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "接收到的Intent的Action为:" +
intent.getAction() + "\n消息内容是:" + intent.getStringExtra("msg"),
Toast.LENGTH_SHORT).show();
// 创建一个Bundle对象,并存入数据
Bundle bundle = new Bundle();
bundle.putString("first", "第一个BroadcastReceiver存入的消息");
// 将bundle放入结果中
setResultExtras(bundle);
// 取消Broadcast的继续传播
abortBroadcast(); // ①
}
}
public class MyReceiver2 extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
Bundle bundle = getResultExtras(true);
// 解析前一个BroadcastReceiver所存入的key为first的消息
String first = bundle.getString("first");
Toast.makeText(context, "第一个Broadcast存入的消息为:"
+ first, Toast.LENGTH_LONG).show();
}
}
<receiver android:name=".MyReceiver1">
<intent-filter android:priority="20">
<action android:name="org.crazyit.action.CRAZY_BROADCAST" />
</intent-filter>
</receiver>
<receiver android:name=".MyReceiver2">
<intent-filter android:priority="0">
<action android:name="org.crazyit.action.CRAZY_BROADCAST" />
</intent-filter>
</receiver>
9.接收系统广播消息
Android常见的广播Action常量(参考Android API 关于Intent的说明)
- ACTION_AIRPLANE_MODE_CHANGED//关闭或打开飞行模式时的广播
- ACTION_BATTERY_CHANGED//充电状态,或者电池的电量发生变化
- ACTION_BATTERY_LOW//表示电池电量低
- ACTION_BATTERY_OKAY//表示电池电量充足,即从电池电量低变化到饱满时会发出广播
- ACTION_BOOT_COMPLETED//在系统启动完成后,这个动作被广播一次(只有一次)。
- ACTION_SHUTDOWN//系统被关闭
通过使用BroadcastReceiver来监听特殊的广播,即可让应用随系统执行特定的操作。
实例:开机自动运行的Activity
public class LaunchReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
Intent tIntent = new Intent(context
, MainActivity.class);
tIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// 启动指定Activity
context.startActivity(tIntent);
}
}
配置BroadcastReceiver
<!-- 定义一个BroadcastReceiver,监听系统开机广播 -->
<receiver android:name=".LaunchReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
增加权限
<!-- 授予应用程序访问系统开机事件的权限 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
实例:手机电量提示
手机电量发生改变时,系统会对外发送Intent的Ation为ACTION_BATTERY_CHANGED常量的广播;电量过低,发送Intent的Ation为ACTION_BATTERY_LOW常量的广播。通过开发对应Intent的BroadcastReceiver,可让系统对手机点亮进行提示。
public class BatteryReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
Bundle bundle = intent.getExtras();
// 获取当前电量
int current = bundle.getInt("level");
// 获取总电量
int total = bundle.getInt("scale");
// 如果当前电量小于总电量的15%
if (current * 1.0 / total < 0.15)
{
Toast.makeText(context, "电量过低,请尽快充电!", Toast.LENGTH_LONG).show();
}
}
}
主:
IntentFilter batteryfilter = new IntentFilter();
// 设置该Intent的Action属性
batteryfilter.addAction(Intent.ACTION_BATTERY_CHANGED);
// 注册BatteryReceiver
registerReceiver(new BatteryReceiver(), batteryfilter);
BatteryManager bm = (BatteryManager) getSystemService(Context.BATTERY_SERVICE);
// 获取电池的状态
int st = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS);
// 获取电池的剩下电量(剩下的百分比)
int a = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
// 获取电池的剩下的电量(以纳瓦时为单位)
//int a = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER);
// 获取电池的平均电流(以毫安为单位),正值表示正在充电,负值表示正在放电
int b = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE);
// 获取电池的瞬时电流(以毫安为单位),正值表示正在充电,负值表示正在放电
int c = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CURRENT_NOW);
权限:
<!-- 授权应用读取电量信息 -->
<uses-permission android:name="android.permission.BATTERY_STATS" />