如何检查活动是在前台或后台可见?

问题描述 投票:92回答:22

我有一个计时器启动画面。我的问题是,在我finish()我的活动我需要检查下一个活动已经开始,因为一个系统对话框弹出,而我只想finish();一旦用户选择了从对话框中的选项?

我知道,有就怎么看,如果你的活动是在前台的许多问题,但我不知道是否该允许对话盒上的活动之上了。

这里的问题是,红色是我的活动是在后台对话是在前台:

编辑:我曾尝试只是不使用finish()但后来我的活动可以在我正努力避免应用程序堆栈中回到了。

android android-activity dialog activity-finish
22个回答
177
投票

这是被推荐为正确的解决方案:

正确的解决方案(学分去丹,CommonsWare和NeTeInStEiN)使用Activity.onPause,Activity.onResume方法你自己的应用程序的轨道知名度。在其它的类商店“知名度”的地位。比较好的选择是自己执行应用程序或服务的(也有这种解决方案的一些变化,如果你想从服务检查活动的可见性)。

例如实现自定义应用程序类(注意isActivityVisible()静态方法):

public class MyApplication extends Application {

  public static boolean isActivityVisible() {
    return activityVisible;
  }  

  public static void activityResumed() {
    activityVisible = true;
  }

  public static void activityPaused() {
    activityVisible = false;
  }

  private static boolean activityVisible;
}

注册您的应用程序类在AndroidManifest.xml:

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

添加的onPause和的onResume每一个活动项目(您可能为您的活动的共同祖先,如果你想,但如果你的活动已经从MapActivity / ListActivity等扩展,你仍然需要手工编写以下) :

@Override
protected void onResume() {
  super.onResume();
  MyApplication.activityResumed();
}

@Override
protected void onPause() {
  super.onPause();
  MyApplication.activityPaused();
}

在你finish()方法,你想用isActivityVisible()以检查活动是否可见。在那里,你也可以检查,如果用户选择一个选项或没有。在满足这两个条件继续。

该人士还提到了两种错误的做法解决方案......所以要避免这样做。

来源:stackoverflow


2
投票

这可以通过使用Application.ActivityLifecycleCallbacks以高效的方式实现这一目标

例如让我们的活动类名作为ProfileActivity可以发现其是否在前台或后台

首先,我们需要通过扩展qazxsw POI创建应用程序类

它实现

Application.ActivityLifecycleCallbacks

让我的应用程序类,如下所示

应用类

Application Class

在上面的类有onActivityResumed ActivityLifecycleCallbacks的倍率methord

public class AppController extends Application implements Application.ActivityLifecycleCallbacks {


private boolean activityInForeground;

@Override
public void onCreate() {
    super.onCreate();

//register ActivityLifecycleCallbacks  

    registerActivityLifecycleCallbacks(this);

}



public static boolean isActivityVisible() {
    return activityVisible;
}

public static void activityResumed() {
    activityVisible = true;
}

public static void activityPaused() {
    activityVisible = false;
}

private static boolean activityVisible;

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

}

@Override
public void onActivityStarted(Activity activity) {

}

@Override
public void onActivityResumed(Activity activity) {
    //Here you can add all Activity class you need to check whether its on screen or not

    activityInForeground = activity instanceof ProfileActivity;
}

@Override
public void onActivityPaused(Activity activity) {

}

@Override
public void onActivityStopped(Activity activity) {

}

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

}

@Override
public void onActivityDestroyed(Activity activity) {

}

public boolean isActivityInForeground() {
    return activityInForeground;
}
}

其中,这是目前在屏幕上显示的所有活动实例可以发现,只需要检查你的活动是否在屏幕上或不按上述方法。

在注册的manifest.xml应用程序类

 @Override
public void onActivityResumed(Activity activity) {
    //Here you can add all Activity class you need to check whether its on screen or not

    activityInForeground = activity instanceof ProfileActivity;
}

要检查的天气活动是前景或背景按上述方案调用下面的方法对地方,你需要检查

<application
    android:name=".AppController" />

1
投票

你试过没有要求完成,并把“机器人:noHistory =”?清单中的真正”这将防止从去到堆栈中的活动。


1
投票

我不得不说,你的工作流程是不是在一个标准的Android方式。在Android中,如果你想从意图打开另一个活动,你不需要AppController applicationControl = (AppController) getApplicationContext(); if(applicationControl.isActivityInForeground()){ Log.d("TAG","Activity is in foreground") } else { Log.d("TAG","Activity is in background") } 您的活动。至于用户的方便,Android版允许用户使用“返回”键,从您打开您的应用程序的活动回去。

