studio - comprobar la aplicación de Android está en primer plano o no?
permisos especiales android (15)
A continuación, la solución funciona desde el nivel de API 14+
Backgrounding ComponentCallbacks2 - Ver la documentación no es 100% claro sobre cómo usaría esto. Sin embargo, eche un vistazo más de cerca y notará que el método onTrimMemory pasa en una bandera. Estos indicadores generalmente tienen que ver con la disponibilidad de la memoria, pero el que nos interesa es TRIM_MEMORY_UI_HIDDEN. Al verificar si la IU está oculta, podemos suponer que la aplicación está ahora en segundo plano. No es exactamente obvio, pero debería funcionar.
Foregrounding ActivityLifecycleCallbacks: podemos usar esto para detectar los conocimientos adquiridos anulando onActivityResumed y haciendo un seguimiento del estado actual de la aplicación (Foreground / Background).
Crea nuestra interfaz que será implementada por una clase de aplicación personalizada
interface LifecycleDelegate {
fun onAppBackgrounded()
fun onAppForegrounded()
}
Cree una clase que vaya a implementar ActivityLifecycleCallbacks y ComponentCallbacks2 y anule los métodos ActivityResumed y onTrimMemory
// Take an instance of our lifecycleHandler as a constructor parameter
class AppLifecycleHandler(private val lifecycleDelegate: LifecycleDelegate)
: Application.ActivityLifecycleCallbacks, ComponentCallbacks2 // <-- Implement these
{
private var appInForeground = false
// Override from Application.ActivityLifecycleCallbacks
override fun onActivityResumed(p0: Activity?) {
if (!appInForeground) {
appInForeground = true
lifecycleDelegate.onAppForegrounded()
}
}
// Override from ComponentCallbacks2
override fun onTrimMemory(level: Int) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// lifecycleDelegate instance was passed in on the constructor
lifecycleDelegate.onAppBackgrounded()
}
}
}
Ahora todo lo que tenemos que hacer es que nuestra clase de aplicación personalizada implemente nuestra interfaz LifecycleDelegate y se registre.
class App : Application(), LifeCycleDelegate {
override fun onCreate() {
super.onCreate()
val lifeCycleHandler = AppLifecycleHandler(this)
registerLifecycleHandler(lifeCycleHandler)
}
override fun onAppBackgrounded() {
Log.d("Awww", "App in background")
}
override fun onAppForegrounded() {
Log.d("Yeeey", "App in foreground")
}
private fun registerLifecycleHandler(lifeCycleHandler: AppLifecycleHandler) {
registerActivityLifecycleCallbacks(lifeCycleHandler)
registerComponentCallbacks(lifeCycleHandler)
}
}
En Manifest establece la CustomApplicationClass
<application
android:name=".App"
Esta pregunta ya tiene una respuesta aquí:
Recibí muchas respuestas para esta pregunta. Pero se trata de una sola actividad ... ¿Cómo comprobar si toda la aplicación se ejecuta en primer plano o no?
A continuación, se encuentra la solución actualizada para el último SDK de Android.
String PackageName = context.getPackageName();
ActivityManager manager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
ComponentName componentInfo;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
List<ActivityManager.AppTask> tasks = manager.getAppTasks();
componentInfo = tasks.get(0).getTaskInfo().topActivity;
}
else
{
List<ActivityManager.RunningTaskInfo> tasks = manager.getRunningTasks(1);
componentInfo = tasks.get(0).topActivity;
}
if (componentInfo.getPackageName().equals(PackageName))
return true;
return false;
Espero que esto ayude, gracias.
Con las nuevas extensiones de Android Architecture of Lifecycle, podemos lograr esto con la mayor facilidad.
Solo asegúrese de obtener esta dependencia en su archivo build.gradle:
dependencies {
implementation "android.arch.lifecycle:extensions:1.1.0"
}
Luego, en su clase de Aplicación, use esto:
class ArchLifecycleApp : Application(), LifecycleObserver {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded() {
Log.d("MyApp", "App in background")
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded() {
Log.d("MyApp", "App in foreground")
}
}
Al final, actualice su archivo AndroidManifest.xml con:
<application
android:name=".ArchLifecycleApp"
//Your extra code
....>
</application>
Ahora, cada vez que la Aplicación vaya a Primer plano o Fondo, recibiremos los Registros asociados con los dos métodos declarados.
Desde Android 19, puede registrar una devolución de llamada de ciclo de vida de la aplicación en onCreate () de su clase de aplicación de esta manera:
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new AppLifecycleCallback());
}
El AppLifecycleCallback se ve así:
class AppLifecycleCallback implements Application.ActivityLifecycleCallbacks {
private int numStarted = 0;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
if (numStarted == 0) {
//app went to foreground
}
numStarted++;
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
numStarted--;
if (numStarted == 0) {
// app went to background
}
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
}
Encontré una solución simple para esto al crear una clase de actividad base, debes extender todas tus clases de actividad desde aquí:
public class BaseActivity extends ActionBarActivity {
@Override
protected void onResume() {
ApplicationStateChecker.view_resumed(this);
super.onResume();
}
@Override
protected void onStop() {
ApplicationStateChecker.view_stopped(this);
super.onStop();
}
@Override
protected void onPause() {
ApplicationStateChecker.view_paused(this);
super.onPause();
}
}
Clase ApplicationStateChecker:
public class ApplicationStateChecker {
private static final String _pause_string = "paused";
private static final String _resume_string = "resumed";
private static String _view_lastState;
private static boolean _from_background = true;
public static void view_paused(Activity activity){
_view_lastState = _pause_string;
}
public static void view_stopped(Activity activity){
if ( _view_lastState.equals(_pause_string) ){
//if stop called and last event was pause then app is brought to background
_from_background = true;
} //if
}
public static void view_resumed(Activity activity){
if ( _from_background ) {
//Do your stuff here , app is brought to foreground
} //if
_from_background = false;
_view_lastState = _resume_string;
}
He intentado con el filtro del paquete desde el proceso en ejecución. pero eso es muy raro. En lugar de eso, he intentado con una nueva solución y esto funciona perfectamente. Lo he comprobado muchas veces y obtuve el resultado perfecto a través de este módulo.
private int numRunningActivities = 0;
public void onCreate() {
super.onCreate();
this.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityStarted(Activity activity) {
numRunningActivities++;
if (numRunningActivities == 1) {
LogUtils.d("APPLICATION", "APP IN FOREGROUND");
}
}
@Override
public void onActivityStopped(Activity activity) {
numRunningActivities--;
if (numRunningActivities == 0) {
Log.e("", "App is in BACKGROUND")
}
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
});
}
La biblioteca de Android Architecture Components puede usar ProcessLifecycleOwner para configurar un escucha para todo el proceso de aplicación para eventos onStart y onStop. Para hacer esto, haga que su clase de aplicación implemente la interfaz de LifecycleObserver y agregue algunas anotaciones para onStop y onStart a sus métodos de fondo y primer plano.
class ArchLifecycleApp : Application(), LifecycleObserver {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded() {
Log.d("Awww", "App in background")
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded() {
Log.d("Yeeey", "App in foreground")
}
}
La forma más sencilla y no obsoleta que he encontrado hasta ahora para hacer esto, es la siguiente:
@Override
public boolean foregrounded() {
ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
ActivityManager.getMyMemoryState(appProcessInfo);
return (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE)
}
Solo funciona con SDK 16+.
EDITAR :
Eliminé el siguiente código de la solución:
KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
// App is foreground, but screen is locked, so show notification
return km.inKeyguardRestrictedInputMode();
ya que eso hace que no se reciban las notificaciones si la pantalla está bloqueada. Eché un vistazo al marco y el propósito de esto no está del todo claro. Lo eliminaría Verificar el estado de la información del proceso sería suficiente :-)
La respuesta de @ user370305 es propensa a errores y desalentada por los desarrolladores de SO Android (compruebe https://groups.google.com/forum/#!msg/android-developers/zH-2bovZSLg/L2YM8Z1N-HwJ )
Hay un enfoque mucho más simple:
En una actividad base que todas las actividades se extienden :
protected static boolean isVisible = false;
@Override
public void onResume() {
super.onResume();
setVisible(true);
}
@Override
public void onPause() {
super.onPause();
setVisible(false);
}
Siempre que necesite verificar si alguna de sus actividades de aplicación está en primer plano, simplemente marque isVisible();
Para comprender este enfoque, verifique esta respuesta del ciclo de vida de la actividad side-by-side : Actividad ciclo de vida lado a lado
La respuesta de cesards es correcta, pero solo para API> 15. Para versiones de API inferiores, decidí usar el método getRunningTasks()
:
private boolean isAppInForeground(Context context)
{
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
{
ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName();
return foregroundTaskPackageName.toLowerCase().equals(context.getPackageName().toLowerCase());
}
else
{
ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
ActivityManager.getMyMemoryState(appProcessInfo);
if (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE)
{
return true;
}
KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
// App is foreground, but screen is locked, so show notification
return km.inKeyguardRestrictedInputMode();
}
}
Por favor, avíseme si funciona para todos ustedes.
Ninguna de las soluciones basadas en getRunningTasks () funciona en versiones recientes de Android, getRunningTasks () se desaprobó en API nivel 21. Incluso si todavía se usa, no devuelve suficiente información para determinar si la aplicación está en primer plano.
En su lugar, amplíe la clase de aplicación y use Application.ActivityLifecycleCallbacks para rastrear el estado de visibilidad de la aplicación.
public class MyApplication extends Application {
static final String APP_STATE_FOREGROUND = "com.xxx.appstate.FOREGROUND";
static final String APP_STATE_BACKGROUND = "com.xxx.appstate.BACKGROUND";
private static int m_foreground = -1;
private Handler m_handler = new Handler();
private Runnable m_guard;
public static boolean isForeground() {
return m_foreground == 1;
}
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
if(m_guard != null) {
m_handler.removeCallbacks(m_guard);
m_guard = null;
}
if(m_foreground == 1)
return;
m_foreground = 1;
sendBroadcast(new Intent(APP_STATE_FOREGROUND));
}
@Override
public void onActivityPaused(Activity activity) {
if(m_foreground == 0)
return;
/*
* Use a 400ms guard to protect against jitter
* when switching between two activities
* in the same app
*/
m_guard = new Runnable() {
@Override
public void run() {
if(m_foreground == 1) {
m_foreground = 0;
sendBroadcast(new Intent(APP_STATE_BACKGROUND));
}
}
};
m_handler.postDelayed(m_guard, 400);
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
});
}
}
El uso del temporizador de protección de 400 ms elimina la detección falsa del estado de fondo al cambiar de actividades en la misma aplicación. El estado de fondo / primer plano se puede consultar en cualquier momento usando:
MyApplication.isForeground();
Una clase también puede escuchar los eventos de difusión si está interesado en las transiciones de estado:
private static IntentFilter m_appStateFilter;
static {
m_appStateFilter = new IntentFilter();
m_appStateFilter.addAction(MyApplication.APP_STATE_FOREGROUND);
m_appStateFilter.addAction(MyApplication.APP_STATE_BACKGROUND);
}
private BroadcastReceiver m_appStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(MyApplication.APP_STATE_FOREGROUND)) {
/* application entered foreground */
} else if (action.equals(MyApplication.APP_STATE_BACKGROUND)) {
/* application entered background */
}
}
};
registerReceiver(m_appStateReceiver, m_appStateFilter);
No hay devolución de llamada global para esto, pero para cada actividad es onStop (). No es necesario que te metas con una int atómica. Solo tiene un int global con la cantidad de actividades iniciadas, en cada actividad incremente en onStart () y disminuya en onStop ().
public class BaseActivity extends ActionBarActivity {
public static int count = 0;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected void onStart() {
super.onStart();
count = count + 1;
Log.d(TAG, "onStart" + count);
if (count == 1) {
Toast.makeText(getApplicationContext(), "online", Toast.LENGTH_SHORT).show();
}
}
protected void onStop() {
super.onStop();
count = count - 1;
if (count == 0) {
Toast.makeText(getApplicationContext(), "offline", Toast.LENGTH_SHORT).show();
}
}
}
Pruebe ActivityLifecycleCallbacks en su clase de aplicación.
verifica si la aplicación está en segundo plano o en primer plano. Este método devolverá verdadero si la aplicación está en segundo plano.
Primero agregue el permiso GET_TASKS a su AndroidManifest.xml
private boolean isAppIsInBackground(Context context) {
boolean isInBackground = true;
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) {
List<ActivityManager.RunningAppProcessInfo> runningProcesses = am.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
for (String activeProcess : processInfo.pkgList) {
if (activeProcess.equals(context.getPackageName())) {
isInBackground = false;
}
}
}
}
} else {
List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
ComponentName componentInfo = taskInfo.get(0).topActivity;
if (componentInfo.getPackageName().equals(context.getPackageName())) {
isInBackground = false;
}
}
return isInBackground;
}
No entiendo lo que quiere, pero puede detectar la aplicación de primer plano / fondo actual con la llamada a ActivityManager.getRunningAppProcesses()
.
Algo como,
class ForegroundCheckTask extends AsyncTask<Context, Void, Boolean> {
@Override
protected Boolean doInBackground(Context... params) {
final Context context = params[0].getApplicationContext();
return isAppOnForeground(context);
}
private boolean isAppOnForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
if (appProcesses == null) {
return false;
}
final String packageName = context.getPackageName();
for (RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
}
// Use like this:
boolean foregroud = new ForegroundCheckTask().execute(context).get();
También avíseme si no lo entiendo ...
ACTUALIZAR: Mire esta pregunta SO. Determinar la aplicación en primer plano actual de una tarea en segundo plano o servicio para obtener más información.
Gracias..