在我的应用我有一个是通过BroadcastReceiver
标签推出的一种成分,过滤<receiver>
主意都能android.net.conn.CONNECTIVITY_CHANGE
。
我的目标很简单,就是知道什么时候建立WiFi连接,所以我在做什么在onReceive()
是这样的:
NetworkInfo networkInfo = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI && networkInfo.isConnected()) {
// Wifi is connected
}
它工作正常,但我似乎总是约一秒钟之内获得两个相同的意图是建立WiFi连接时。我想看看任何信息,我可以从意图,ConnectivityManager
和WifiManager
得到,但我无法找到任何区别这两种意图。
查看日志,存在还接收两个相同的目的确定至少一个其它BroadcastReceiver
。
它是在HTC Desire的运行了Android 2.2
任何想法,为什么我似乎得到“复制”的意图时,无线上网连接或者两者之间的差异可能是什么?
注:对于最近的,跟上时代的回答,请参见下面的this one!
很多使用Google和调试之后,我相信这是确定无线上网已经连接或断开的正确方法。
在广播接收器的onReceive()
方法:
public void onReceive(final Context context, final Intent intent) {
if(intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
NetworkInfo networkInfo =
intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if(networkInfo.isConnected()) {
// Wifi is connected
Log.d("Inetify", "Wifi is connected: " + String.valueOf(networkInfo));
}
} else if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
NetworkInfo networkInfo =
intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI &&
! networkInfo.isConnected()) {
// Wifi is disconnected
Log.d("Inetify", "Wifi is disconnected: " + String.valueOf(networkInfo));
}
}
}
连同在AndroidManifest.xml以下接收机元件
<receiver android:name="ConnectivityActionReceiver"
android:enabled="true" android:label="ConnectivityActionReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
<action android:name="android.net.wifi.STATE_CHANGE"/>
</intent-filter>
</receiver>
一些解释:
ConnectivityManager.CONNECTIVITY_ACTION
,我总是包含相同的NetworkInfo情况下,两个目的(这两个的getType()== TYPE_WIFI和isConnected()==真)当无线上网连接 - 在这个问题上所描述的问题。WifiManager.NETWORK_STATE_CHANGED_ACTION
,但是没有任何意图广播时无线上网的断开,但含有不同的NetworkInfo情况下,允许确定一个事件无线上网连接时两个目的。注:我收到一个单一的崩溃报告(NPE),其中intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO)
返回null。所以,即使它似乎是极为罕见的情况发生,它可能是添加一个空检查是一个好主意。
干杯,托斯滕
我处理的方式,是通过简单地节约了网络的状态,然后比较,看看是否有一个变化。
public class ConnectivityChangedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
boolean previouslyConnected = MyApp.getInstance().isNetworkPreviouslyConnected();
boolean currentlyConnected = MyApp.getInstance().isNetworkConnected();
if (previouslyConnected != currentlyConnected) {
// do something and reset
MyApp.getInstance().resetNetworkPreviouslyConnected();
}
}
}
如果这是你采取的方法,它在你的片段或活动的onResume
恢复是很重要的,所以,它保持当前值:
@Override
public void onResume() {
super.onResume();
MyApp.getInstance().resetNetworkPreviouslyConnected();
}
我这样做,我BaseFragment
,所有片段的父母在我的应用程序。
从意向检查NETWORKTYPE和比较activeNetworkInfo.getType()
Bundle bundle = intent.getExtras();
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = manager.getActiveNetworkInfo();
if(ni != null && ni.getState() == NetworkInfo.State.CONNECTED) {
if(bundle.getInt("networkType") == ni.getType()) {
// active network intent
}
}
发现网络连接说没有互联网,但居然还有一种特殊情况。原来getActiveNetworkInfo
总是会把你返回DISCONNECTED /受阻时,而电池电量低,只是交换应用网络发生变化的具体案例
当开启WiFi,
可以在上述两个条件下转动WIFI OFF可以观察到类似的行为。
为了区分两者,请按#2及以下#3:
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "*** Action: " + intent.getParcelableExtra("networkInfo"));
NetworkInfo netInfo = intent.getParcelableExtra("networkInfo");
if(intent.getAction().equalsIgnoreCase("android.net.conn.CONNECTIVITY_CHANGE")) {
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetInfo != null) {
if (netInfo.getType() == ConnectivityManager.TYPE_WIFI) {
if (netInfo.getState().name().contains("DISCONNECTED")
&& activeNetInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
Log.d(TAG, "WIFI disconnect created this broadcast. MOBILE data ON."); // #1
} else if (netInfo.getState().name().contains("CONNECTED")
&& activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI) {
Log.d(TAG, "WIFI connect created this broadcast."); // #2
}
} else if (netInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
if (netInfo.getState().name().contains("DISCONNECTED")
&& activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI) {
Log.d(TAG, "MOBILE data disconnect created this broadcast. WIFI ON."); // #3
} else if (netInfo.getState().name().contains("CONNECTED")
&& activeNetInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
Log.d(TAG, "MOBILE data connect created this broadcast."); // #4
}
}
} else {
Log.d(TAG, "No network available");
}
}
}
只听行动“android.net.conn.CONNECTIVITY_CHANGE”。每当建立或销毁连接它的播出。
“android.net.wifi.STATE_CHANGE”,当连接建立,将播放。所以,你得到两个触发器。
请享用!
如果你在WifiManager.NETWORK_STATE_CHANGED_ACTION
听,因为有2种方法在NetworkInfo
你会两次收到此
isConnectedOrConnecting()
isConnected()
第一次isConnectedOrConnecting()
返回true
和isConnected()
false
第二次isConnectedOrConnecting()
和isConnected()
返回true
干杯
更新托斯滕的代码,这样,当WIFI断开连接,只有一个适当的广播起作用时。
二手NetworkInfo.getDetailedState()== DetailedState.DISCONNECTED的检查。
public void onReceive(final Context context, final Intent intent) {
if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
NetworkInfo networkInfo = intent
.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if (networkInfo.isConnected()) {
// Wifi is connected
Log.d("Inetify","Wifi is connected: " + String.valueOf(networkInfo));
}
} else if (intent.getAction().equals(
ConnectivityManager.CONNECTIVITY_ACTION)) {
NetworkInfo networkInfo = intent
.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if (networkInfo.getDetailedState() == DetailedState.DISCONNECTED) {
// Wifi is disconnected
Log.d("Inetify","Wifi is disconnected: "+String.valueOf(networkInfo));
}
}
}
如果你注册的活动为目的听众,那么你将收到相同的消息两次。具体来说,您需要选择是否要监听的包级别(XML)或程序化水平。
如果你设置了一个类的广播接收器和附加听它,你附加一个意图过滤器的活动,则该消息将被复制两次。
我希望这能解决您的问题。
这是对21 API和更高的连接更改注册的正确方法。下面的代码可以放在一个基地活动,这样你可以期待在您的应用程序的每个屏幕(从这个活动继承)来获取这些回调。
首先,创建一个网络回调将监测连接变化。
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private val networkCallback: ConnectivityManager.NetworkCallback = object : ConnectivityManager.NetworkCallback() {
// Implement the callback methods that are relevant to the actions you want to take.
// I have implemented onAvailable for connecting and onLost for disconnecting.
override fun onAvailable(network: Network?) {
super.onAvailable(network)
}
override fun onLost(network: Network?) {
super.onLost(network)
}
}
然后,注册并在相关点注销该回调。
override fun onResume() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
cm?.registerNetworkCallback(NetworkRequest.Builder().build(), networkCallback)
}
}
并在适当的时候注销。
override fun onPause() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
cm?.unregisterNetworkCallback(networkCallback)
}
}
请注意,有是Build.VERSION_CODES.LOLLIPOP
检查。此功能仅在棒棒糖及更高版本。一定要拥有怎样,如果你支持不到在你的应用程序API 21处理的预棒棒糖设备的网络状态变化的计划。
我用SharedPref与及时解决两次电话。
private static final Long SYNCTIME = 800L;
private static final String LASTTIMESYNC = "DATE";
SharedPreferences sharedPreferences;
private static final String TAG = "Connection";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Network connectivity change");
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
final ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo ni = connectivityManager.getActiveNetworkInfo();
if (ni != null && ni.isConnected()) {
if(System.currentTimeMillis()-sharedPreferences.getLong(LASTTIMESYNC, 0)>=SYNCTIME)
{
sharedPreferences.edit().putLong(LASTTIMESYNC, System.currentTimeMillis()).commit();
// Your code Here.
}
}
else if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, Boolean.FALSE)) {
Log.d(TAG, "There's no network connectivity");
}
}
因为有1.call和2.call(约200毫秒为单位)之间的小延迟。所以如果与时间第二个电话会停止,只是第一个将持续。
我解决了,如果在
onCreate()
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
intentFilter.addAction("android.net.wifi.WIFI_STATE_CHANGED");
intentFilter.addAction("android.net.wifi.STATE_CHANGE");
ctx.registerReceiver(outgoingReceiver, intentFilter);
在
BroadcastReceiver
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
NetworkInfo networkInfo =
intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI &&
networkInfo.isConnected()) {
// Wifi is connected
Log.d("Inetify", "Wifi is connected: " + String.valueOf(networkInfo));
Log.e("intent action", intent.getAction());
if (isNetworkConnected(context)){
Log.e("WiFi", "is Connected. Saving...");
try {
saveFilesToServer("/" + ctx.getString(R.string.app_name).replaceAll(" ", "_") + "/Temp.txt");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}}
boolean isNetworkConnected(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if (ni != null) {
Log.e("NetworkInfo", "!=null");
try{
//For 3G check
boolean is3g = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
.isConnectedOrConnecting();
//For WiFi Check
boolean isWifi = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
.isConnected();
Log.e("isWifi", "isWifi="+isWifi);
Log.e("is3g", "is3g="+is3g);
if (!isWifi)
{
return false;
}
else
{
return true;
}
}catch (Exception er){
return false;
}
} else{
Log.e("NetworkInfo", "==null");
return false;
}
}
我使用的意图额外费用的NetworkInfo解决了这个问题。在下面的例子中,如果无线连接或移动的onReceive事件被触发一次。
if (intent.getAction().equalsIgnoreCase(ConnectivityManager.CONNECTIVITY_ACTION)) {
NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
boolean screenIsOn = false;
// Prüfen ob Screen on ist
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
screenIsOn = pm.isInteractive();
} else {
screenIsOn = pm.isScreenOn();
}
if (Helper.isNetworkConnected(context)) {
if (networkInfo.isConnected() && networkInfo.isAvailable()) {
Log.v(logTAG + "onReceive", "connected");
if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
Log.v(logTAG + "onReceive", "mobile connected");
} else if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
Log.v(logTAG + "onReceive", "wifi connected");
}
}
}
和我的助手:
public static boolean isNetworkConnected(Context ctx) {
ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
return ni != null;
}
如果你只想一次接受它,你可以简单地通过变量控制它。
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
NetworkInfo activeNetwork = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if (activeNetwork != null) { // connected to the internet
if (activeNetwork.isConnected() && !isUpdated) {
if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
// connected to wifi
} else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
// connected to the mobile provider's data plan
}
isUpdated = true;
} else {
isUpdated = false;
}
}
}