所谓后台,我的意思是应用程序的活动目前对用户都不可见?


当前回答

自从Android API 16以来,有一个简单的方法来检查应用程序是否在前台。这可能不是万无一失的,但Android上没有万无一失的方法。当你的服务接收到来自服务器的更新,并且必须决定是否显示通知时,这个方法就足够好了(因为如果UI是前台,用户会注意到更新而不通知)。

RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;

其他回答

在我的onResume和onPause活动中,我写了一个isVisible布尔值给sharedpreferences。

    SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
    Editor editor = sharedPrefs.edit();
    editor.putBoolean("visible", false);
    editor.commit();

如有需要可在其他地方阅读,

    // Show a Toast Notification if App is not visible (ie in background. Not running, etc) 
    SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
    if(!sharedPrefs.getBoolean("visible", true)){...}

也许不优雅,但对我来说很管用……

我自己实现了ActivityLifecycleCallbacks。我正在使用SherlockActivity,但对于正常的活动类可能工作。

首先,我创建了一个接口,它有跟踪活动生命周期的所有方法:

public interface ActivityLifecycleCallbacks{
    public void onActivityStopped(Activity activity);
    public void onActivityStarted(Activity activity);
    public void onActivitySaveInstanceState(Activity activity, Bundle outState);
    public void onActivityResumed(Activity activity);
    public void onActivityPaused(Activity activity);
    public void onActivityDestroyed(Activity activity);
    public void onActivityCreated(Activity activity, Bundle savedInstanceState);
}

其次,我在我的应用程序的类中实现了这个接口:

public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{

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

    @Override
    public void onActivityStopped(Activity activity) {
        Log.i("Tracking Activity Stopped", activity.getLocalClassName());

    }

    @Override
    public void onActivityStarted(Activity activity) {
        Log.i("Tracking Activity Started", activity.getLocalClassName());

    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
    }

    @Override
    public void onActivityResumed(Activity activity) {
        Log.i("Tracking Activity Resumed", activity.getLocalClassName());
    }

    @Override
    public void onActivityPaused(Activity activity) {
        Log.i("Tracking Activity Paused", activity.getLocalClassName());
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        Log.i("Tracking Activity Created", activity.getLocalClassName());
    }
}

第三,我正在创建一个从SherlockActivity扩展的类:

public class MySherlockActivity extends SherlockActivity {

    protected MyApplication nMyApplication;

    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        nMyApplication = (MyApplication) getApplication();
        nMyApplication.onActivityCreated(this, savedInstanceState);
    }

    protected void onResume() {
        // TODO Auto-generated method stub
        nMyApplication.onActivityResumed(this);
        super.onResume();

    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        nMyApplication.onActivityPaused(this);
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        nMyApplication.onActivityDestroyed(this);
        super.onDestroy();
    }

    @Override
    protected void onStart() {
        nMyApplication.onActivityStarted(this);
        super.onStart();
    }

    @Override
    protected void onStop() {
        nMyApplication.onActivityStopped(this);
        super.onStop();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        nMyApplication.onActivitySaveInstanceState(this, outState);
        super.onSaveInstanceState(outState);
    }   
}

第四,所有从SherlockActivity扩展的类,我替换为MySherlockActivity:

public class MainActivity extends MySherlockActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

}

现在,在日志记录中,您将看到MyApplication中Interface实现中编写的日志。

谷歌解决方案-不是一个黑客,像以前的解决方案。使用ProcessLifecycleOwnerKotlin:

class ArchLifecycleApp : Application(), LifecycleObserver {

