简体   繁体   English

Android:互联网连接变化监听器

[英]Android: Internet connectivity change listener

I already have this code which listens to connectivity change -我已经有了这个监听连接变化的代码 -

public class NetworkStateReceiver extends BroadcastReceiver
{
  public void onReceive(Context context, Intent intent)
  {
    Log.d("app","Network connectivity change");

    if(intent.getExtras() != null)
    {
      NetworkInfo ni = (NetworkInfo) intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO);
      if(ni != null && ni.getState() == NetworkInfo.State.CONNECTED)
      {
        Log.i("app", "Network " + ni.getTypeName() + " connected");
      }
    }

    if(intent.getExtras().getBoolean(ConnectivityManager.EXTRA_NO_CONNECTIVITY, Boolean.FALSE))
    {
      Log.d("app", "There's no network connectivity");
    }
  }
}

And I check Internet connectivity using this code - Internet Check我使用此代码检查 Internet 连接 - Internet Check

But the problem is that if network suddenly loses internet connection without any connectivity change, this code is useless.但问题是,如果网络突然失去互联网连接而没有任何连接变化,则此代码无用。 Is there any way to create Broadcast Receiver listener for Internet connectivity change?有没有办法为 Internet 连接更改创建广播接收器侦听器? I have a web app and sudden Internet connectivity changes can cause problems.我有一个 web 应用程序,突然的 Internet 连接更改可能会导致问题。

Try this尝试这个

public class NetworkUtil {
    public static final int TYPE_WIFI = 1;
    public static final int TYPE_MOBILE = 2;
    public static final int TYPE_NOT_CONNECTED = 0;
    public static final int NETWORK_STATUS_NOT_CONNECTED = 0;
    public static final int NETWORK_STATUS_WIFI = 1;
    public static final int NETWORK_STATUS_MOBILE = 2;

    public static int getConnectivityStatus(Context context) {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        if (null != activeNetwork) {
            if(activeNetwork.getType() == ConnectivityManager.TYPE_WIFI)
                return TYPE_WIFI;

            if(activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE)
                return TYPE_MOBILE;
        } 
        return TYPE_NOT_CONNECTED;
    }

    public static int getConnectivityStatusString(Context context) {
        int conn = NetworkUtil.getConnectivityStatus(context);
        int status = 0;
        if (conn == NetworkUtil.TYPE_WIFI) {
            status = NETWORK_STATUS_WIFI;
        } else if (conn == NetworkUtil.TYPE_MOBILE) {
            status = NETWORK_STATUS_MOBILE;
        } else if (conn == NetworkUtil.TYPE_NOT_CONNECTED) {
            status = NETWORK_STATUS_NOT_CONNECTED;
        }
        return status;
    }
}

And for the BroadcastReceiver对于广播接收器

public class NetworkChangeReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(final Context context, final Intent intent) {

        int status = NetworkUtil.getConnectivityStatusString(context);
        Log.e("Sulod sa network reciever", "Sulod sa network reciever");
        if ("android.net.conn.CONNECTIVITY_CHANGE".equals(intent.getAction())) {
            if (status == NetworkUtil.NETWORK_STATUS_NOT_CONNECTED) {
                new ForceExitPause(context).execute();
            } else {
                new ResumeForceExitPause(context).execute();
            }
       }
    }
}

Don't forget to put this into your AndroidManifest.xml不要忘记将其放入您的 AndroidManifest.xml

 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 <uses-permission android:name="android.permission.INTERNET" />
 <receiver
        android:name="NetworkChangeReceiver"
        android:label="NetworkChangeReceiver" >
        <intent-filter>
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            <action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
        </intent-filter>
    </receiver>

Hope this will help you Cheers!希望这会帮助你干杯!

ConnectivityAction is deprecated in api 28+. ConnectivityAction 在 api 28+ 中已弃用 Instead you can use registerDefaultNetworkCallback as long as you support api 24+.相反,只要您支持 api 24+,您就可以使用registerDefaultNetworkCallback

