Geo*_*rge 172 service android android-activity
是否有一种原生的android方法来从服务获取对当前运行的Activity的引用?
我有一个在后台运行的服务,我想在事件发生时(在服务中)更新我当前的Activity.有没有一种简单的方法(就像我上面建议的那样)?
Nel*_*rez 139
这是使用活动管理器完成此操作的好方法.您基本上从活动管理器获取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();
Run Code Online (Sandbox Code Playgroud)
您的清单上需要以下权限:
<uses-permission android:name="android.permission.GET_TASKS"/>
Run Code Online (Sandbox Code Playgroud)
Sam*_*Sam 103
Google已威胁要从Play商店中移除应用,如果他们使用辅助功能服务用于非无障碍目的.但据报道,这一情况正在重新考虑之中.
AccessibilityServiceAccessibilityService.onAccessibilityEvent回调中,检查事件类型以确定当前窗口何时更改.TYPE_WINDOW_STATE_CHANGED PackageManager.getActivityInfo().GET_TASKS许可.AccessibilityService,如果应用在屏幕上放置了叠加层,则无法按"确定"按钮.一些应用程序是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() {}
}
Run Code Online (Sandbox Code Playgroud)
将其合并到您的清单中:
<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>
Run Code Online (Sandbox Code Playgroud)
把它放进去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"/>
Run Code Online (Sandbox Code Playgroud)
应用程序的每个用户都需要明确启用AccessibilityService它才能使用它.有关如何执行此操作,请参阅此StackOverflow答案.
请注意,如果应用在屏幕上放置了叠加层,例如Velis Auto Brightness或Lux,则在尝试启用辅助功能服务时,用户将无法按OK按钮.
Com*_*are 85
是否有一种原生的android方法来从服务获取对当前运行的Activity的引用?
您可能不拥有"当前正在运行的活动".
我有一个在后台运行的服务,我想在事件发生时(在服务中)更新我当前的Activity.有没有一种简单的方法(就像我上面建议的那样)?
Intent向活动发送广播- 这是展示此模式的示例项目PendingIntent(例如,via createPendingResult())bindService(),并让服务调用该回调/监听器对象上的事件方法Intent到活动,具有低优先级BroadcastReceiver作为备份(Notification如果活动不在屏幕上则提高a ) - 这是一篇关于此模式的更多博客帖子Vit*_*res 18
它可以通过以下方式完成:
实现您自己的应用程序类,注册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;
}
}
Run Code Online (Sandbox Code Playgroud)在您的服务调用中getApplication(),将其强制转换为您的应用程序类名称(在本例中为App).比你可以调用app.getActiveActivity()- 这会给你一个当前可见的Activity(当没有活动可见时为null).您可以通过调用获取活动的名称activeActivity.getClass().getSimpleName()
Sam*_*Sam 13
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);
}
}
Run Code Online (Sandbox Code Playgroud)
将GET_TASKS权限添加到AndroidManifest.xml:
<!--suppress DeprecatedClassUsageInspection -->
<uses-permission android:name="android.permission.GET_TASKS" />
Run Code Online (Sandbox Code Playgroud)
Mux*_*uxa 13
我找不到我们团队满意的解决方案,所以我们推出了自己的解决方案.我们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
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
然后配置您的DI容器以返回MyApplicationfor的实例ContextProvider,例如
public class ApplicationModule extends AbstractModule {
@Provides
ContextProvider provideMainActivity() {
return MyApplication.getCurrent();
}
}
Run Code Online (Sandbox Code Playgroud)
(注意,getCurrent()上面的代码中省略了实现.它只是一个从应用程序构造函数设置的静态变量)
我正在使用它进行测试.它的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");
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
258119 次 |
| 最近记录: |