所以才让系统停止你的活动,并保存任何需要的时候,你的活动被称为回。


1
投票

如果你想知道,如果你的应用程序的任何活动是在屏幕上可见,你可以这样做:

finish()

只要创建这个类的单一,并设置它在你的应用实例如下图所示:

public class MyAppActivityCallbacks implements Application.ActivityLifecycleCallbacks {
private Set<Class<Activity>> visibleActivities = new HashSet<>();

@Override
public void onActivityResumed(Activity activity) {
    visibleActivities.add((Class<Activity>) activity.getClass());
}

@Override
public void onActivityStopped(Activity activity) {
     visibleActivities.remove(activity.getClass());
}

public boolean isAnyActivityVisible() {
    return !visibleActivities.isEmpty();
}

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

@Override
public void onActivityStarted(Activity activity) {}

@Override
public void onActivityPaused(Activity activity) {}

@Override
public void onActivityDestroyed(Activity activity) {}

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

然后你可以使用你的MyAppActivityCallbacks实例的isAnyActivityVisible()方法,无处不在!


0
投票

保存一个标志,如果你被暂停或恢复。如果你正在恢复它意味着你在前台

class App extends Application{
     @Override
     public void onCreate() {
         registerActivityLifecycleCallbacks(myAppActivityCallbacks);
     }
}

0
投票

一个可能的解决方案可能会设置一个标志,同时显示系统对话框,然后在活动生命周期的方法的onStop,检查标志,如果是真的,完成活动。

例如,如果系统对话框是由一些buttonclick触发,那么听者的onclick可能会像

boolean  isResumed = false;

@Override
public void onPause() {
  super.onPause();    
  isResumed = false;
}

@Override
public void onResume() {
  super.onResume();    
  isResumed = true;
}

private void finishIfForeground() {
  if (isResumed) {
    finish();
  }
}

在活动的onStop:

private OnClickListener btnClickListener = new OnClickListener() {

    @Override
    public void onClick(View v) {           
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_SEND);
        intent.setType("text/plain");
        CheckActivity.this.startActivity(Intent.createChooser(intent, "Complete action using"));
        checkFlag = true;  //flag used to check

    }
};

0
投票

为什么不使用这个广播?第二项活动(需要达到的那个)可以发送这样的本地广播:

@Override
protected void onStop() {
    if(checkFlag){
        finish();
    }
    super.onStop();
}

然后写飞溅活动中一个简单的接收器:

//put this in onCreate(..) or any other lifecycle method that suits you best
//notice the string sent to the intent, it will be used to register a receiver!
Intent result = new Intent("broadcast identifier");
result.putString("some message");//this is optional
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(result);

并注册与LocalBroadcastManager新的接收器收听来自你的第二个活动的广播:

//this goes on the class level (like a class/instance variable, not in a method) of your splash activity:
private BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        //kill activity here!!!
        //mission accomplished!
    }
};

请注意,您可以使用一个常量或字符串资源的“广播标识符”的字符串。


0
投票

如果您使用//notice the string sent to the intent filter, this is where you tell the BroadcastManager which broadcasts you want to listen to! LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(receiver, new IntentFilter("broadcast identifier")); 只是为了避免在你的堆栈(任务)应用程序的新应用开始,你可以开始新的应用程序时使用finish()标志,并且不叫Intent.FLAG_ACTIVITY_NEW_TASK可言。按照finish(),这是标志被用于实现“发射”式的行为。

documentation

0
投票

使用// just add this line before you start an activity intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); 内这些方法。 Activity

在API 17 如果最终的onDestroy()调用已对活动作出返回true,所以这种情况下,现在已经死了。

isDestroyed()

在API 1 请检查是否这项活动是在整理的过程中,或者是因为你叫光洁度()或其他人已要求它完成。这通常是在的onPause()用于确定活动是否被简单地暂停或完全整理。

isFinishing()

Memory Leaks Documentation一个常见的错误是捕获的强引用主机AsyncTask(或Activity):

Fragment