In Kotlin:在科特林:

val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
connectivityManager?.let {
    it.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) {
            //take action when network connection is gained
        }
        override fun onLost(network: Network?) {
            //take action when network connection is lost
        }
    })
}

Here's the Java code using registerDefaultNetworkCallback (and registerNetworkCallback for API < 24):这是使用registerDefaultNetworkCallback的 Java 代码(以及 API < 24 的registerNetworkCallback ):

ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
    @Override
    public void onAvailable(Network network) {
        // network available
    }

    @Override
    public void onLost(Network network) {
        // network unavailable
    }
};

ConnectivityManager connectivityManager =
        (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    connectivityManager.registerDefaultNetworkCallback(networkCallback);
} else {
    NetworkRequest request = new NetworkRequest.Builder()
            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build();
    connectivityManager.registerNetworkCallback(request, networkCallback);
}

Update :更新

Apps targeting Android 7.0 (API level 24) and higher do not receive CONNECTIVITY_ACTION broadcasts if they declare the broadcast receiver in their manifest.面向 Android 7.0(API 级别 24)及更高版本的应用如果在其清单中声明广播接收器,则不会接收 CONNECTIVITY_ACTION 广播。 Apps will still receive CONNECTIVITY_ACTION broadcasts if they register their BroadcastReceiver with Context.registerReceiver() and that context is still valid.如果应用程序使用 Context.registerReceiver() 注册其 BroadcastReceiver 并且该上下文仍然有效,则应用程序仍将接收 CONNECTIVITY_ACTION 广播。

You need to register the receiver via registerReceiver() method:您需要通过registerReceiver()方法注册接收器:

 IntentFilter intentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
 mCtx.registerReceiver(new NetworkBroadcastReceiver(), intentFilter);

This should work:这应该有效:

public class ConnectivityChangeActivity extends Activity {

    private BroadcastReceiver networkChangeReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d("app","Network connectivity change");
        }
    };

    @Override
    protected void onResume() {
        super.onResume();

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(networkChangeReceiver, intentFilter);
    }

    @Override
    protected void onPause() {
        super.onPause();

        unregisterReceiver(networkChangeReceiver);
    }
}

I used this method as a connection listener.我将此方法用作连接侦听器。 Working for Lolipop+, Android JAVA language.为 Lolipop+ 工作,Android JAVA 语言。

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
    ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkRequest networkRequest = new NetworkRequest.Builder().build();
    connectivityManager.registerNetworkCallback(networkRequest, new ConnectivityManager.NetworkCallback() {
        @Override
        public void onAvailable(Network network) {
            super.onAvailable(network);
            Log.i("Tag", "active connection");
        }

        @Override
        public void onLost(Network network) {
            super.onLost(network);
            Log.i("Tag", "losing active connection");
            isNetworkConnected();
        }
    });
}

private boolean isNetworkConnected() {
    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    if (!(cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected())) {
        //Do something
        return false;
    }
    return true;
}

And also add this permission in your Android Manifest.xml并在您的 Android Manifest.xml 中添加此权限

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  1. first add dependency in your code as implementation 'com.treebo:internetavailabilitychecker:1.0.4'首先在代码中添加依赖项作为implementation 'com.treebo:internetavailabilitychecker:1.0.4'
  2. implements your class with InternetConnectivityListener .使用InternetConnectivityListener实现您的类。
public class MainActivity extends AppCompatActivity implements InternetConnectivityListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        InternetAvailabilityChecker.init(this);
        mInternetAvailabilityChecker = InternetAvailabilityChecker.getInstance();
        mInternetAvailabilityChecker.addInternetConnectivityListener(this);
    }

    @Override
    public void onInternetConnectivityChanged(boolean isConnected) {
        if (isConnected) {
            alertDialog = new AlertDialog.Builder(this).create();
            alertDialog.setTitle(" internet is connected or not");
            alertDialog.setMessage("connected");
            alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    });
            alertDialog.show();

    }
    else {
            alertDialog = new AlertDialog.Builder(this).create();
            alertDialog.setTitle("internet is connected or not");
            alertDialog.setMessage("not connected");
            alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    });
            alertDialog.show();

        }
    }
}

