广播监听sd卡,sd卡有三种状态MEDIA_MOUNTED===sd卡可用,MEDIA_REMOVED===sd卡拔出,MEDIA_UNMOUNTED===sd卡不可用,这里面不需要权限
清单文件(只需要和下面三种任意一个匹配就可以收到广播,data必须存在,为了匹配而存在):
<receiver android:name="com.ldw.sdlistener.sdReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED"/>
<action android:name="android.intent.action.MEDIA_REMOVED"/>
<action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
<data android:scheme="file"/>
</intent-filter>
</receiver>
检测sd卡状态代码
package com.ldw.sdlistener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class sdReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
//判断收到的是什么样的广播
String action = intent.getAction();
if("android.intent.action.MEDIA_MOUNTED".equals(action)){
Toast.makeText(context, "sd卡可用", Toast.LENGTH_SHORT).show();
}
else if("android.intent.action.MEDIA_REMOVED".equals(action)){
Toast.makeText(context, "sd卡拔出", Toast.LENGTH_SHORT).show();
}
else if("android.intent.action.MEDIA_UNMOUNTED".equals(object)){
Toast.makeText(context, "sd卡不可用", Toast.LENGTH_SHORT).show();
}
}
}
MainActivity.java
package com.ldw.sdlistener;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
一开始我是在Activity中注册广播,可以正常监听电量状态,但随着Activity生命周期变化,不能持续监听电量。就想到用service来持续监听,尝试了多次静态注册,发现竟然接收不到电量变化的广播。!!!!????
有五个不能静态注册的广播
不能静态注册的广播:
- android.intent.action.SCREEN_ON
- android.intent.action.SCREEN_OFF
- android.intent.action.BATTERY_CHANGED
- android.intent.action.CONFIGURATION_CHANGED
- android.intent.action.TIME_TICK
原因(有以下几种说法,提供给大家参考):
1.提高系统效率:这两个事件是android的基本事件,如果大多数程序监听,会大大的拖慢整个系统,所以android不鼓励我们在后台监听这两个事件。
2.因为有序广播的优先级问题。以上这些广播中,静态注册时,系统的优先级大于应用,并且系统阻止了广播的向下传播。又因在Android 的广播机制中,动态注册的优先级是要高于静态注册优先级的。故用动态注册代替静态注册。
3.系统安全问题。
解决方式(以android.intent.action.BATTERY_CHANGED为例):
动态注册不能放到activity中,因为动态注册必须要在activity消亡的时候调用unregisterReceiver,会随着activity的解锁消失而不能再接收广播。一般的办法是在activity起来后马上start一个service,这个service里动态注册一个broadcastreceiver,service必须常驻在系统内,所以要接收开机消息android.intent.action.BOOT_COMPLETED。
持续监听电量变化实例:
1,在Broadcast中启动service代码,开机自动启动:
private String boot_action ="android.intent.action.BOOT_COMPLETED";
@Override
public void onReceive(Context context, Intent intent) {
if(boot_action.equals(action)){
Log.i(TAG, "android.intent.action.BOOT_COMPLETED");
Intent in0 = new Intent(context, BatteryService.class);
context.startService(in0);
}
}
Manifest.xml中注册开机启动广播
<receiver android:name="BootBroadcastReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
2,在service中动态注册广播,处理电量,service停止后自动启动
import java.text.SimpleDateFormat;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.IBinder;
import android.util.Log;
public class BatteryService extends Service {
private static final String TAG = "BatteryReceiver";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate--------------");
IntentFilter batteryfilter = new IntentFilter();
batteryfilter.addAction(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(batteryReceiver, batteryfilter);
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand--------------");
return Service.START_STICKY; //
}
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy--------------");
super.onDestroy();
this.unregisterReceiver(batteryReceiver);
}
// 接收电池信息更新的广播
private BroadcastReceiver batteryReceiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "BatteryReceiver--------------");
String action = intent.getAction();
Log.i(TAG, " 0 action:"+ action);
Log.i(TAG, "ACTION_BATTERY_CHANGED");
int status = intent.getIntExtra("status", 0);
int health = intent.getIntExtra("health", 0);
boolean present = intent.getBooleanExtra("present", false);
int level = intent.getIntExtra("level", 0);
int scale = intent.getIntExtra("scale", 0);
int icon_small = intent.getIntExtra("icon-small", 0);
int plugged = intent.getIntExtra("plugged", 0);
int voltage = intent.getIntExtra("voltage", 0);
int temperature = intent.getIntExtra("temperature", 0);
String technology = intent.getStringExtra("technology");
String statusString = "";
switch (status) {
case BatteryManager.BATTERY_STATUS_UNKNOWN:
statusString = "unknown";
break;
case BatteryManager.BATTERY_STATUS_CHARGING:
statusString = "charging";
break;
case BatteryManager.BATTERY_STATUS_DISCHARGING:
statusString = "discharging";
break;
case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
statusString = "not charging";
break;
case BatteryManager.BATTERY_STATUS_FULL:
statusString = "full";
break;
}
String acString = "";
switch (plugged) {
case BatteryManager.BATTERY_PLUGGED_AC:
acString = "plugged ac";
break;
case BatteryManager.BATTERY_PLUGGED_USB:
acString = "plugged usb";
break;
}
SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss:SSS ");
String date = sDateFormat.format(new java.util.Date());
Log.i(TAG, "battery: date=" + date + ",status " + statusString
+ ",level=" + level +",scale=" + scale
+ ",voltage=" + voltage +",acString=" + acString );
MyLog.i("Battery.txt", "Battery",":date=" + date + ",status=" + statusString
+ ",level=" + level +",scale=" + scale
+ ",voltage=" + voltage );
}
};
}
那么怎样才能保证service不被杀死?
Android开发的过程中,每次调用startService(Intent)的时候,都会调用该Service对象的onStartCommand(Intent,int,int)方法,这里在onStartCommand方法的返回值做文章就可以了,这里用到的是Service.START_STICKY这个返回值:
网络上找到的解释:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
3,将电量数据保存到文件中(这里只提取了关键的方法)
/**
* 打开日志文件并写入日志
*
* @return
* **/
private static void writeLogtoFile(String logTypename, String mylogtype,
String tag, String text) {// 新建或打开日志文件
Log.i("zjq", "mylog----------");
File path = Environment.getExternalStorageDirectory();
Date nowtime = new Date();
String needWriteFiel = logfile.format(nowtime);
String needWriteMessage = text;
File file = new File(path, needWriteFiel + logTypename);
try {
FileWriter filerWriter = new FileWriter(file, true);// 后面这个参数代表是不是要接上文件中原来的数据,不进行覆盖
BufferedWriter bufWriter = new BufferedWriter(filerWriter);
bufWriter.write(needWriteMessage);
bufWriter.newLine();
bufWriter.close();
filerWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}