这是一个问题,因为class MyActivity extends Activity { private AsyncTask<Void, Void, Void> myTask = new AsyncTask<Void, Void, Void>() { // Don't do this! Inner classes implicitly keep a pointer to their // parent, which in this case is the Activity! } } 可以很容易地活得比父AsyncTask,例如,如果该任务运行时的配置发生了变化。

要做到这一点,正确的做法是让你的任务Activity类,它不捕获父,并保持static到主机weak reference

Activity

0
投票

下面是使用class MyActivity extends Activity { static class MyTask extends AsyncTask<Void, Void, Void> { // Weak references will still allow the Activity to be garbage-collected private final WeakReference<MyActivity> weakActivity; MyTask(MyActivity myActivity) { this.weakActivity = new WeakReference<>(myActivity); } @Override public Void doInBackground(Void... params) { // do async stuff here } @Override public void onPostExecute(Void result) { // Re-acquire a strong reference to the activity, and verify // that it still exists and is active. MyActivity activity = weakActivity.get(); if (activity == null || activity.isFinishing() || activity.isDestroyed()) { // activity is no longer valid, don't do anything! return; } // The activity is still valid, do main-thread stuff here } } } 类的解决方案。

Application

你可以简单地使用它像如下,

public class AppSingleton extends Application implements Application.ActivityLifecycleCallbacks {

private WeakReference<Context> foregroundActivity;


@Override
public void onActivityResumed(Activity activity) {
    foregroundActivity=new WeakReference<Context>(activity);
}

@Override
public void onActivityPaused(Activity activity) {
    String class_name_activity=activity.getClass().getCanonicalName();
    if (foregroundActivity != null && 
            foregroundActivity.get().getClass().getCanonicalName().equals(class_name_activity)) {
        foregroundActivity = null;
    }
}

//............................

public boolean isOnForeground(@NonNull Context activity_cntxt) {
    return isOnForeground(activity_cntxt.getClass().getCanonicalName());
}

public boolean isOnForeground(@NonNull String activity_canonical_name) {
    if (foregroundActivity != null && foregroundActivity.get() != null) {
        return foregroundActivity.get().getClass().getCanonicalName().equals(activity_canonical_name);
    }
    return false;
}
}

如果您有需要的活动或使用活动的规范名称的引用,你可以发现无论是在前台与否。这种解决方案可能无法做到万无一失。因此,您的意见是真正欢迎。


65
投票

如果定位API级14或以上,可以使用android.app.Application.ActivityLifecycleCallbacks

public class MyApplication extends Application implements ActivityLifecycleCallbacks {
    private static boolean isInterestingActivityVisible;

    @Override
    public void onCreate() {
        super.onCreate();

        // Register to be notified of activity state changes
        registerActivityLifecycleCallbacks(this);
        ....
    }

    public boolean isInterestingActivityVisible() {
        return isInterestingActivityVisible;
    }

    @Override
    public void onActivityResumed(Activity activity) {
        if (activity instanceof MyInterestingActivity) {
             isInterestingActivityVisible = true;
        }
    }

    @Override
    public void onActivityStopped(Activity activity) {
        if (activity instanceof MyInterestingActivity) {
             isInterestingActivityVisible = false;
        }
    }

    // Other state change callback stubs
    ....
}

0
投票

我不知道为什么没有人提及sharedPreferences,为活动A,(在的onPause例如())设置SharedPreference这样的:

((AppSingleton)context.getApplicationContext()).isOnForeground(context_activity);

我认为这是跟踪活动的知名度可靠的方法。


0
投票

SharedPreferences pref = context.getSharedPreferences(SHARED_PREF, 0); SharedPreferences.Editor editor = pref.edit(); editor.putBoolean("is_activity_paused_a", true); editor.commit(); 有用吗?这样,再加一个类级别的标志,像Activity.onWindowFocusChanged(boolean hasFocus)isFocused套,将是一个简单的方法在你活动的任何一点说,如果它集中与否。从阅读的文档,它看起来像它会正确设置在该活动并非直接在物理“前台”任何情况下“假”,就像如果正在显示一个对话框或通知托盘被拉低。

例:

onWindowFocusChanged

-3
投票

我以前做的一样,

如果该活动是不是在前台

getIntent()

将返回null。 := P


12
投票

UPD:更新状态Lifecycle.State.RESUMED。由于@htafoya了点。

在2019年新的支持库28+或AndroidX的帮助下,你可以简单地使用:

val isActivityInForeground = activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)

你可以阅读更多的the documenation了解引擎盖下发生了什么。


10
投票

这正是onPause和在onStop中,活性Activity class documentation事件之间的差别。

如果我理解正确的话,你需要做的是从你的活动finish()通话onStop终止它。看到Activity Lifecycle Demo App的附加图像。这是它的外观,当活动B从活动A.事件的顺序是从底部启动到顶部,所以你可以看到,活动结束后活动B onStop已经被称为A onResume被称为等。

在情况下会出现一个对话框您的活动在后台变暗,只有onPause被调用。


9
投票

Activity::hasWindowFocus()返回你所需要的布尔值。

public class ActivityForegroundChecker extends TimerTask
{
    private static final long FOREGROUND_CHECK_PERIOD = 5000;
    private static final long FIRST_DELAY             = 3000;

    private Activity m_activity;
    private Timer    m_timer;

    public ActivityForegroundChecker (Activity p_activity)
    {
        m_activity = p_activity;
    }

    @Override
    public void run()
    {
        if (m_activity.hasWindowFocus() == true) {
            // Activity is on foreground
            return;
        }
        // Activity is on background.
    }

    public void start ()
    {
        if (m_timer != null) {
            return;
        }
        m_timer = new Timer();
        m_timer.schedule(this, FIRST_DELAY, FOREGROUND_CHECK_PERIOD);
    }

    public void stop ()
    {
        if (m_timer == null) {
            return;
        }
        m_timer.cancel();
        m_timer.purge();
        m_timer = null;
    }
}

下面是一个例子类,无论你在哪里检查activites'的知名度。

请记住,如果你显示一个对话框,其结果将是错误的,因为该对话框会的主要焦点。除此之外,它真的很方便,比建议的解决方案更可靠。


7
投票

Two possible solutions :

1)行业生命周期回调

使用实现ApplicationActivityLifecycleCallbacks并用它来跟踪你的应用程序活动生命周期事件。需要注意的是ActivityLifecycleCallbacks是为Android API> = 14,对于以前的Android API,您需要自己实现它里面所有的活动的;-)

当你需要跨越的活动共享/存储的状态使用Application

2)检查正在运行的进程信息

