在使用广播BroadCatsReceiver监听网络状态变化时会碰到这样的问题,在遇到网络变化时会多次执行onReceive,导致接收到多个相同的广播,下面就这个问题进行分析和提出解决办法。
首先,写一个网络工具类,这个类主要是获取网络连接状态,是WiFi、数据网络还是无网络,代码如下:
public class NetUtils {
private static final int NETWORK_NONE=-1; //无网络连接
private static final int NETWORK_WIFI=0; //wifi
private static final int NETWORK_MOBILE=1; //数据网络
public static int getNetWorkState(Context context){
ConnectivityManager connectivityManager=(ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo=connectivityManager.getActiveNetworkInfo();
if(activeNetworkInfo!=null&&activeNetworkInfo.isConnected()){
if(activeNetworkInfo.getType()==(ConnectivityManager.TYPE_WIFI)){
return NETWORK_WIFI;
}else if(activeNetworkInfo.getType()==(ConnectivityManager.TYPE_MOBILE)){
return NETWORK_MOBILE;
}
}else{
return NETWORK_NONE;
}
return NETWORK_NONE;
}
}
通常我们使用广播监听网络状态变化的方式如下:
public class NetReceiver extends BroadcastReceiver {
private static final String TAG="NetReceiver";
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)){
final int netWorkState=NetUtils.getNetWorkState(context);
if(netWorkState==0){
Toast.makeText(context, "wifi", Toast.LENGTH_SHORT).show();
Log.i(TAG,"wifi");
}else if(netWorkState==1){
Toast.makeText(context, "数据网络", Toast.LENGTH_SHORT).show();
Log.i(TAG,"数据网络");
}else{
Toast.makeText(context, "无网络", Toast.LENGTH_SHORT).show();
Log.i(TAG,"无网络");
}
}
}
}
这看起来并没有什么不妥的地方,然而查看一下打印的日志
11-02 21:38:35.072 24210-24210/com.example.myapplication I/NetReceiver: 无网络
11-02 21:38:42.711 24210-24210/com.example.myapplication I/NetReceiver: 数据网络
11-02 21:38:43.488 24210-24210/com.example.myapplication I/NetReceiver: 数据网络
11-02 21:38:49.388 24210-24210/com.example.myapplication I/NetReceiver: wifi
11-02 21:38:49.412 24210-24210/com.example.myapplication I/NetReceiver: wifi
11-02 21:38:49.683 24210-24210/com.example.myapplication I/NetReceiver: wifi
11-02 21:38:49.925 24210-24210/com.example.myapplication I/NetReceiver: wifi
11-02 21:41:14.238 24210-24210/com.example.myapplication I/NetReceiver: 无网络
11-02 21:41:14.488 24210-24210/com.example.myapplication I/NetReceiver: 无网络
11-02 21:41:19.206 24210-24210/com.example.myapplication I/NetReceiver: 数据网络
11-02 21:41:19.425 24210-24210/com.example.myapplication I/NetReceiver: 数据网络
11-02 21:41:26.985 24210-24210/com.example.myapplication I/NetReceiver: wifi
11-02 21:41:26.996 24210-24210/com.example.myapplication I/NetReceiver: wifi
11-02 21:41:27.247 24210-24210/com.example.myapplication I/NetReceiver: wifi
11-02 21:41:27.486 24210-24210/com.example.myapplication I/NetReceiver: wifi
可以发现,当网络状态发生变化时,会接收到多个相同的广播消息,如从无网络到连接到数据网络,几乎会在同一时刻接收到2个表示当前处于数据网络的广播,再从数据网络切换到WiFi,几乎在同一时刻接收到4个表示当前处于WiFi网络的广播。仔细观察一下上方的打印时间,可以发现,如果只精确到秒的话(不考虑毫秒),打印出来的相同信息基本是在同一时刻接收到的,从这点来看,我们可以设置两个状态位,一个是接收的时间,另一个是网络状态,控制系统只处理一个相同网络状态的广播。这里先说明一下大致的解决思路:当网络状态发生变化,系统接收到第一个广播消息时,记录下接收的时间(只考虑到秒)和相应的网络状态,对于之后接收到的广播消息,首先判断接收的时间是不是和之前记录的时间一样以及网络状态是否一样,如果都一样就当做相同的一个广播进行处理,这里应该设置三个时间状态位,分别记录WiFi、数据网络和无网络状态最新记录的时间,以及一个上一次网络连接状态的状态位。总体代码如下:
public class NetReceiver extends BroadcastReceiver {
private static final String TAG="NetReceiver";
private static long WIFI_TIME=0;
private static long ETHERNET_TIME=0;
private static long NONE_TIME=0;
private static int LAST_TYPE=-3;
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)){
long time=getTime();
if(time!=WIFI_TIME&&time!=ETHERNET_TIME&&time!=NONE_TIME){
final int netWorkState=NetUtils.getNetWorkState(context);
if(netWorkState==0&&LAST_TYPE!=0){
Toast.makeText(context, "wifi", Toast.LENGTH_SHORT).show();
WIFI_TIME=time;
LAST_TYPE=netWorkState;
Log.i(TAG,"wifi"+time);
}else if(netWorkState==1&&LAST_TYPE!=1){
ETHERNET_TIME=time;
Toast.makeText(context, "数据网络", Toast.LENGTH_SHORT).show();
LAST_TYPE=netWorkState;
Log.i(TAG,"数据网络"+time);
}else if(netWorkState==-1&&LAST_TYPE!=-1){
NONE_TIME=time;
Toast.makeText(context, "无网络", Toast.LENGTH_SHORT).show();
LAST_TYPE=netWorkState;
Log.i(TAG,"无网络"+time);
}
}
}
}
public long getTime(){
SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyyMMddhhmmss");
String date = sDateFormat.format(new java.util.Date());
return Long.valueOf(date);
}
}
我们在查看一下打印的日志:
11-02 22:10:33.991 19510-19510/com.example.myapplication I/NetReceiver: 无网络:20171102101033
11-02 22:10:36.396 19510-19510/com.example.myapplication I/NetReceiver: 数据网络:20171102101036
11-02 22:10:42.226 19510-19510/com.example.myapplication I/NetReceiver: wifi:20171102101042
11-02 22:10:44.792 19510-19510/com.example.myapplication I/NetReceiver: 数据网络:20171102101044
11-02 22:10:46.589 19510-19510/com.example.myapplication I/NetReceiver: 无网络:20171102101046
11-02 22:10:49.556 19510-19510/com.example.myapplication I/NetReceiver: 数据网络:20171102101049
11-02 22:10:54.553 19510-19510/com.example.myapplication I/NetReceiver: wifi:20171102101054
11-02 22:10:58.265 19510-19510/com.example.myapplication I/NetReceiver: 无网络:20171102101058
11-02 22:11:03.494 19510-19510/com.example.myapplication I/NetReceiver: wifi:20171102101103
可以看到,同一时刻系统只打印一次相应网络状态变化的广播。
至此,就解决了同一时刻接收到多个广播的问题,最后不要忘了在manifest.xml文件的
以及申请权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
然后在MainActivity中动态注册广播:
public class MainActivity extends AppCompatActivity {
NetReceiver netReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
netReceiver=new NetReceiver();
IntentFilter filter=new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(netReceiver,filter);
}
@Override
public void onDestroy(){
unregisterReceiver(netReceiver);
super.onDestroy();
}
}