programacion - Detecta CAMBIO DE CONECTIVIDAD en Android 7 y superior cuando la aplicación se cierra/en segundo plano
programacion android pdf 2017 (5)
A continuación se muestra un extracto de la documentación.
Las aplicaciones dirigidas a Android 7.0 (nivel de API 24) y superior no reciben transmisiones de CONNECTIVITY_ACTION si declaran el receptor de transmisión en su manifiesto. Las aplicaciones seguirán recibiendo transmisiones de CONNECTIVITY_ACTION si registran su BroadcastReceiver con Context.registerReceiver () y ese contexto sigue siendo válido.
Por lo tanto, recibirá esta transmisión hasta que su contexto sea válido en Android N y superior registrándose explícitamente en el mismo.
Arranque completado:
Puede escuchar la emisión de
android.intent.action.BOOT_COMPLETED
, necesitará este permiso para lo mismo.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Escenario de la aplicación eliminada:
No lo vas a recibir.
Eso es muy esperado y debido a varias razones.
-
Android Oreo tiene limitaciones para ejecutar servicios en segundo plano, por lo que puede enfrentar esto en dispositivos O
-
El modo Doze en Android Marshmallow en adelante puede causar esto, detendrá todas las operaciones de red y eliminará los bloqueos de activación de la CPU
-
Aunque el modo Doze tiene un mecanismo para solicitar listas blancas de aplicaciones , esto puede ser útil para usted.
Problema:
Entonces, el problema es que tengo una aplicación que envía una solicitud a nuestro backend cada vez que se conecta WiFi (con el SSID conectado y otra información) o cuando se desconecta (a través de la red móvil). Sin embargo, con los cambios en Android 7 / N y superiores, CONNECTIVITY_CHANGE y CONNECTIVITY_ACTION ya no funcionan en segundo plano. Ahora, en la mayoría de los casos, la gente hace mal uso de esta transmisión y, como tal, puedo entender completamente por qué se realizó el cambio. Sin embargo, no tengo idea de cómo resolver este problema en el estado actual.
Ahora no soy un gran desarrollador de Android (esto es para un complemento de Cordova), ¡así que cuento con ustedes!
Comportamiento esperado: la aplicación se despierta y la solicitud se envía cada vez que WiFi cambia la conectividad, incluso cuando la aplicación se desactiva / en segundo plano.
Comportamiento actual: la aplicación solo envía solicitudes cuando la aplicación está en primer plano.
Probé hasta ahora: hasta ahora he movido la intención implícita de escuchar CONNECTIVITY_ACTION desde el manifiesto para registrarlo manualmente en la parte principal de la aplicación (complemento). Esto hace que funcione mientras la aplicación esté en la memoria pero no en el arranque en frío o en el fondo real
Ya examinado: la mayoría de las respuestas hablan sobre el uso de trabajos programados para sustituir la transmisión que falta. Veo cómo funciona esto, por ejemplo, reintentando una descarga o similar, pero no para mi caso (pero corríjame si me equivoco). A continuación se muestran las publicaciones SO que ya he visto:
Detecta cambios de conectividad en Android 7.0 Nougat cuando la aplicación está en primer plano
ConnectivityManager.CONNECTIVITY_ACTION en desuso
Así lo hice yo.
He creado un
IntentService
y en el método
onCreate
y he registrado
networkBroadacst
que comprueba la conexión a Internet.
public class SyncingIntentService extends IntentService {
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
networkBroadcast=new NetworkBroadcast();
registerReceiver(networkBroadcast,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onHandleIntent(intent);
return START_STICKY;
}
}
Esta es mi clase de transmisión
public class NetworkBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Constants.isInternetConnected(context)) {
// Toast.makeText(context, "Internet Connect", Toast.LENGTH_SHORT).show();
context.startService(new Intent(context, SyncingIntentService.class));
}
else{}
}
}
De esta manera, puede verificar la conexión a Internet para saber si su aplicación está en primer plano o en segundo plano en turrón.
La mejor manera de obtener el cambio de conectividad Android Os 7 y superior es registrar su transmisión ConnectivityReceiver en la clase de aplicación como se muestra a continuación.
public class MyApplication extends Application {
private ConnectivityReceiver connectivityReceiver;
private ConnectivityReceiver getConnectivityReceiver() {
if (connectivityReceiver == null)
connectivityReceiver = new ConnectivityReceiver();
return connectivityReceiver;
}
@Override
public void onCreate() {
super.onCreate();
registerConnectivityReceiver();
}
// register here your filtters
private void registerConnectivityReceiver(){
try {
// if (android.os.Build.VERSION.SDK_INT >= 26) {
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
//filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
//filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
//filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
registerReceiver(getConnectivityReceiver(), filter);
} catch (Exception e) {
MLog.e(TAG, e.getMessage());
}
}
}
Y luego en manifiesto
<application
android:name=".app.MyApplication"/>
Aquí está su ConnectivityReceiver.java
public class ConnectivityReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, final Intent intent) {
MLog.v(TAG, "onReceive().." + intent.getAction());
}
}
Otro enfoque que es más simple y más fácil cuando usa
registerNetworkCallback (NetworkRequest, PendingIntent)
:
NetworkRequest.Builder builder = new NetworkRequest.Builder();
builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
builder.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
Intent intent = new Intent(this, SendAnyRequestService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
if (connectivityManager != null) {
NetworkRequest networkRequest = builder.build();
connectivityManager.registerNetworkCallback(networkRequest, pendingIntent);
}
Que es
SendAnyRequestService.class
es su clase de servicio, y puede llamar a su API dentro de ella.
Este código funciona para Android 6.0 (API 23) y superior
El documento de referencia está here
Turrón y superior: tenemos que usar JobScheduler y JobService para los cambios de conexión.
Todo lo que puedo dividir esto en tres pasos.
Registre JobScheduler dentro de la actividad. Además, inicie JobService (Servicio para manejar devoluciones de llamadas desde JobScheduler. Las solicitudes programadas con JobScheduler finalmente se dirigen al método "onStartJob" de este servicio).
public class NetworkConnectionActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_network_connection);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
scheduleJob();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void scheduleJob() {
JobInfo myJob = new JobInfo.Builder(0, new ComponentName(this, NetworkSchedulerService.class))
.setRequiresCharging(true)
.setMinimumLatency(1000)
.setOverrideDeadline(2000)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPersisted(true)
.build();
JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(myJob);
}
@Override
protected void onStop() {
// A service can be "started" and/or "bound". In this case, it''s "started" by this Activity
// and "bound" to the JobScheduler (also called "Scheduled" by the JobScheduler). This call
// to stopService() won''t prevent scheduled jobs to be processed. However, failing
// to call stopService() would keep it alive indefinitely.
stopService(new Intent(this, NetworkSchedulerService.class));
super.onStop();
}
@Override
protected void onStart() {
super.onStart();
// Start service and provide it a way to communicate with this class.
Intent startServiceIntent = new Intent(this, NetworkSchedulerService.class);
startService(startServiceIntent);
}
}
El servicio para comenzar y terminar el trabajo.
public class NetworkSchedulerService extends JobService implements
ConnectivityReceiver.ConnectivityReceiverListener {
private static final String TAG = NetworkSchedulerService.class.getSimpleName();
private ConnectivityReceiver mConnectivityReceiver;
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "Service created");
mConnectivityReceiver = new ConnectivityReceiver(this);
}
/**
* When the app''s NetworkConnectionActivity is created, it starts this service. This is so that the
* activity and this service can communicate back and forth. See "setUiCallback()"
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand");
return START_NOT_STICKY;
}
@Override
public boolean onStartJob(JobParameters params) {
Log.i(TAG, "onStartJob" + mConnectivityReceiver);
registerReceiver(mConnectivityReceiver, new IntentFilter(Constants.CONNECTIVITY_ACTION));
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
Log.i(TAG, "onStopJob");
unregisterReceiver(mConnectivityReceiver);
return true;
}
@Override
public void onNetworkConnectionChanged(boolean isConnected) {
String message = isConnected ? "Good! Connected to Internet" : "Sorry! Not connected to internet";
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
}
Finalmente, la clase de receptor que verifica los cambios de conexión de red.
public class ConnectivityReceiver extends BroadcastReceiver {
private ConnectivityReceiverListener mConnectivityReceiverListener;
ConnectivityReceiver(ConnectivityReceiverListener listener) {
mConnectivityReceiverListener = listener;
}
@Override
public void onReceive(Context context, Intent intent) {
mConnectivityReceiverListener.onNetworkConnectionChanged(isConnected(context));
}
public static boolean isConnected(Context context) {
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
}
public interface ConnectivityReceiverListener {
void onNetworkConnectionChanged(boolean isConnected);
}
}
No olvide agregar permiso y servicio dentro del archivo de manifiesto.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yourpackagename">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- Always required on api < 21, needed to keep a wake lock while your job is running -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<!-- Required on api < 21 if you are using setRequiredNetworkType(int) -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- Required on all api levels if you are using setPersisted(true) -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".connectivity.NetworkConnectionActivity"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Define your service, make sure to add the permision! -->
<service
android:name=".connectivity.NetworkSchedulerService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE"/>
</application>
</manifest>
Consulte los enlaces a continuación para obtener más información.
https://github.com/jiteshmohite/Android-Network-Connectivity
https://github.com/evant/JobSchedulerCompat