Hello from the year 2022.你好,从 2022 年开始。

In my custom view model I observe network status changes like this:在我的自定义视图模型中,我观察到这样的网络状态变化:

public class MyViewModel extends AndroidViewModel {
    private final MutableLiveData<Boolean> mConnected = new MutableLiveData<>();

    public MyViewModel(Application app) {
        super(app);

        ConnectivityManager manager = (ConnectivityManager)app.getSystemService(Context.CONNECTIVITY_SERVICE);

        if (manager != null && 
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

            NetworkRequest networkRequest = new NetworkRequest.Builder()
                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .build();

            manager.registerNetworkCallback(networkRequest, new ConnectivityManager.NetworkCallback() {
                public void onAvailable(@NonNull Network network) {
                    mConnected.postValue(true);
                }

                public void onLost(@NonNull Network network) {
                    mConnected.postValue(false);
                }

                public void onUnavailable() {
                    mConnected.postValue(false);
                }
            });
        } else {
            mConnected.setValue(true);
        }
    }

    @NonNull
    public MutableLiveData<Boolean> getConnected() {
        return mConnected;
    }
}

And then in my Activity or Fragment I can change the UI by observing:然后在我的 Activity 或 Fragment 中,我可以通过观察来更改 UI:

@Override
protected void onCreate(Bundle savedInstanceState) {
    MyViewModel vm = new ViewModelProvider(this).get(MyViewModel.class);

    vm.getConnected().observe(this, connected -> {
        // TODO change GUI depending on the connected value
    });
}

I have noticed that no one mentioned WorkManger solution which is better and support most of android devices.我注意到没有人提到更好的WorkManger解决方案并支持大多数安卓设备。

You should have a Worker with network constraint AND it will fired only if network available, ie:您应该有一个具有网络约束的Worker ,并且只有在网络可用时才会触发它,即:

val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
val worker = OneTimeWorkRequestBuilder<MyWorker>().setConstraints(constraints).build()

And in worker you do whatever you want once connection back, you may fire the worker periodically .在worker中,一旦连接回来,您就可以做任何您想做的事情,您可以定期解雇worker。

ie: IE:

inside dowork() callback:dowork()回调中:

notifierLiveData.postValue(info)

According to the official docs as on 12/07/22:根据 12/07/22 的官方文档

  1. Define network request定义网络请求
private val networkRequest = NetworkRequest.Builder().apply {
    // To check wifi and cellular networks for internet availability
    addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
    addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        // Capabilities can be verified starting Android 6.0.
        // For a network with NET_CAPABILITY_INTERNET, 
        // it means that Internet connectivity was successfully detected
        addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        // Indicates that this network is available for use by apps,
        // and not a network that is being kept up in the background 
        // to facilitate fast network switching.
        addCapability(NetworkCapabilities.NET_CAPABILITY_FOREGROUND)
    }
}.build()
  1. Configure a network callback配置网络回调
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
    private val networks = mutableListOf<Network>()

    override fun onAvailable(network: Network) {
        super.onAvailable(network)

        networks.add(network)
        Log.d("Has network --->", networks.any().toString())
    }

    override fun onLost(network: Network) {
        super.onLost(network)

        networks.removeIf { it.toString() == network.toString() }
        Log.d("Has network --->", networks.any().toString())
    }
}
  1. Register for network updates注册网络更新
val connectivityService =
    applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
connectivityService.registerNetworkCallback(networkRequest, networkCallback)

ref https://developer.android.com/training/monitoring-device-state/connectivity-status-type参考https://developer.android.com/training/monitoring-device-state/connectivity-status-type

