1 动态注册和静态注册
静态注册和动态注册的区别:
① 动态注册是在Java类中注册,而静态注册是在AndroidManifest.xml中注册。
② 动态注册的广播接收器不是常驻型的,会随着所注册的Activity的结束而结束,如果所在的Activity已经destroy了,那么该广播接收器也就不能再继续接收广播了。注意:在Activity结束前,要取消注册广播接收器,不然会导致内存泄露;静态注册的广播接收器是常驻型的,即使所在的APP被关闭了,也是可以接收到广播的。
1)动态注册监听网络变化
利用一个网络状态监听器来说明,建立一个继承BroadcastReceiver的广播接收器,通过监听 intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");//网络发生变化时系统发出android.net.conn.CONNECTIVITY_CHANGE的广播,当网络发生变化时,onReceive()方法得到执行。需要注意的是 要在AndroidManifest.xml中 加入权限配置。
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
public class FifthActivity extends AppCompatActivity {
private final static String TAG = "XULIWEI_ACTIVITY";
private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fifth);
Button button = findViewById(R.id.button_3);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FifthActivity.this,MainActivity.class);
// intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
});
Log.d(TAG,"FifthActivity onCreate "+this.toString());
intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");//网络发生变化时系统发出android.net.conn.CONNECTIVITY_CHANGE的广播
networkChangeReceiver = new NetworkChangeReceiver();
registerReceiver(networkChangeReceiver,intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG,"FifthActivity onDestroy "+this.toString());
unregisterReceiver(networkChangeReceiver);
}
//通过广播接收器监听网络变化
class NetworkChangeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// Toast.makeText(context,"network changes",Toast.LENGTH_LONG).show();
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);//ConnectivityManager是一个系统服务类,专门用来管理网络连接的
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if(networkInfo!=null&&networkInfo.isAvailable()){
Toast.makeText(context,"网络正常",Toast.LENGTH_LONG).show();
}else{
Toast.makeText(context,"无网络",Toast.LENGTH_LONG).show();
}
}
}
}
2)静态注册实现开机自启
利用静态注册实现开机自启提示,静态注册可以不依赖与某一个应用
广播接收器
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
Toast.makeText(context,"开机了",Toast.LENGTH_LONG).show();
}
}
在AndroidManifest.xml中注册,并且要添加权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver
android:name=".broadcasttest.BootCompleteReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
2.IntentService
IntentService 与普通Service的区别是,
(1) Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,不建议在Service中编写耗时的逻辑和操作,否则会引起ANR。
(2) IntentService 它创建了一个独立的工作线程来处理所有的通过onStartCommand()传递给服务的intents(把intent插入到工作队列中)。通过工作队列把intent逐个发送给onHandleIntent()。
(3) 不需要主动调用stopSelft()来结束服务。因为,在所有的intent被处理完后,系统会自动关闭服务。
下图是IntentService的生命周期,可以看到IntentService与活动主线程不是一个,在服务处理结束后会自动关闭服务
IntentService通过广播与Activity通信
广播地址
public static String SERVICE_RECEIVER = "com.example.myproject.broadcasttest.MsgReceiver";
AndroidManifest.xml注册
<receiver
android:name=".broadcasttest.MsgReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.myproject.broadcasttest.MsgReceiver" />
</intent-filter>
</receiver>
活动页面按钮点击后启动IntentService 服务 ,并注册广播接收器
Button intentServiceButtion = findViewById(R.id.btn_intent_service);
intentServiceButtion.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG,"Thread id is "+Thread.currentThread().getId());
//动态注册广播接收器
Toast.makeText(getApplicationContext(), "Service的count的值为:", Toast.LENGTH_SHORT).show();
msgReceiver = new MsgReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(SERVICE_RECEIVER);
registerReceiver(msgReceiver,intentFilter);
//启动后台服务
Intent intent = new Intent(SecondActivity.this, MyIntentService.class);
startService(intent);
}
});
}
IntentService模拟完成任务后,广播通知广播接收器
public class MyIntentService extends IntentService {
private final String TAG = "XULIWEI_SERVICE";
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
//打印当前进程的id
Log.d(TAG, "开始完成任务,通过进程"+Thread.currentThread().getId());
//发送广播通知到Activity
Intent sendIntent = new Intent(SecondActivity.SERVICE_RECEIVER);
intent.setPackage("com.example.myproject.broadcasttest");
sendIntent.putExtra("progressID",Thread.currentThread().getId());
sendBroadcast(intent);
Log.d(TAG, "广播,通过进程"+Thread.currentThread().getId());
}
@Override
public void onDestroy() {
// super.onDestroy();
Log.d(TAG,"intentService onDestroy");
}
}
通过广播接收器提示intentService服务已完成
//通过广播接收器提示intentService服务已完成
public class MsgReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String progressID = intent.getStringExtra("progressID");
Log.d(SecondActivity.TAG,"进程"+progressID+"下的服务处理已完成");
}
}
结合Service和广播实现计时器
思路:启动一个Service,创建一个线程用于计时,在Service和Activity两边分别添加一个广播接收器,当点击开始时,通知服务开始计时,服务端每隔1秒发送一个广播到Activity,刷新页面,显示最新的时间,当点击结束,Activity端发送广播停止计时。
package com.example.mybroadreceiver;
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.Button;
import android.widget.TextView;
public class ClockActivity extends AppCompatActivity {
private TextView tvClock;
public static final String CLOCK_ACTION="com.jereh.Clock_Action";
public static int TIME=2*60*60*1000;//倒计时2个小时
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clock);
tvClock=findViewById(R.id.tvClock);
regReceiver();//注册广播
startService(new Intent(this,ClockService.class));//启动计时服务
Button clockStartButtion = findViewById(R.id.button_clock_start);
//通过发送广播,控制计时服务
//继续计时
clockStartButtion.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent();
intent.setAction(ClockService.CLOCK_SERVICE_ACTION);
intent.putExtra("method", "continue");
sendBroadcast(intent);
}
});
//通过发送广播,控制计时服务
//暂停计时
Button clockEndButtion = findViewById(R.id.button_clock_end);
clockEndButtion.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent();
intent.setAction(ClockService.CLOCK_SERVICE_ACTION);
intent.putExtra("method","pause");
sendBroadcast(intent);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
super.unregisterReceiver(clockReceiver);
TIME=2*60*60*1000;
Intent intent=new Intent();
intent.setAction(ClockService.CLOCK_SERVICE_ACTION);
intent.putExtra("method", "stop");
super.sendBroadcast(intent);
}
private void regReceiver(){
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction(CLOCK_ACTION);
super.registerReceiver(clockReceiver, intentFilter);
}
/**
*广播接受者,接受来自ClockService(计时服务)的广播,ClockService每隔一秒
*钟发一次广播
*/
private BroadcastReceiver clockReceiver=new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
changeTime();//改变TextView中的显示时间
}
};
private void changeTime(){
String stime="";
if(TIME==0){
stime="计时结束";
}else{
int hour=TIME/(1000*60*60);
int minute=TIME%(1000*60*60)/(60*1000);
int second=(TIME%(1000*60*60))%(60*1000)/1000;
String shour=""+hour,sminute=""+minute,ssecond=""+second;
if(hour<=9){
shour="0"+hour;
}
if(minute<=9){
sminute="0"+minute;
}
if (second<=9){
ssecond="0"+second;
}
stime=shour+":"+sminute+":"+ssecond;
}
tvClock.setText(stime);
}
}
package com.example.mybroadreceiver;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
public class ClockService extends Service {
public static final String CLOCK_SERVICE_ACTION="clock_service_actoin";
private boolean controllOpt=true;
public ClockService() { }
@Override
public void onCreate(){
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction(CLOCK_SERVICE_ACTION);
//在service中注册广播(serviceController),接受来自ClockActivity中
//的广播信息,实现对计时服务的控制(暂停、继续)
super.registerReceiver(serviceController,intentFilter);
}
@Override
public int onStartCommand(Intent intent,int flags,int startId){
countTime();//执行计时功能
return Service.START_STICKY;
}
//实现计时功能,每隔一秒减少总时间并ClockActivity发送广播
private void countTime(){
new Thread(new Runnable() {
@Override
public void run() {
Intent intent= new Intent(ClockActivity.CLOCK_ACTION);
while(controllOpt){
try {
Thread.sleep(1000);
if(ClockActivity.TIME<=0){
sendBroadcast(intent);
stopSelf();
break;
}
ClockActivity.TIME-=1000;
sendBroadcast(intent);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
//广播接受者,接受来自ClockActivity的广播以便暂停、继续、停止广播
private BroadcastReceiver serviceController=new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String method=intent.getStringExtra("method");
switch (method){
case "pause":
controllOpt=false;
break;
case "continue":
controllOpt=true;
countTime();
break;
case "stop":
controllOpt=false;
stopSelf();
break;
}
}
};
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onDestroy(){
super.unregisterReceiver(serviceController);
}
}
融合Service、广播、handler、AlarmManager等知识点实现一个闹钟
实现思路 开启Service后传过去当前时间,并累加时间,通过binder通信更新时间,利用AlarmManager设置定时任务,当时间到后发广播提醒用户。
ClockActivity中的核心代码
private ServiceConnection conn = new ServiceConnection() {
//Activity与Service断开连接时回调该方法
@Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("------Service DisConnected-------");
}
//Activity与Service连接成功时回调该方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("------Service Connected-------");
binder = (ClockService.MyBinder) service;
System.out.println(binder.getTime());
}
};
ClockActivity中onCreate中的代码,需要注意的是bindService是异步的,在onResume执行之后才会执行,因此如果在onCreate中想要获取binder会获得到null
//启动计时服务
Intent intent = new Intent(ClockActivity.this, ClockService.class);
intent.putExtra("time",""+Calendar.getInstance().getTimeInMillis());
startService(intent);
bindService(intent, conn, Service.BIND_ABOVE_CLIENT);
//实现闹钟模块的代码
currentTimeText = findViewById(R.id.time_text);
clockText = findViewById(R.id.clock_text);
Button clockButton = findViewById(R.id.button_clock);
//设置当前时间
currentTimeText.setText(time);
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
//注册广播主要用来刷新时间
IntentFilter clockIntentFilter = new IntentFilter();
clockIntentFilter.addAction(CLOCK_ACTION);
registerReceiver(clockReceiver,clockIntentFilter);
Intent receiverIntent = new Intent();
receiverIntent.setAction(CLOCK_ACTION);
PendingIntent pi = PendingIntent.getBroadcast(ClockActivity.this,0,receiverIntent,PendingIntent.FLAG_UPDATE_CURRENT);
clockButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Calendar currentTime = Calendar.getInstance();
new TimePickerDialog(ClockActivity.this, 0,
new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
//设置当前时间
Calendar c = Calendar.getInstance();
c.setTimeInMillis(System.currentTimeMillis());
// 根据用户选择的时间来设置Calendar对象
c.set(Calendar.HOUR, hourOfDay);
c.set(Calendar.MINUTE, minute);
SimpleDateFormat sdf=new SimpleDateFormat("HH:mm:ss");
String sd = sdf.format(new Date(c.getTimeInMillis()));
clockText.setText(sd);
// 设置AlarmManager在Calendar对应的时间启动Activity
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pi);
}
Log.e("HEHE",c.getTimeInMillis()+""); //这里的时间是一个unix时间戳
// 提示闹钟设置完毕:
Toast.makeText(ClockActivity.this, "闹钟设置完毕~"+ c.getTimeInMillis(),
Toast.LENGTH_SHORT).show();
}
}, currentTime.get(Calendar.HOUR_OF_DAY), currentTime
.get(Calendar.MINUTE), false).show();
}
});
new Timer().schedule(new TimerTask() {
@Override
public void run() {
if(binder!=null){
// 创建消息
Message msg = new Message();
msg.what = 0x123;
Bundle bundle = new Bundle();
bundle.putString("current_time",binder.getTime());
msg.setData(bundle);
myHandler.sendMessage(msg);
}
}
},0,1000);
ClockService 主要用于实现时间戳累加任务
public class ClockService extends Service {
public final static String mServiceAction = "com.example.myproject.mServiceAction";
private Thread mClockThread;
private boolean controllerFlag = false;
public static long TIME = 0;
public static boolean clockFlag = true;
public ClockService() {
}
//定义onBinder方法所返回的对象
private MyBinder binder = new MyBinder();
public class MyBinder extends Binder
{
public String getTime(){
SimpleDateFormat sdf=new SimpleDateFormat("HH:mm:ss");
String sd = sdf.format(new Date(TIME));
return sd;
}
}
@Override
public void onCreate() {
super.onCreate();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(mServiceAction);
registerReceiver(serverController,intentFilter);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
TIME = Long.parseLong(intent.getStringExtra("time"));
mClockThread = new Thread(new Runnable() {
@Override
public void run() {
while(clockFlag){
try {
Thread.sleep(1000);
TIME += 1000;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
mClockThread.start();
return binder;
}
//Service断开连接时回调
@Override
public boolean onUnbind(Intent intent) {
return true;
}
//Service被关闭前回调
@Override
public void onDestroy() {
clockFlag = false;
super.onDestroy();
}
@Override
public void onRebind(Intent intent) {
super.onRebind(intent);
}
}