您可以查看正在运行的进程的状态与此类RunningAppProcessInfo

取正在运行的进程列表以ActivityManager.getRunningAppProcesses()和过滤结果列表检查所需RunningAppProcessInfo并检查其“重要性”


4
投票

我已创建GitHub上app-foreground-background-listen项目

它使用了非常简单的逻辑和正常工作与所有Android API级别。


3
投票

使用从后台暂停和恢复之间的时间间隔,以确定它是否是从背景清醒

在自定义应用程序

private static boolean isInBackground;
private static boolean isAwakeFromBackground;
private static final int backgroundAllowance = 10000;

public static void activityPaused() {
    isInBackground = true;
    final Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            if (isInBackground) {
                isAwakeFromBackground = true;
            }
        }
    }, backgroundAllowance);
    Log.v("activity status", "activityPaused");
}

public static void activityResumed() {
    isInBackground = false;
    if(isAwakeFromBackground){
        // do something when awake from background
        Log.v("activity status", "isAwakeFromBackground");
    }
    isAwakeFromBackground = false;
    Log.v("activity status", "activityResumed");
}

在BaseActivity类

@Override
protected void onResume() {
  super.onResume();
  MyApplication.activityResumed();
}

@Override
protected void onPause() {
  super.onPause();
  MyApplication.activityPaused();
}

3
投票

我觉得我有更好的解决方案。因为你可以建立在简单的我Application.activity简历();由一个每个Activity延伸。

首先,你必须创建(如控制论Twerk大师兽人)

public class MyApplication extends Application {

  public static boolean isActivityVisible() {
    return activityVisible;
  }  

  public static void activityResumed() {
    activityVisible = true;
  }

  public static void activityPaused() {
    activityVisible = false;
  }

  private static boolean activityVisible;
}

接下来,你必须应用类添加到AndroidManifest.xml中

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

然后,创建一流ACTIVITYBASE

public class ActivityBase extends Activity {

    @Override
    protected void onPause() {
        super.onPause();
        MyApplication.activityPaused();
    }

    @Override
    protected void onResume() {
        super.onResume();
        MyApplication.activityResumed();
    }
}

最后,当你箱新的活动,你可以简单地通过ACTIVITYBASE,而不是活动进行了扩展。

public class Main extends ActivityBase {
    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }
}

对我来说,这是最好的方法,因为你必须只记得有关ACTIVITYBASE延伸。此外,你可以展开你的未来的基础功能。在我来说,我在一个类中增加了对我的服务型接收器,并提醒有关网络。

如果你的应用程序的你想检查的知名度,你可以简单地调用

MyApplication.isActivityVisible()
© www.soinside.com 2019 - 2024. All rights reserved.