    override fun onCreate() {
        super.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(this)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onAppBackgrounded() {
        //App in background
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onAppForegrounded() {
        // App in foreground
    }

}

Java:

public class ArchLifecycleApp extends Application implements LifecycleObserver {

    @Override
    public void onCreate() {
        super.onCreate();
        ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onAppBackgrounded() {
        //App in background
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onAppForegrounded() {
        // App in foreground
    }
}

在app.gradle

dependencies {
    ...
    implementation "android.arch.lifecycle:extensions:1.1.0"

    //New Android X dependency is this - 
    implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
    
}

allprojects {
    repositories {
        ...
        google()
        jcenter()
        maven { url 'https://maven.google.com' }
    }
}

你可以在这里阅读更多关于生命周期相关的体系结构组件——https://developer.android.com/topic/libraries/architecture/lifecycle

你可以使用ComponentCallbacks2来检测应用程序是否在后台。顺便说一下,这个回调只在API级别14(冰淇淋三明治)及以上可用。

你会得到一个方法的调用:

onTrimMemory (int级)

如果级别是ComponentCallbacks2。TRIM_MEMORY_UI_HIDDEN则应用程序处于后台。

您可以将此接口实现到活动、服务等。

public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 {
   @Override
   public void onConfigurationChanged(final Configuration newConfig) {

   }

   @Override
   public void onLowMemory() {

   }

   @Override
   public void onTrimMemory(final int level) {
     if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
        // app is in background
     }
   }
}

在我看来,许多答案引入了大量的代码,带来了很多复杂性和可读性。

当人们问SO如何在服务和活动之间通信时,我通常建议使用LocalBroadcastManager。


Why?

我引用一下医生的话:

你知道你广播的数据不会离开你的应用程序,所以不需要担心泄露私人数据。 其他应用程序不可能将这些广播发送到你的应用程序,所以你不需要担心他们可以利用的安全漏洞。 这比通过系统发送全球广播更有效。

文档里没有:

它不需要外部库 代码是最少的 它易于实现和理解 没有自定义的自实现回调/超单例/进程内 任何模式…… 没有对Activity, Application,…


描述

你想要检查是否有Activity当前在前台。您通常在服务或应用程序类中这样做。

这意味着,您的Activity对象成为信号的发送者(I'm on / I'm off)。另一方面,您的服务成为接收者。

Activity有两个时刻告诉你它是在前台还是在后台(是的,只有两个…不是6)。

当Activity进入前台时,onResume()方法被触发(也在onCreate()之后调用)。

当Activity回到后面时,onPause()被调用。

在这些时刻,您的活动应该向您的服务发送信号,以描述其状态。

在有多个Activity的情况下,记住一个Activity先进入后台,然后另一个进入前台。

所以情况是:*

Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON

服务/应用程序将简单地监听这些信号并进行相应的操作。


代码(TLDR)

你的服务必须实现一个BroadcastReceiver来监听信号。

this.localBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // received data if Activity is on / off
    }
}

public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL") 

在服务中注册接收者::onCreate()

@Override
protected void onCreate() {
    LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}

在Service::onDestroy()中取消注册

@Override
protected void onDestroy() {
    // I'm dead, no need to listen to anything anymore.
    LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}

现在你的Activity必须传达它们的状态。

在活动::onResume ()

Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent    
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);

在活动::onPause ()

Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent    
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);

这是一种非常非常常见的情况

开发人员:我想从我的服务发送数据并更新活动。我如何检查活动是否在前景?

通常不需要检查Activity是否在前台。只需从服务中通过LocalBroadcastManager发送数据。如果活动处于开启状态,那么它将做出响应并采取行动。

对于这种非常常见的情况,服务成为发送方,活动实现BroadcastReceiver。

因此,在您的活动中创建一个Receiver。在onResume()中注册,在onPause()中取消注册。不需要使用其他生命周期方法。

在onReceive()中定义Receiver行为(更新ListView,做这个,做那个,…)

这样Activity只会在它在前台的时候监听,如果它在后面或者被销毁了什么也不会发生。

在多个活动的情况下,任何一个活动都将响应(如果它们也实现了Receiver)。

如果所有人都在后台,没有人会回应,信号就会丢失。

通过Intent(见上面的代码)通过指定信号ID从服务发送数据。


除了多窗口支持。这可能很棘手(如果需要,请测试它)…