2011-04-08 25 views
26

Tengo una aplicación de Android que envía algunos datos a un servicio web. Necesito enviar estos datos tan pronto como se cierra la aplicación o se envían a fondo ... Pero, ¿cómo puedo lograr esto?Ejecutar código cuando la aplicación de Android está cerrada/enviada al fondo

Mi solución actual es ejecutarlo en OnPause() en la actividad de mi casa, pero necesito que esto se ejecute sin importar en qué actividad esté el usuario al cerrar la aplicación ... ¿Es posible o tengo que agregar el método OnPause para todas las actividades?

+0

Creo que un servicio realiza las operaciones a largo plazo y se activa cuando el usuario sale de la aplicación. – Utopia

Respuesta

21

Editar

Esta respuesta sólo sirve para un propósito, es decir, la ejecución de un código en onPause() para todas las actividades. No le permite ejecutar un código cuando su aplicación se envía a segundo plano.

respuesta original

Hacer una actividad denominada YourBasicActivity y anular su método onPause() y se extienden cada Actividad de YourBasicActivity

+1

hmm. esta es una buena sugerencia :) pero tengo en mi aplicación muchas actividades diferentes ... como ListActivity ... ¿cómo lo haría entonces? – Herter

+1

En ese caso, tendría que escribir YourListActivity porque es una forma especializada de 'Activity'. (En caso de que use tantas ListActivity) –

+19

Pero onPause() también se invoca cuando cambiamos de una actividad a otra, no justo cuando la aplicación se cierra o se envía a fondo. – peceps

0

reemplazar el método de su actividad principal onStop() y ejecutar el código allí.

0

Creo que necesita ejecutar su propio hilo que verificará si todas las actividades en ejecución en segundo plano o destruidas.

MyBasicActivity extends Activity 
{ 
    private static ArrayList<MyBasicActivity> activities=new ArrayList<MyBasicActivities); 
    private boolean started; 

    public void onCreate() 
    { 
     activities.add(this); 
    } 

    public void onDestroy() 
    { 
     activities.remove(this); 
    } 

    public void onStart() 
    { 
     this.started=true; 
    } 

    public void onPause() 
    { 
     this.started=false; 
    } 

    public boolean isStarted() 
    { 
     return started; 
    } 
} 

MyThread implements Runnable 
{ 
    private ArrayList<MyBasicActivity> activities; 

    public MyThread(ArrayList<MyBasicActivity> activities) 
    { 
     this.activities=activities; 
    } 

    void run() 
    { 
      while(!stopped) 
      { 
       boolean inBackground=true; 
       for(MyBasicActivity activity:activities) 
       { 
       if(activity.isStarted()) 
       { 
         inBackground=false; 
         break; 
       } 
       } 
       if(inBackground) 
        //run your code here; 
       sleep(10000); //10 secs 
      } 

    } 
} 
27

Comprobar esta solución primerohttps://stackoverflow.com/a/5862048/1037294 antes de decidirse a utilizar el código de abajo!


Para comprobar si su aplicación se envía al fondo, puede llamar a este código en onPause() o onStop() en todas las actividades en su aplicación:

/** 
    * Checks if the application is being sent in the background (i.e behind 
    * another application's Activity). 
    * 
    * @param context the context 
    * @return <code>true</code> if another application will be above this one. 
    */ 
    public static boolean isApplicationSentToBackground(final Context context) { 
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 
    List<RunningTaskInfo> tasks = am.getRunningTasks(1); 
    if (!tasks.isEmpty()) { 
     ComponentName topActivity = tasks.get(0).topActivity; 
     if (!topActivity.getPackageName().equals(context.getPackageName())) { 
     return true; 
     } 
    } 

    return false; 
    } 

Para que esto funcione debe incluir esto en su AndroidManifest.xml

<uses-permission android:name="android.permission.GET_TASKS" /> 
+0

¿No hay un evento para permitir que un receptor haga eso? – StErMi

+0

Hay un problema aquí. Esto no garantiza que la aplicación esté en segundo plano. La aplicación todavía podría estar ejecutándose y, como resultado, am.getRunningTasks() podría devolver su aplicación como la aplicación en ejecución. en cuyo caso este método devolverá falso. De su documentación: Tenga en cuenta que "ejecutar" no significa que el código de la tarea esté actualmente cargado o la actividad - la tarea puede haber sido congelada por el sistema, por lo que puede reiniciarse en su estado anterior cuando la próxima al primer plano. Más aquí: http://developer.android.com/reference/android/app/ActivityManager.html#getRecentTasks(int, int) – RPM

+0

He resuelto el problema anterior que mencioné llamando al código en onStop() – RPM

2

Tal vez esto puede ser útil, dime si funciona para usted. solo cuando regrese del fondo el valor de las actividades sería 0 (cero) el resto del tiempo sería un número mayor que 0 (cero) cuando se ejecuta onRestart() .

public class FatherClass extends Activity { 

private static int activities = 0; 

public void onCreate(Bundle savedInstanceState, String clase) { 
    super.onCreate(savedInstanceState); 
} 

protected void onRestart() 
{ 
    super.onRestart(); 
    if(activities == 0){ 
     Log.i("APP","BACK FROM BACKGROUND"); 
    } 
} 

protected void onStop(){ 
    super.onStop(); 
    activities = activities - 1; 
} 

protected void onStart(){ 
    super.onStart(); 
    activities = activities + 1; 
} 

} 

Todas sus clases deben extenderse desde esta clase para que esto funcione.

Explicación: El onStart se ejecuta uno la actividad es "visible" y el onStop cuando la actividad es "no visible".Entonces cuando su APLICACIÓN (dice APP no actividad) va al fondo todas las actividades son "no visibles" entonces ejecutan el método onStop, entonces la idea detrás de esto es AGREGAR UNO cada vez que se inició una actividad, y RESUMEN ONE cada vez que se oculta una actividad, por lo que si el valor de la variable "actividades" es cero, significa que todas las actividades que comenzaron en algún punto ahora no son visibles, por lo que cuando la APP vuelve desde el fondo y ejecuta onRestart método en la actividad en "frente" puede verificar si proviene de fondo o simplemente está reiniciando una actividad.

19

Este es el método que he utilizado y parece que funciona bastante bien:

que tienen una clase de aplicaciones de nivel superior de mi propia que se extiende aplicación como tal

public class MyApplication extends Application implements Application.ActivityLifecycleCallbacks { 

También necesita registro este objeto Aplicación en el archivo de manifiesto:

<application android:label="@string/app_name" android:icon="@drawable/ic_launcher" android:name=".MyApplication"> 

Note como también implementar la interfaz ActivityLifeCycleCallbacks. Esta interfaz tiene los siguientes métodos:

public static interface ActivityLifecycleCallbacks { 
    void onActivityCreated(android.app.Activity activity, android.os.Bundle bundle); 

    void onActivityStarted(android.app.Activity activity); 

    void onActivityResumed(android.app.Activity activity); 

    void onActivityPaused(android.app.Activity activity); 

    void onActivityStopped(android.app.Activity activity); 

    void onActivitySaveInstanceState(android.app.Activity activity, android.os.Bundle bundle); 

    void onActivityDestroyed(android.app.Activity activity); 
} 

que necesita para poner en práctica esos métodos y luego registrarse para estos eventos en sus aplicaciones onCreate() de la siguiente manera

@Override 
public void onCreate() { 
    super.onCreate(); 
    registerActivityLifecycleCallbacks(this); 
} 

Esto entonces llamar a la devolución de llamada (el MyApplication objeto) siempre que ocurra un método de ciclo de vida de actividad como onCreate(), onPause, etc. En su onActivityPaused() puede verificar si la aplicación está en segundo plano o no llamando al método @peceps: isApplicationSentToBackground (...)

Esto es lo que mi código es entonces ...

/** 
* Application.ActivityLifecycleCallbacks methods 
*/ 
@Override 
public void onActivityCreated(Activity activity, Bundle bundle) { 

} 

@Override 
public void onActivityStarted(Activity activity) { 
} 

@Override 
public void onActivityResumed(Activity activity) { 
} 

@Override 
public void onActivityStopped(Activity activity) { 
    try { 
     boolean foreground = new ForegroundCheckTask().execute(getApplicationContext()).get(); 
     if(!foreground) { 
      //App is in Background - do what you want 
     } 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } catch (ExecutionException e) { 
     e.printStackTrace(); 
    } 
} 

@Override 
public void onActivityPaused(Activity activity) { 
} 

@Override 
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { 
} 

@Override 
public void onActivityDestroyed(Activity activity) { 
} 

crear una nueva clase para ir al primer plano de control (que es un asíncrono. tarea). Ver check android application is in foreground or not? para más.

class ForegroundCheckTask extends AsyncTask<Context, Void, Boolean> { 
    @Override 
    protected Boolean doInBackground(Context... params) { 
     final Context context = params[0]; 
     return isAppOnForeground(context); 
    } 

    private boolean isAppOnForeground(Context context) { 
     ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 
     List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses(); 
     if (appProcesses == null) { 
      return false; 
     } 
     final String packageName = context.getPackageName(); 
     for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) { 
      if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) { 
       return true; 
      } 
     } 
     return false; 
    } 
} 
+0

Todavía necesitará los en su manifiesto – RPM

+1

disponible en API 14 - gran solución –

+1

¡Gran solución! Necesitaba obtener la actividad cuando la aplicación va a fondo (en pausa) y esto funcionó como un amuleto. Gracias – Pablo

0

puede utilizar el método onAppForegroundStateChange() que llama cuando la aplicación está abierta y el método closed.this sólo se invoca cuando la aplicación se presenta en primer plano/fondo. en el método AppForegroundStateChange() es mejor que utilizar el método onPause() porque el método onPause también se invoca cada vez que se va a otra actividad.

puede utilizar este método como la

public class MyApplication extends Application { 
    @Override 
    public void onCreate() { 
     super.onCreate(); 
     AppForegroundStateManager.getInstance().addListener(this); 
    } 

    @Override 
    public void onAppForegroundStateChange(AppForegroundStateManager.AppForegroundState newState) { 
     if (AppForegroundStateManager.AppForegroundState.IN_FOREGROUND == newState) { 
      // App just entered the foreground. Do something here! 
     } else { 
      // App just entered the background. Do something here! 
     } 
    } 
} 
Cuestiones relacionadas