Answers:
是否有原生的android方法从服务获取对当前正在运行的Activity的引用?
您可能不拥有“当前正在运行的活动”。
我有一个在后台运行的服务,当事件(在服务中)发生时,我想更新当前的活动。有没有简单的方法可以做到这一点(就像我上面建议的那样)?
instanceof检查或重构活动以共享一个公共的超类或接口,那么您的服务将无法与它们做任何事情。而且,如果您要重构活动,则最好以更适合框架并涵盖更多方案的方式进行,例如没有活动处于活动状态。#4可能是最少的工作,也是最灵活的。
                    更新:从Android 5.0开始,此功能不再与其他应用程序的活动一起使用
这是使用活动管理器的一种好方法。您基本上可以从活动管理器中获得runningTasks。它将始终始终首先返回当前活动的任务。从那里您可以获取topActivity。
有一种简单的方法可以从ActivityManager服务中获取正在运行的任务的列表。您可以请求手机上运行的最大任务数,默认情况下,将首先返回当前活动的任务。
一旦有了,就可以通过从列表中请求topActivity来获取ComponentName对象。
这是一个例子。
    ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
    Log.d("topActivity", "CURRENT Activity ::" + taskInfo.get(0).topActivity.getClassName());
    ComponentName componentInfo = taskInfo.get(0).topActivity;
    componentInfo.getPackageName();
您需要在清单上具有以下权限:
<uses-permission android:name="android.permission.GET_TASKS"/>
              As of LOLLIPOP, this method is no longer available to third party applications: the introduction of document-centric recents means it can leak person information to the caller. For backwards compatibility, it will still return a small subset of its data: at least the caller's own tasks, and possibly some other tasks such as home that are known to not be sensitive.
                    Google威胁说,如果将出于无障碍目的使用无障碍服务的应用从Play商店中删除。但是,据报道正在对此进行重新考虑。
AccessibilityServiceAccessibilityService。onAccessibilityEvent回调中,检查事件类型以确定当前窗口何时更改。TYPE_WINDOW_STATE_CHANGED PackageManager.getActivityInfo()。GET_TASKS权限。AccessibilityService,如果应用在屏幕上放置了叠加层,则他们无法按OK(确定)按钮。Velis Auto Brightness和Lux就是其中一些应用。这可能会造成混淆,因为用户可能不知道为什么他们不能按下按钮或如何解决该按钮。AccessibilityService不知道当前的活动,直到第一个变化的活动。public class WindowChangeDetectingService extends AccessibilityService {
    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        //Configure these here for compatibility with API 13 and below.
        AccessibilityServiceInfo config = new AccessibilityServiceInfo();
        config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
        config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
        if (Build.VERSION.SDK_INT >= 16)
            //Just in case this helps
            config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
        setServiceInfo(config);
    }
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
            if (event.getPackageName() != null && event.getClassName() != null) {
                ComponentName componentName = new ComponentName(
                    event.getPackageName().toString(),
                    event.getClassName().toString()
                );
                ActivityInfo activityInfo = tryGetActivity(componentName);
                boolean isActivity = activityInfo != null;
                if (isActivity)
                    Log.i("CurrentActivity", componentName.flattenToShortString());
            }
        }
    }
    private ActivityInfo tryGetActivity(ComponentName componentName) {
        try {
            return getPackageManager().getActivityInfo(componentName, 0);
        } catch (PackageManager.NameNotFoundException e) {
            return null;
        }
    }
    @Override
    public void onInterrupt() {}
}
合并到清单中:
<application>
    <service
        android:label="@string/accessibility_service_name"
        android:name=".WindowChangeDetectingService"
        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
        <intent-filter>
            <action android:name="android.accessibilityservice.AccessibilityService"/>
        </intent-filter>
        <meta-data
            android:name="android.accessibilityservice"
            android:resource="@xml/accessibilityservice"/>
    </service>
</application>
放入res/xml/accessibilityservice.xml:
<?xml version="1.0" encoding="utf-8"?>
<!-- These options MUST be specified here in order for the events to be received on first
 start in Android 4.1.1 -->
<accessibility-service
    xmlns:tools="http://schemas.android.com/tools"
    android:accessibilityEventTypes="typeWindowStateChanged"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagIncludeNotImportantViews"
    android:description="@string/accessibility_service_description"
    xmlns:android="http://schemas.android.com/apk/res/android"
    tools:ignore="UnusedAttribute"/>
