Запуск кода, когда приложение Android закрыто / отправлено в фоновый режим

У меня есть приложение для Android, которое отправляет некоторые данные в веб-сервис. Мне нужно отправить эти данные, как только приложение будет закрыто или отправлено в фоновый режим. Но как мне это сделать?

Мое текущее решение состоит в том, чтобы запустить его на OnPause() в моем домашнем действии, но мне нужно, чтобы оно выполнялось независимо от того, какое действие выполняет пользователь при закрытии приложения. Возможно ли это, или я должен добавить метод OnPause в все виды деятельности?

8 ответов

Решение

редактировать

Этот ответ служит только для одной цели, то есть запуска кода в onPause() для всех видов деятельности. Он не позволяет запускать код, когда ваше приложение отправляется в фоновый режим.

Оригинальный ответ

Сделайте деятельность с именем YourBasicActivity и переопределить его onPause() метод и расширить каждую деятельность от YourBasicActivity

Проверьте это решение сначала /questions/23694610/proverka-rabotaet-li-prilozhenie-android-v-fonovom-rezhime/23694621#23694621 прежде чем вы решите использовать код ниже!


Чтобы проверить, отправлена ​​ли ваша заявка в фоновый режим, вы можете позвонить по этому коду на onPause() или же onStop() по каждому виду деятельности в вашем приложении:

 /**
   * 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;
  }

Чтобы это работало, вы должны включить это в свой AndroidManifest.xml

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

Это метод, который я использовал, и он, кажется, работает довольно хорошо:

У меня есть собственный класс Application высшего уровня, который расширяет Application как таковой

public class MyApplication extends Application implements Application.ActivityLifecycleCallbacks {

Вам также необходимо зарегистрировать этот объект Application в файле манифеста:

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

Обратите внимание, как я также реализую интерфейс ActivityLifeCycleCallbacks. Этот интерфейс имеет следующие методы:

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);
}

Вам необходимо реализовать эти методы, а затем зарегистрироваться для этих событий в ваших приложениях onCreate() следующим образом

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

Затем он будет вызывать обратный вызов (объект MyApplication) всякий раз, когда происходит метод жизненного цикла действия, такой как onCreate(), onPause и т. Д. В вашем onActivityPaused() вы можете затем проверить, было ли приложение фоновым или нет, вызвав метод @peceps: isApplicationSentToBackground(...)

Вот так выглядит мой код...

/**
 * 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) {
}

Создайте новый класс для проверки Foreground (это асинхронная задача). Видите, проверка приложения Android находится на переднем плане или нет? для большего.

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 (ноль), а остальное время будет больше 0 (ноль) при выполнении 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;
}

}

Все ваши классы должны выходить из этого класса, чтобы это работало.

Объяснение: OnStart выполняется, когда действие "видимое", и onStop, когда действие "не видно". Поэтому, когда ваше приложение (оно говорит, что приложение не является активностью) переходит в фоновый режим, все действия "не видны", поэтому они выполняют метод onStop, поэтому идея заключается в том, чтобы ДОБАВИТЬ ОДИН каждый раз, когда начинается действие, и ПОДРАЗУМЕВАТЬ ОДИН каждый раз действие скрыто, поэтому, если значение переменной "активность" равно нулю, это означает, что все действия, которые были начаты в некоторой точке, теперь не видны, поэтому, когда ваше приложение возвращается из фона и выполняет метод onRestart для действия в "передний" вы можете проверить, идет ли он из фона или просто перезапускает действие.

Вы можете использовать метод onAppForegroundStateChange(), который вызывается, когда приложение открыто и закрыто. Этот метод вызывается только тогда, когда ваше приложение находится на переднем плане / фоне. Метод onAppForegroundStateChange() лучше, чем метод onPause(), потому что метод onPause также вызывается каждый раз, когда вы переходите к другой операции.

Вы можете использовать этот метод, как это

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!
        }
    }
}

Я думаю, что вам нужно запустить свой собственный поток, который будет проверять, все ли запущенные действия в фоновом режиме или уничтожены.

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
          }

    }
}

Если вы пытаетесь отправить / сохранить данные, введенные пользователем, есть лучшие способы сделать это, чем делать это, когда он пытается закрыть приложение. Есть много способов закрыть приложение. Пользователь может даже выключить телефон. Поэтому трудно принять меры предосторожности против всех них.

Я бы посоветовал вам отправлять данные каждый раз, когда пользователь прекращает запись, любое количество секунд или когда он нажимает кнопку, например, если ваш вызов в веб-сервис слишком медленный.

Таким образом, это более безопасно и проще в реализации.

Переопределить onStop() метод вашей домашней деятельности и запустить код там.

Другие вопросы по тегам