Android: слушатель смены интернет-соединения
У меня уже есть этот код, который слушает изменения подключения -
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");
}
}
}
И я проверяю интернет-соединение, используя этот код - Internet Check
Но проблема в том, что если сеть внезапно теряет подключение к Интернету без каких-либо изменений подключения, этот код бесполезен. Есть ли способ создать приемник Broadcast Receiver для изменения подключения к Интернету? У меня есть веб-приложение, и внезапные изменения подключения к Интернету могут вызвать проблемы.
14 ответов
Попробуй это
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;
}
}
И для 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();
}
}
}
}
Не забудьте поместить это в свой 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>
Надеюсь, это поможет вам ура!
ConnectivityAction устарела в API 28+. Вместо этого вы можете использовать registerDefaultNetworkCallback
до тех пор, пока вы поддерживаете API 24+.
В Котлине:
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
}
})
}
Вот код Java, использующий registerDefaultNetworkCallback
(а также registerNetworkCallback
для API < 24):
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);
}
Обновление:
Приложения, ориентированные на Android 7.0 (уровень API 24) и выше, не получают широковещательные сообщения CONNECTIVITY_ACTION, если они декларируют широковещательный получатель в своем манифесте. Приложения по-прежнему будут получать широковещательные сообщения CONNECTIVITY_ACTION, если они зарегистрируют свой BroadcastReceiver с помощью Context.registerReceiver() и этот контекст будет по-прежнему действителен.
Вам необходимо зарегистрировать получателя через registerReceiver()
метод:
IntentFilter intentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
mCtx.registerReceiver(new NetworkBroadcastReceiver(), intentFilter);
Это должно работать:
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);
}
}
Я использовал этот метод как прослушиватель соединений. Работает на 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();
}
});
}
А также добавьте это разрешение в свой Android Manifest.xml
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Привет из 2022 года.
В моей пользовательской модели представления я наблюдаю изменения состояния сети следующим образом:
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;
}
}
И затем в моем действии или фрагменте я могу изменить пользовательский интерфейс, наблюдая:
@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
});
}
- сначала добавьте зависимость в свой код как
implementation 'com.treebo:internetavailabilitychecker:1.0.4'
- реализует ваш класс с помощью
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();
}
}
}
Я заметил, что никто не упомянул
WorkManger
решение, которое лучше и поддерживает большинство устройств Android.
У вас должен быть
Worker
с сетевым ограничением И он будет запущен, только если сеть доступна, то есть:
val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
val worker = OneTimeWorkRequestBuilder<MyWorker>().setConstraints(constraints).build()
А в worker вы делаете все, что хотите, после восстановления соединения, вы можете периодически увольнять воркера .
то есть:
внутри
dowork()
Перезвоните:
notifierLiveData.postValue(info)
Согласно официальным документам :
- Определить сетевой запрос
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()
- Настройка обратного вызова по сети
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.remove(network)
Log.d("Has network --->", networks.any().toString())
}
}
- Зарегистрируйтесь для получения обновлений сети
val connectivityService =
applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
connectivityService.registerNetworkCallback(networkRequest, networkCallback)
Отвечая на это в 2023 году, поскольку доступна лучшая реализация
NetworkObserver.kt
/**
* This class is in charge of listening to the state of the network connection and notifying the
* activity if the state of the connection changes.
* */
class NetworkObserver constructor(
private val context: Context,
private val lifecycle: Lifecycle
) : DefaultLifecycleObserver {
private lateinit var networkCallback: ConnectivityManager.NetworkCallback
private var connectivityManager: ConnectivityManager? = null
private val validNetworks = HashSet<Network>()
private lateinit var job: Job
private lateinit var coroutineScope: CoroutineScope
// State Holder: Indicating either the network is available or not-available
private val _networkAvailableStateFlow: MutableStateFlow<NetworkState> = MutableStateFlow(NetworkState.Available)
val networkAvailableStateFlow
get() = _networkAvailableStateFlow
// ---> This variable can be accessed anytime to get the current state of the network
val isConnected: Boolean
get() = _isConnected.get()
private val _isConnected = AtomicBoolean(false)
override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
init()
}
override fun onStart(owner: LifecycleOwner) {
super.onStart(owner)
registerNetworkCallback()
checkValidNetworks()
}
override fun onStop(owner: LifecycleOwner) {
super.onStop(owner)
unregisterNetworkCallback()
}
private fun init() {
// Initialize the connectivity manager instance
connectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
}
private fun registerNetworkCallback() {
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
// Observing the network should happen only when the life-cycle is in started state
initCoroutine()
initNetworkMonitoring()
}
}
private fun unregisterNetworkCallback() {
validNetworks.clear()
connectivityManager?.unregisterNetworkCallback(networkCallback)
job.cancel()
}
/**
* Co-Routine used to monitor the connectivity
*/
private fun initCoroutine() {
// Create a job instance
job = Job()
// Provide a co-routine scope
coroutineScope = CoroutineScope(Dispatchers.Default + job)
}
private fun initNetworkMonitoring() {
networkCallback = createNetworkCallback()
val networkRequest = NetworkRequest.Builder()
.addCapability(NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build()
connectivityManager?.registerNetworkCallback(networkRequest, networkCallback)
}
private fun createNetworkCallback() = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
connectivityManager?.getNetworkCapabilities(network).also {
if (it?.hasCapability(NET_CAPABILITY_INTERNET) == true) {
validNetworks.add(network)
}
}
checkValidNetworks()
}
override fun onLost(network: Network) {
validNetworks.remove(network)
checkValidNetworks()
}
}
private fun checkValidNetworks() {
coroutineScope.launch {
_networkAvailableStateFlow.emit(
if (validNetworks.size > 0){
_isConnected.set(true)
NetworkState.Available
} else {
_isConnected.set(false)
NetworkState.Unavailable
}
)
}
}
}
sealed class NetworkState {
object Unavailable : NetworkState()
object Available : NetworkState()
}
Применение
// --> Initialize the network observer in your activity or fragment
networkObserver = NetworkObserver(this, lifecycle)
lifecycle.addObserver(networkObserver)
// --> Use live data to observe the network changes
networkObserver.networkAvailableStateFlow.asLiveData().observe(this, Observer { networkState ->
when (networkState) {
NetworkState.Unavailable -> SnackBarDisplay.showNetworkUnavailableAlert(binding.root)
NetworkState.Available -> SnackBarDisplay.removeNetworkUnavailableAlert()
}
})
Я разместил полное решение в моем GitHub здесь
ссылка https://developer.android.com/training/monitoring-device-state/connectivity-status-type
Чтобы указать транспортный тип сети, такой как Wi-Fi или сотовая связь, и возможности текущей подключенной сети, такие как подключение к Интернету, необходимо настроить сетевой запрос.
Объявите NetworkRequest, описывающий потребности вашего приложения в сетевом подключении. Следующий код создает запрос для сети, которая подключена к Интернету и использует Wi-Fi или сотовую связь для типа транспорта.
добавить это в onCreate
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build();
Настройка сетевого обратного вызова При регистрации NetworkRequest в ConnectivityManager необходимо реализовать NetworkCallback для получения уведомлений об изменениях состояния подключения и сетевых возможностей.
Наиболее часто реализуемые функции в NetworkCallback включают следующее:
onAvailable() указывает, что устройство подключено к новой сети, которая удовлетворяет требованиям к возможностям и типу транспорта, указанным в NetworkRequest. onLost() указывает, что устройство потеряло соединение с сетью. onCapabilitiesChanged() указывает, что возможности сети изменились. Объект NetworkCapabilities предоставляет информацию о текущих возможностях сети.
добавить слушателя
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);
}};
Зарегистрируйтесь для получения сетевых обновлений. После объявления NetworkRequest и NetworkCallback используйте функции requestNetwork() или registerNetworkCallback() для поиска сети для подключения с устройства, которое удовлетворяет NetworkRequest. Затем о состоянии сообщается NetworkCallback.
Зарегистрируйтесь в onCreate
ConnectivityManager connectivityManager =
(ConnectivityManager) getSystemService(ConnectivityManager.class);
connectivityManager.requestNetwork(networkRequest, networkCallback);
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();
}
}
Это моя реализация, которую вы можете предоставить в области применения:
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
}
}