应用程序的每个用户都需要显式启用AccessibilityService才能使用它。请参阅此StackOverflow答案以了解如何执行此操作。
请注意,如果某个应用在屏幕上放置了叠加层(例如Velis Auto Brightness或Lux),则尝试启用辅助功能时,用户将无法按“确定”按钮。
settingsActivity的your.app.ServiceSettingsActivity,所以你应该改变,要你自己设置的活动为您的无障碍服务。我认为设置活动无论如何都是可选的,因此我从答案中删除了该部分以使其更简单。
                    onAccessibilityEvent,但未收到任何事件,但是如果我禁用了此功能,然后再次启用了无障碍服务,则该服务将重新激活并   onAccessibilityEvent开始工作。
                    可以通过以下方式完成:
实现您自己的应用程序类,注册ActivityLifecycleCallbacks-通过这种方式,您可以查看我们的应用程序的运行情况。在每一次继续执行时,回调都会在屏幕上分配当前可见的活动,并在暂停时将其删除。它使用registerActivityLifecycleCallbacks()API 14中添加的方法。
public class App extends Application {
private Activity activeActivity;
@Override
public void onCreate() {
    super.onCreate();
    setupActivityListener();
}
private void setupActivityListener() {
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        }
        @Override
        public void onActivityStarted(Activity activity) {
        }
        @Override
        public void onActivityResumed(Activity activity) {
            activeActivity = activity;
        }
        @Override
        public void onActivityPaused(Activity activity) {
            activeActivity = null;
        }
        @Override
        public void onActivityStopped(Activity activity) {
        }
        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        }
        @Override
        public void onActivityDestroyed(Activity activity) {
        }
    });
}
public Activity getActiveActivity(){
    return activeActivity;
}
}在您的服务呼叫中getApplication(),并将其强制转换为您的应用程序类名称(在这种情况下为App)。比您可以致电app.getActiveActivity()-会给您当前可见的活动(如果没有活动可见,则为null)。您可以通过致电获取活动名称activeActivity.getClass().getSimpleName()
onActivityResumed(),onActivityPaused()并getActiveActivity()查看其调用方式(如果有)。
                    activity和activeActivity是分配前一样activeActivity与null以便由于各种活动的生命周期方法调用混杂,以免差错。
                    我找不到能使我们的团队满意的解决方案,所以我们自己动手了。我们ActivityLifecycleCallbacks用来跟踪当前活动,然后通过服务公开它:
public interface ContextProvider {
    Context getActivityContext();
}
public class MyApplication extends Application implements ContextProvider {
    private Activity currentActivity;
    @Override
    public Context getActivityContext() {
         return currentActivity;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                MyApplication.this.currentActivity = activity;
            }
            @Override
            public void onActivityStarted(Activity activity) {
                MyApplication.this.currentActivity = activity;
            }
            @Override
            public void onActivityResumed(Activity activity) {
                MyApplication.this.currentActivity = activity;
            }
            @Override
            public void onActivityPaused(Activity activity) {
                MyApplication.this.currentActivity = null;
            }
            @Override
            public void onActivityStopped(Activity activity) {
                // don't clear current activity because activity may get stopped after
                // the new activity is resumed
            }
            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
            }
            @Override
            public void onActivityDestroyed(Activity activity) {
                // don't clear current activity because activity may get destroyed after
                // the new activity is resumed
            }
        });
    }
}
然后配置你的DI容器的回报情况MyApplication的ContextProvider,如
public class ApplicationModule extends AbstractModule {    
    @Provides
    ContextProvider provideMainActivity() {
        return MyApplication.getCurrent();
    }
}
(请注意,getCurrent()上面的代码省略了的实现。这只是从应用程序构造函数设置的静态变量)
activity和currentActivity是分配前一样currentActivity与null以便由于各种活动的生命周期方法调用混杂,以免差错。
                    ActivityManager如果您只想知道包含当前活动的应用程序,则可以使用ActivityManager。您可以使用的技术取决于Android的版本:
ActivityManager.RunningAppProcessInfo.processStatepublic class CurrentApplicationPackageRetriever {
    private final Context context;
    public CurrentApplicationPackageRetriever(Context context) {
        this.context = context;
    }
    public String get() {
        if (Build.VERSION.SDK_INT < 21)
            return getPreLollipop();
        else
            return getLollipop();
    }
    private String getPreLollipop() {
        @SuppressWarnings("deprecation")
        List<ActivityManager.RunningTaskInfo> tasks =
            activityManager().getRunningTasks(1);
        ActivityManager.RunningTaskInfo currentTask = tasks.get(0);
        ComponentName currentActivity = currentTask.topActivity;
        return currentActivity.getPackageName();
    }
    private String getLollipop() {
        final int PROCESS_STATE_TOP = 2;
        try {
            Field processStateField = ActivityManager.RunningAppProcessInfo.class.getDeclaredField("processState");
            List<ActivityManager.RunningAppProcessInfo> processes =
                activityManager().getRunningAppProcesses();
            for (ActivityManager.RunningAppProcessInfo process : processes) {
                if (
                    // Filters out most non-activity processes
                    process.importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
                    &&
                    // Filters out processes that are just being
                    // _used_ by the process with the activity
                    process.importanceReasonCode == 0
                ) {
                    int state = processStateField.getInt(process);
                    if (state == PROCESS_STATE_TOP) {
                        String[] processNameParts = process.processName.split(":");
                        String packageName = processNameParts[0];
                        /*
                         If multiple candidate processes can get here,
                         it's most likely that apps are being switched.
                         The first one provided by the OS seems to be
                         the one being switched to, so we stop here.
                         */
                        return packageName;
                    }
                }
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return null;
    }
    private ActivityManager activityManager() {
        return (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    }
}
将GET_TASKS权限添加到AndroidManifest.xml:
<!--suppress DeprecatedClassUsageInspection -->
<uses-permission android:name="android.permission.GET_TASKS" />
              我正在使用它进行测试。API> 19,但仅适用于您的应用活动。
@TargetApi(Build.VERSION_CODES.KITKAT)
public static Activity getRunningActivity() {
    try {
        Class activityThreadClass = Class.forName("android.app.ActivityThread");
        Object activityThread = activityThreadClass.getMethod("currentActivityThread")
                .invoke(null);
        Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
        activitiesField.setAccessible(true);
        ArrayMap activities = (ArrayMap) activitiesField.get(activityThread);
        for (Object activityRecord : activities.values()) {
            Class activityRecordClass = activityRecord.getClass();
            Field pausedField = activityRecordClass.getDeclaredField("paused");
            pausedField.setAccessible(true);
            if (!pausedField.getBoolean(activityRecord)) {
                Field activityField = activityRecordClass.getDeclaredField("activity");
                activityField.setAccessible(true);
                return (Activity) activityField.get(activityRecord);
            }
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    throw new RuntimeException("Didn't find the running activity");
}
              将此代码用于API 21或更高版本。与其他答案相比,该方法可以有效地提供更好的结果,并且可以完美地检测到前台进程。
if (Build.VERSION.SDK_INT >= 21) {
    String currentApp = null;
    UsageStatsManager usm = (UsageStatsManager) this.getSystemService(Context.USAGE_STATS_SERVICE);
    long time = System.currentTimeMillis();
    List<UsageStats> applist = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 1000, time);
    if (applist != null && applist.size() > 0) {
        SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>();
        for (UsageStats usageStats : applist) {
            mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
        }
        if (mySortedMap != null && !mySortedMap.isEmpty()) {
            currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
        }
    }
              这是我的答案,效果很好...
您应该能够以这种方式获取当前的活动...如果您使用一些带有很多片段的活动来构建应用程序,并且想要跟踪当前的活动是什么,那么它将需要大量的工作。我的观点是我确实有一个带有多个片段的活动。因此,我可以通过Application Object跟踪Current Activity,该对象可以存储Global变量的所有当前状态。
这是一种方法。启动活动时,可以通过Application.setCurrentActivity(getIntent());来存储该活动。该应用程序将存储它。在您的服务类上,您可以像Intent currentIntent = Application.getCurrentActivity();一样简单地进行操作。getApplication()。startActivity(currentIntent);
我不知道这是否是一个愚蠢的答案,但是通过在每次输入任何活动的onCreate()时在共享的首选项中存储一个标志来解决此问题,然后我使用舍弃的首选项中的值来查找它是前台的活动。
最近才发现这一点。使用api作为:
targetSdkVersion 26
ActivityManager.getCurrentActivity(上下文)
希望这是有用的。
getCurrentActivity(),ActivityManager该类中没有任何功能(developer.android.com/reference/android/app/ActivityManager)。有趣的是,该功能确实存在:   ActivityManager.isUserAMonkey()。