To specify the transport type of the network, such as Wi-Fi or cellular connection, and the currently connected network's capabilities, such as internet connection, you must configure a network request.要指定网络的传输类型(例如 Wi-Fi 或蜂窝连接)以及当前连接的网络的功能(例如 Internet 连接),您必须配置网络请求。

Declare a NetworkRequest that describes your app's network connection needs.声明一个 NetworkRequest 来描述您的应用程序的网络连接需求。 The following code creates a request for a network that is connected to the internet and uses either a Wi-Fi or cellular connection for the transport type.以下代码为连接到 Internet 并使用 Wi-Fi 或蜂窝连接作为传输类型的网络创建请求。

add this in onCreate在 onCreate 中添加这个

NetworkRequest networkRequest = new NetworkRequest.Builder()
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
    .build();

Configure a network callback When you register the NetworkRequest with the ConnectivityManager, you must implement a NetworkCallback to receive notifications about changes in the connection status and network capabilities.配置网络回调 当您向 ConnectivityManager 注册 NetworkRequest 时,您必须实现 NetworkCallback 以接收有关连接状态和网络能力变化的通知。

The most commonly implemented functions in the NetworkCallback include the following: NetworkCallback 中最常实现的函数包括:

onAvailable() indicates that the device is connected to a new network that satisfies the capabilities and transport type requirements specified in the NetworkRequest. onAvailable() 表示设备已连接到满足 NetworkRequest 中指定的功能和传输类型要求的新网络。 onLost() indicates that the device has lost connection to the network. onLost() 表示设备已失去与网络的连接。 onCapabilitiesChanged() indicates that the capabilities of the network have changed. onCapabilitiesChanged() 表示网络的能力发生了变化。 The NetworkCapabilities object provides information about the current capabilities of the network. NetworkCapabilities object 提供有关网络当前功能的信息。

add listener添加监听器

private ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(@NonNull Network network) {
    super.onAvailable(network);
}

@Override
public void onLost(@NonNull Network network) {
    super.onLost(network);
}

@Override
public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
    super.onCapabilitiesChanged(network, networkCapabilities);
    final boolean unmetered = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
}};

Register for network updates After you declare the NetworkRequest and NetworkCallback, use the requestNetwork() or registerNetworkCallback() functions to search for a network to connect from the device that satisfies the NetworkRequest.注册网络更新 声明 NetworkRequest 和 NetworkCallback 后,使用 requestNetwork() 或 registerNetworkCallback() 函数从满足 NetworkRequest 的设备搜索要连接的网络。 The status is then reported to the NetworkCallback.然后将状态报告给 NetworkCallback。

Register in onCreate在 onCreate 中注册

ConnectivityManager connectivityManager =
    (ConnectivityManager) getSystemService(ConnectivityManager.class);
connectivityManager.requestNetwork(networkRequest, networkCallback);

This my implementation which you can providing in application scope:这是您可以在应用程序范围内提供的我的实现:

class NetworkStateHelper @Inject constructor(
        private val context: Context
) {
    private val cache: BehaviorSubject<Boolean> = BehaviorSubject.create()

    private val receiver = object : BroadcastReceiver() {
        override fun onReceive(c: Context?, intent: Intent?) {
            cache.onNext(isOnlineOrConnecting())
        }
    }

    init {
        val intentFilter = IntentFilter()
        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
        context.registerReceiver(receiver, intentFilter)
        cache.onNext(isOnlineOrConnecting())
    }

    fun subscribe(): Observable<Boolean> {
        return cache
    }

    fun isOnlineOrConnecting(): Boolean {
        val cm = context.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val netInfo = cm.activeNetworkInfo
        return netInfo != null && netInfo.isConnectedOrConnecting
    }
}

I used this rxjava and dagger2 libraies我使用了这个 rxjava 和 dagger2 库

implementation 'com.treebo:internetavailabilitychecker:1.0.1'

public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        InternetAvailabilityChecker.init(this);
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        InternetAvailabilityChecker.getInstance().removeAllInternetConnectivityChangeListeners();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM