Как определить, когда приложение Android переходит в фоновый режим и возвращается на передний план - PullRequest
353 голосов
/ 11 декабря 2010

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

Ответы [ 38 ]

0 голосов
/ 28 февраля 2012

Эти ответы не верны. Эти методы также вызываются, когда начинается и заканчивается другое действие. Что вы можете сделать, так это сохранить глобальный флаг (да, глобальные перемены плохие :) и установить его в true каждый раз, когда вы начинаете новое действие. Установите значение false в onCreate каждого действия. Затем в onPause вы проверяете этот флаг. Если оно ложно, ваше приложение уходит в фоновый режим или его убивают.

0 голосов
/ 12 февраля 2016

Вот мое решение.Просто зарегистрируйте этот ActivityLifecycleCallbacks в вашем основном классе приложения.В комментариях я упоминаю профиль активности крайний случай.Это действие просто с прозрачными краями.

/**
 * This class used Activity lifecycle callbacks to determine when the application goes to the
 * background as well as when it is brought to the foreground.
 */
public class Foreground implements Application.ActivityLifecycleCallbacks
{
    /**
     * How long to wait before checking onStart()/onStop() count to determine if the app has been
     * backgrounded.
     */
    public static final long BACKGROUND_CHECK_DELAY_MS = 500;

    private static Foreground sInstance;

    private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
    private boolean mIsForeground = false;
    private int mCount;

    public static void init(final Application application)
    {
        if (sInstance == null)
        {
            sInstance = new Foreground();
            application.registerActivityLifecycleCallbacks(sInstance);
        }
    }

    public static Foreground getInstance()
    {
        return sInstance;
    }

    public boolean isForeground()
    {
        return mIsForeground;
    }

    public boolean isBackground()
    {
        return !mIsForeground;
    }

    @Override
    public void onActivityStarted(final Activity activity)
    {
        mCount++;

        // Remove posted Runnables so any Meteor disconnect is cancelled if the user comes back to
        // the app before it runs.
        mMainThreadHandler.removeCallbacksAndMessages(null);

        if (!mIsForeground)
        {
            mIsForeground = true;
        }
    }

    @Override
    public void onActivityStopped(final Activity activity)
    {
        mCount--;

        // A transparent Activity like community user profile won't stop the Activity that launched
        // it. If you launch another Activity from the user profile or hit the Android home button,
        // there are two onStops(). One for the user profile and one for its parent. Remove any
        // posted Runnables so we don't get two session ended events.
        mMainThreadHandler.removeCallbacksAndMessages(null);
        mMainThreadHandler.postDelayed(new Runnable()
        {
            @Override
            public void run()
            {
                if (mCount == 0)
                {
                    mIsForeground = false;
                }
            }
        }, BACKGROUND_CHECK_DELAY_MS);
    }

    @Override
    public void onActivityCreated(final Activity activity, final Bundle savedInstanceState)
    {

    }

    @Override
    public void onActivityResumed(final Activity activity)
    {

    }

    @Override
    public void onActivityPaused(final Activity activity)
    {

    }

    @Override
    public void onActivitySaveInstanceState(final Activity activity, final Bundle outState)
    {

    }

    @Override
    public void onActivityDestroyed(final Activity activity)
    {

    }
}
0 голосов
/ 28 февраля 2018

Используя приведенный ниже код, я могу получить приоритетное или фоновое состояние своего приложения.

Для более подробной информации о его работе, сильный текст нажмите здесь

import android.content.ComponentCallbacks2;
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

private Context context;
private Toast toast;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    context = this;
}

private void showToast(String message) {
    //If toast is already showing cancel it
    if (toast != null) {
        toast.cancel();
    }

    toast = Toast.makeText(context, message, Toast.LENGTH_SHORT);
    toast.show();
}

@Override
protected void onStart() {
    super.onStart();
    showToast("App In Foreground");
}

@Override
public void onTrimMemory(int level) {
    super.onTrimMemory(level);
    if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
        showToast("App In Background");
    }
  }
}
0 голосов
/ 04 июля 2012

Что я сделал, так это удостоверился, что все действия в приложении запускаются с startActivityForResult, а затем проверил, вызывался ли onActivityResult перед onResume. Если это не так, это означает, что мы только что вернулись откуда-то за пределами нашего приложения.

boolean onActivityResultCalledBeforeOnResume;

@Override
public void startActivity(Intent intent) {
    startActivityForResult(intent, 0);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);
    onActivityResultCalledBeforeOnResume = true;
}

@Override
protected void onResume() {
    super.onResume();
    if (!onActivityResultCalledBeforeOnResume) {
        // here, app was brought to foreground
    }
    onActivityResultCalledBeforeOnResume = false;
}
0 голосов
/ 04 февраля 2013

Основная проблема заключается в том, что вам нужно получить определенное поведение, когда вы запускаете действие из фона.Если вы переопределите методы onPause () и onResume (), у вас будет точный ответ, но не решение.Проблема заключается в том, что методы onPause () и onResume () вызываются, даже если вы не минимизируете свое приложение, их можно вызывать, когда вы запускаете действие, а затем нажимаете кнопку «Назад», чтобы вернуться к своей деятельности.Чтобы устранить эту проблему и действительно знать, когда ваше приложение приходит из фона, вы должны получить запущенный процесс и сравнить его с вашим процессом:

private boolean isApplicationBroughtToBackground() {
    ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> tasks = am.getRunningTasks(1);
    if (!tasks.isEmpty()) {
        ComponentName topActivity = tasks.get(0).topActivity;
        if (!topActivity.getPackageName().equals(getPackageName())) {
            return true;
        }
    }
    return false;
}

Теперь вам нужно объявить логическую переменную:

public boolean wasPaused = false;

И спросите, когда ваша активность переходит в фоновый режим:

@Override
public void onPause(){
    super.onPause();
    if(isApplicationBroughtToBackground())
        wasPaused = true;
}

Теперь, когда ваша активность снова появится на экране, спросите в методе onResume ():

@Override
public void onResume(){
    super.onResume();
    if(wasPaused){
        lockScreen(true);
    }
    wasPaused = false;
}

И это все.Теперь, когда ваша активность переходит в фоновый режим, а затем пользователь выводит ее на передний план, появляется экран блокировки.

Если вы хотите повторить это поведение для любой активности вашего приложения, вы должны создать действие(может быть BaseActivity), поместите эти методы, и все ваши действия должны наследоваться от BaseActivity.

Я надеюсь, что это поможет вам.

Привет!

0 голосов
/ 10 марта 2017

Как насчет этого решения

public class BaseActivity extends Activity
{

    static String currentAct = "";

    @Override
    protected void onStart()
    {
        super.onStart();

        if (currentAct.equals(""))
            Toast.makeText(this, "Start", Toast.LENGTH_LONG).show();

        currentAct = getLocalClassName();
    }

    @Override
    protected void onStop()
    {
        super.onStop();

        if (currentAct.equals(getLocalClassName()))
        {
            currentAct = "";
            Toast.makeText(this, "Stop", Toast.LENGTH_LONG).show();
        }
    }
}

Все действия должны расширять BaseActivity.

Когда действие вызывает другое (A-> B), тогда currentAct не равно getLocalClassName (), поскольку onStart () второго действия (B) вызывается перед onStop () первого (A) (https://developer.android.com/guide/components/activities.html#CoordinatingActivities).

Когда пользователь нажимает кнопку «Домой» или переключается между приложениями, он просто вызывает onStop (), и тогда currentAct равен getLocalClassName ().

0 голосов
/ 07 августа 2013

Я использую это решение: http://nathanael.hevenet.com/android-dev-detecting-when-your-app-is-in-the-background-across-activities/

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

Очень похоже на решение @ oldschool4664, но, на мой взгляд, чище

0 голосов
/ 04 мая 2016

Мое приложение должно "перезагрузиться" после возвращения из фона - показать серию действий, согласно просьбам клиентов.После тщательного поиска способов управления переходами между фоном и передним планом (которые по-разному трактуются между iOS и Android), я перешел к этому вопросу.Нашел здесь очень полезную помощь, особенно из ответов, набравших наибольшее количество голосов и помеченных как правильные.Тем не менее, просто восстанавливайте корневую активность КАЖДЫЙ РАЗ, когда приложение выходит на передний план, когда вы думаете о UX, это выглядело слишком раздражающим.Решение, которое сработало для меня, и которое я считаю наиболее адекватным - на основе функциональности приложений Youtube и Twitter - заключалось в объединении ответов @GirishNair и @ d60402: вызов таймера при обрезке памяти приложения следующим образом:

@Override
public void onTrimMemory(int level) {
    if (stateOfLifeCycle.equals("Stop")) {
        startActivityTransitionTimer();
    }

    super.onTrimMemory(level);
}

Мой лимит таймера установлен на 30 секунд - я думаю об этом немного увеличить.

private final long MAX_ACTIVITY_TRANSITION_TIME = 30000;

И когда приложение выходит на передний план, перезапускается или приложение уничтожается,вызовите метод для отмены таймера.

На расширение приложения:

@Override
public void onActivityCreated(Activity activity, Bundle arg1) {
    stopActivityTransitionTimer();
    stateOfLifeCycle = "Create";
}

@Override
public void onActivityDestroyed(Activity activity) {
    stopActivityTransitionTimer();
    stateOfLifeCycle = "Destroy";
}

На активности (предпочтительно на базовой деятельности, унаследованной другими):

@Override
protected void onStart() {
    super.onStart();
    if (App.wasInBackground) {
        stopActivityTransitionTimer();
    }
}

В моем случае, когда приложение выходит на передний план после максимального времени, создается новая задача, поэтому stopActivityTransitionTimer () вызывается для onActivityCreated () или onActivityDestroyed () в классе расширений приложения, что делает ненужным вызов метода вдеятельность.Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...