简体   繁体   English

检查应用程序是在前台还是后台运行(使用同步适配器)

[英]Check if app is running in foreground or background (with sync adapter)

I know this's a repeated question but i've looked all over the place and couldn't find a solution that works for me so...我知道这是一个重复的问题,但我已经找遍了所有地方,找不到适合我的解决方案,所以......

I've an app that fetches movie data from TMDB API, it fetches it by page using a sync adapter, basically it runs great except when the sync adapter's periodic sync is ran while the app is open and the user is not at the first page, so my options were to force update the movies list and send the user to the top of the list which is totally bad experience so not considered as an option, Or i could check if the app is running, either in foreground or in the app stack that it's not visible to the user yet still running, so the best i could get to by searching was this piece of code:我有一个从 TMDB API 获取电影数据的应用程序,它使用同步适配器按页面获取它,基本上它运行良好,除非在应用程序打开并且用户不在第一页时运行同步适配器的定期同步,所以我的选择是强制更新电影列表并将用户发送到列表的顶部,这是完全糟糕的体验,因此不被视为一个选项,或者我可以检查应用程序是否正在运行,无论是在前台还是在应用程序中堆栈,它对用户不可见但仍在运行,所以我可以通过搜索得到的最好的代码是这段代码:

   public static boolean isAppRunning(final Context context, final String packageName) {

    final ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    final List<ActivityManager.RunningAppProcessInfo> procInfos = activityManager.getRunningAppProcesses();

    if (procInfos != null) {
        for (final ActivityManager.RunningAppProcessInfo processInfo : procInfos) {
            if (processInfo.processName.equals(packageName))
                return true;
        }
    }

    return false;
}

but for whatever reason it doesn't work correctly and sees the app as running even if i killed it by swiping, at first i thought it was because i have a sync adapter which could be considered as the app running so i used another process for it in the manifest using the但无论出于何种原因,它都无法正常工作,并且即使我通过滑动杀死了它,它也会看到该应用程序正在运行,起初我认为这是因为我有一个同步适配器,它可以被视为正在运行的应用程序,所以我使用了另一个进程它在清单中使用

android:process=":service"

but it didn't work但它没有用

Also thought about using variables in onStart and onStop of the activity but it's not guaranteed that onStop will be called when app is closed or killed so trying to avoid this method还考虑在活动的 onStart 和 onStop 中使用变量,但不能保证在关闭或终止应用程序时会调用 onStop,因此尽量避免使用此方法

this's my manifest.xml这是我的 manifest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="inc.mourad.ahmed.watchme">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />

<permission
    android:name="inc.ahmed.mourad.ACCESS_WATCHME_DATABASE"
    android:label="access my movies content provider"
    android:protectionLevel="dangerous" />
<permission
    android:name="inc.ahmed.mourad.ACCESS_WATCHME_SYNC_SERVICE"
    android:label="access my sync service"
    android:protectionLevel="dangerous" />
<permission
    android:name="inc.ahmed.mourad.ACCESS_WATCHME_SYNC_AUTHENTICATOR_SERVICE"
    android:label="access my sync authenticator dummy service"
    android:protectionLevel="dangerous" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/Theme.AppCompat">

    <activity android:name=".SplashScreenActivity"
        android:theme="@style/Theme.AppCompat.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat">
        <intent-filter>
            <data
                android:host="www.ahmedmourad.com"
                android:pathPrefix="/watchme/"
                android:scheme="http" />

            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT"/>
            <category android:name="android.intent.category.BROWSABLE"/>
        </intent-filter>
    </activity>

    <activity
        android:name=".SettingsActivity"
        android:label="@string/title_activity_settings"
        android:parentActivityName=".MainActivity">
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="inc.mourad.ahmed.watchme.MainActivity" />
    </activity>
    <activity android:name=".MovieDetailsActivity" />

    <provider
        android:name=".data.MovieProvider"
        android:authorities="@string/content_authority"
        android:enabled="true"
        android:exported="false"
        android:permission="inc.ahmed.mourad.ACCESS_WATCHME_DATABASE"
        android:syncable="true" />

    <!-- SyncAdapter's dummy authentication service -->
    <service android:name=".sync.WatchMeAuthenticatorService"
        android:permission="inc.ahmed.mourad.ACCESS_WATCHME_SYNC_AUTHENTICATOR_SERVICE"
        android:process=":service">
        <intent-filter>
            <action android:name="android.accounts.AccountAuthenticator" />
        </intent-filter>

        <meta-data
            android:name="android.accounts.AccountAuthenticator"
            android:resource="@xml/authenticator" />
    </service>

    <!-- The SyncAdapter service -->
    <service
        android:name=".sync.WatchMeSyncService"
        android:exported="true"
        android:permission="inc.ahmed.mourad.ACCESS_WATCHME_SYNC_SERVICE"
        android:process=":service">
        <intent-filter>
            <action android:name="android.content.SyncAdapter" />
        </intent-filter>

        <meta-data
            android:name="android.content.SyncAdapter"
            android:resource="@xml/syncadapter" />
    </service>

</application>

so, any ideas?那么,有什么想法吗? Thanks in advance提前致谢

We tweaked your idea and came up with this (in Kotlin, see below for Java):我们调整了你的想法并提出了这个(在 Kotlin 中,Java 见下文):

fun appInForeground(context: Context): Boolean {
    val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    val runningAppProcesses = activityManager.runningAppProcesses ?: return false
    return runningAppProcesses.any { it.processName == context.packageName && it.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND }
}

This is the equivalent in Java:这在 Java 中是等价的:

private boolean appInForeground(@NonNull Context context) {
    ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();
    if (runningAppProcesses == null) {
        return false;
    }

    for (ActivityManager.RunningAppProcessInfo runningAppProcess : runningAppProcesses) {
        if (runningAppProcess.processName.equals(context.getPackageName()) &&
                runningAppProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
            return true;
        }
    }
    return false;
}

Here's the relevant documentation. 这是相关文档。

Original Answer : https://stackoverflow.com/a/48767617/10004454 The recommended way to do it in accordance with Android documentation is原始答案: https : //stackoverflow.com/a/48767617/10004454根据 Android 文档推荐的方法是

class MyApplication : Application(), LifecycleObserver {

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

fun isInForeground(): Boolean {
    return ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)
}

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

    Log.e(TAG, "************* backgrounded")
    Log.e(TAG, "************* ${isInForeground()}")
}

@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded() {

    Log.e(TAG, "************* foregrounded")
    Log.e(TAG, "************* ${isInForeground()}")
    // App in foreground
}}

In your gradle (app) add : implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"在您的 gradle(应用程序)中添加: implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"

Then to check the state at runtime call (applicationContext as MyApplication).isActivityVisible()然后在运行时调用(applicationContext as MyApplication).isActivityVisible()检查状态(applicationContext as MyApplication).isActivityVisible()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM