每当我的广播被执行时,我想对前台活动显示警报。
15 回答
(注: API 14 中添加了官方 API:请参阅此答案https://stackoverflow.com/a/29786451/119733)
不要使用以前的(waqas716)答案。
由于对活动的静态引用,您将遇到内存泄漏问题。有关更多详细信息,请参阅以下链接http://android-developers.blogspot.fr/2009/01/avoiding-memory-leaks.html
为避免这种情况,您应该管理活动引用。在清单文件中添加应用程序的名称:
<application
android:name=".MyApp"
....
</application>
您的应用程序类:
public class MyApp extends Application {
public void onCreate() {
super.onCreate();
}
private Activity mCurrentActivity = null;
public Activity getCurrentActivity(){
return mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity){
this.mCurrentActivity = mCurrentActivity;
}
}
创建一个新活动:
public class MyBaseActivity extends Activity {
protected MyApp mMyApp;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMyApp = (MyApp)this.getApplicationContext();
}
protected void onResume() {
super.onResume();
mMyApp.setCurrentActivity(this);
}
protected void onPause() {
clearReferences();
super.onPause();
}
protected void onDestroy() {
clearReferences();
super.onDestroy();
}
private void clearReferences(){
Activity currActivity = mMyApp.getCurrentActivity();
if (this.equals(currActivity))
mMyApp.setCurrentActivity(null);
}
}
因此,现在不要为您的活动扩展 Activity 类,只需扩展 MyBaseActivity。现在,您可以像这样从应用程序或活动上下文中获取当前活动:
Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();
我扩展了@gezdy 的答案。
Application
在每个活动中,我们可以使用从级别 14 开始的以下 API ,而不是必须通过手动编码“注册”自身,以帮助我们以更少的手动编码实现类似的目的。
public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
在Application.ActivityLifecycleCallbacks
中,您可以获得哪个Activity
“附加”到或“分离”到 this Application
。
但是,此技术仅从 API 级别 14 开始可用。
更新 3:为此添加了一个官方 api,请改用ActivityLifecycleCallbacks。
@lockwobr感谢您的更新
这在 api 版本 16 中 100% 都不起作用,如果您阅读 github 上的代码,Kitkat 中的“currentActivityThread”函数发生了变化,所以我想说的是 19 版本,很难将 api 版本与 github 中的版本相匹配.
访问电流Activity
非常方便。getActivity
让一个静态方法返回当前 Activity 而没有不必要的问题不是很好吗?
Activity
课堂非常有用。它允许访问应用程序的 UI 线程、视图、资源等等。许多方法都需要一个Context
,但是如何获取指针呢?这里有一些方法:
- 使用覆盖的生命周期方法跟踪应用程序的状态。您必须将当前活动存储在一个静态变量中,并且您需要访问所有活动的代码。
- 使用 Instrumentation 跟踪应用程序的状态。在清单中声明 Instrumentation,实现它并使用它的方法来跟踪 Activity 的变化。将活动指针传递给活动中使用的方法和类。使用代码注入库之一注入指针。所有这些方法都相当不方便;幸运的是,有一种更简单的方法可以获取当前的 Activity。
- 似乎系统需要访问所有活动而没有上述问题。因此,很可能有一种方法可以仅使用静态调用来获取活动。我花了很多时间在 grepcode.com 上挖掘 Android 资源,并找到了我想要的东西。有一个类叫
ActivityThread
. 这个类可以访问所有的活动,而且更好的是,它有一个静态方法来获取当前的ActivityThread
. 只有一个小问题——活动列表具有包访问权限。
使用反射很容易解决:
public static Activity getActivity() {
Class activityThreadClass = Class.forName("android.app.ActivityThread");
Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null);
Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
activitiesField.setAccessible(true);
Map<Object, Object> activities = (Map<Object, Object>) activitiesField.get(activityThread);
if (activities == null)
return null;
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);
Activity activity = (Activity) activityField.get(activityRecord);
return activity;
}
}
return null;
}
这种方法可以在应用程序的任何地方使用,它比所有提到的方法都方便得多。此外,它似乎并不像看起来那么不安全。它不会引入任何新的潜在泄漏或空指针。
上面的代码片段缺少异常处理,并且天真地假设第一个运行的 Activity 就是我们正在寻找的那个。您可能想要添加一些额外的检查。
知道ActivityManager管理Activity,所以我们可以从ActivityManager获取信息。我们通过以下方式获取当前前台运行的Activity
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
更新 2018/10/03
getRunningTasks () 已弃用。请参阅下面的解决方案。
此方法在 API 级别 21 中已弃用。从 Build.VERSION_CODES.LOLLIPOP 开始,此方法不再可用于第三方应用程序:引入以文档为中心的最新消息意味着它可以将人员信息泄露给调用者。为了向后兼容,它仍然会返回其数据的一小部分:至少是调用者自己的任务,可能还有其他一些已知不敏感的任务,例如 home。
我在 Kotlin 中做了以下事情
- 创建应用程序类
编辑应用程序类如下
class FTApplication: MultiDexApplication() { override fun attachBaseContext(base: Context?) { super.attachBaseContext(base) MultiDex.install(this) } init { instance = this } val mFTActivityLifecycleCallbacks = FTActivityLifecycleCallbacks() override fun onCreate() { super.onCreate() registerActivityLifecycleCallbacks(mFTActivityLifecycleCallbacks) } companion object { private var instance: FTApplication? = null fun currentActivity(): Activity? { return instance!!.mFTActivityLifecycleCallbacks.currentActivity } } }
创建 ActivityLifecycleCallbacks 类
class FTActivityLifecycleCallbacks: Application.ActivityLifecycleCallbacks { var currentActivity: Activity? = null override fun onActivityPaused(activity: Activity?) { currentActivity = activity } override fun onActivityResumed(activity: Activity?) { currentActivity = activity } override fun onActivityStarted(activity: Activity?) { currentActivity = activity } override fun onActivityDestroyed(activity: Activity?) { } override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) { } override fun onActivityStopped(activity: Activity?) { } override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) { currentActivity = activity } }
您现在可以通过调用以下命令在任何类中使用它:
FTApplication.currentActivity()
getCurrentActivity() 也在 ReactContextBaseJavaModule 中。
(由于最初提出这个问题,许多 Android 应用程序也有 ReactNative 组件 - 混合应用程序。)
ReactNative 中的 ReactContext 类具有维护在 getCurrentActivity() 中返回的 mCurrentActivity 的一整套逻辑。
注意:我希望 getCurrentActivity() 在 Android Application 类中实现。
为了向后兼容:
ComponentName cn;
ActivityManager am = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
cn = am.getAppTasks().get(0).getTaskInfo().topActivity;
} else {
//noinspection deprecation
cn = am.getRunningTasks(1).get(0).topActivity;
}
我找不到我们的团队会满意的解决方案,所以我们推出了自己的解决方案。我们ActivityLifecycleCallbacks
用来跟踪当前活动,然后通过服务公开它。更多细节在这里:https ://stackoverflow.com/a/38650587/10793
我个人按照“卓仁诚”所说的做了,但我用一个“列表”来对我所有的活动进行“Backstack”。
如果您想检查当前活动是哪个,您只需要获取列表中的最后一个活动类。
创建一个扩展“应用程序”的应用程序并执行以下操作:
public class MyApplication extends Application implements Application.ActivityLifecycleCallbacks,
EndSyncReceiver.IEndSyncCallback {
private List<Class> mActivitiesBackStack;
private EndSyncReceiver mReceiver;
private Merlin mMerlin;
private boolean isMerlinBound;
private boolean isReceiverRegistered;
@Override
public void onCreate() {
super.onCreate();
[....]
RealmHelper.initInstance();
initMyMerlin();
bindMerlin();
initEndSyncReceiver();
mActivitiesBackStack = new ArrayList<>();
}
/* START Override ActivityLifecycleCallbacks Methods */
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
mActivitiesBackStack.add(activity.getClass());
}
@Override
public void onActivityStarted(Activity activity) {
if(!isMerlinBound){
bindMerlin();
}
if(!isReceiverRegistered){
registerEndSyncReceiver();
}
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
if(!AppUtils.isAppOnForeground(this)){
if(isMerlinBound) {
unbindMerlin();
}
if(isReceiverRegistered){
unregisterReceiver(mReceiver);
}
if(RealmHelper.getInstance() != null){
RealmHelper.getInstance().close();
RealmHelper.getInstance().logRealmInstanceCount("AppInBackground");
RealmHelper.setMyInstance(null);
}
}
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
if(mActivitiesBackStack.contains(activity.getClass())){
mActivitiesBackStack.remove(activity.getClass());
}
}
/* END Override ActivityLifecycleCallbacks Methods */
/* START Override IEndSyncCallback Methods */
@Override
public void onEndSync(Intent intent) {
Constants.SyncType syncType = null;
if(intent.hasExtra(Constants.INTENT_DATA_SYNC_TYPE)){
syncType = (Constants.SyncType) intent.getSerializableExtra(Constants.INTENT_DATA_SYNC_TYPE);
}
if(syncType != null){
checkSyncType(syncType);
}
}
/* END IEndSyncCallback Methods */
private void checkSyncType(Constants.SyncType){
[...]
if( mActivitiesBackStack.contains(ActivityClass.class) ){
doOperation() }
}
}
就我而言,我使用“Application.ActivityLifecycleCallbacks”来:
绑定/取消绑定 Merlin 实例(用于在应用丢失或连接时获取事件,例如当您关闭移动数据或打开它时)。在禁用“OnConnectivityChanged”意图操作后它很有用。有关 MERLIN 的更多信息,请参阅:MERLIN INFO LINK
关闭应用程序时关闭我的最后一个 Realm 实例;我将在 BaseActivity 中对其进行初始化,该 BaseActivity 是从所有其他活动扩展而来的,并且具有私有 RealmHelper 实例。有关 REALM 的更多信息,请参阅:REALM INFO LINK 例如,我的“RealmHelper”类中有一个静态“RealmHelper”实例,该实例在我的应用程序“onCreate”中实例化。我有一个同步服务,我在其中创建了新的“RealmHelper”,因为 Realm 是“线程链接的”,并且 Realm 实例不能在不同的线程中工作。因此,为了遵循领域文档“您需要关闭所有打开的领域实例以避免系统资源泄漏”,为了完成这件事,我使用了“Application.ActivityLifecycleCallbacks”,如您所见。
最后我有一个接收器,当我完成同步我的应用程序时会触发它,然后当同步结束时,它将调用“IEndSyncCallback”“onEndSync”方法,在该方法中我查看我的 ActivityBackStack 列表中是否有特定的 Activity 类,因为我需要如果同步更新了视图上的数据,我可能需要在应用同步后执行其他操作。
就是这样,希望这会有所帮助。再见 :)
您可以使用此类进行灵活的生命周期处理
用法:
//Initialization
val lifeCycleHandler = ActivityLifeCycleHandler<Activity>()
//Detect only a specific type of activities
val lifeCycleHandler = ActivityLifeCycleHandler<MainActivity>()
//Get current activity
val instance = lifeCycleHandler.currentReference
//Get current activity state
val state = lifeCycleHandler.currentState
//Use listeners
lifeCycleHandler.addStateChangeListener { newState ->
//TODO: handle new state
}
lifeCycleHandler.addSpecificStateChangeListener(ActivityLifeCycleHandler.ActivityState.STARTED) {
//TODO: handle new state
}
//Removable listeners
val listener = { newState: Int ->
}
lifeCycleHandler.addStateChangeListener(listener)
lifeCycleHandler.removeStateChageListener(listener)
//Start listening
App.app.registerActivityLifecycleCallbacks(lifeCycleHandler)
//Stop listening
lifeCycleHandler.releaseListeners()
App.app.unregisterActivityLifecycleCallbacks(lifeCycleHandler)
waqas716的回答很好。我为需要更少代码和维护的特定案例创建了一种解决方法。
通过让静态方法从我怀疑处于前台的活动中获取视图,我找到了一个特定的解决方法。您可以遍历所有活动并检查您是否愿意或从马丁的答案中获取活动名称
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
然后我检查视图是否不为空并通过 getContext() 获取上下文。
View v = SuspectedActivity.get_view();
if(v != null)
{
// an example for using this context for something not
// permissible in global application context.
v.getContext().startActivity(new Intent("rubberduck.com.activities.SomeOtherActivity"));
}
我不喜欢任何其他答案。ActivityManager 并不意味着用于获取当前活动。超级分类和依赖于 onDestroy 也是脆弱的,不是最好的设计。
老实说,到目前为止我想出的最好的方法就是在我的应用程序中维护一个枚举,它在创建活动时设置。
另一个建议可能是尽可能避免使用多项活动。这可以通过使用片段或在我的偏好自定义视图中完成。
一个相当简单的解决方案是创建一个单例管理器类,您可以在其中存储对一个或多个活动的引用,或者您希望在整个应用程序中访问的任何其他内容。
调用UberManager.getInstance().setMainActivity( activity );
主活动的 onCreate。
在您的应用程序中的任何位置调用UberManager.getInstance().getMainActivity();
以检索它。(我正在使用它来使用非 UI 线程中的 Toast。)
确保UberManager.getInstance().cleanup();
在您的应用程序被销毁时添加调用。
import android.app.Activity;
public class UberManager
{
private static UberManager instance = new UberManager();
private Activity mainActivity = null;
private UberManager()
{
}
public static UberManager getInstance()
{
return instance;
}
public void setMainActivity( Activity mainActivity )
{
this.mainActivity = mainActivity;
}
public Activity getMainActivity()
{
return mainActivity;
}
public void cleanup()
{
mainActivity = null;
}
}
我迟到了 3 年,但无论如何我都会回答,以防有人像我一样发现这个问题。
我通过简单地使用这个解决了这个问题:
if (getIntent().toString().contains("MainActivity")) {
// Do stuff if the current activity is MainActivity
}
请注意,“getIntent().toString()”包括一堆其他文本,例如您的包名称和您的活动的任何意图过滤器。从技术上讲,我们正在检查当前的意图,而不是活动,但结果是相同的。只需使用例如 Log.d("test", getIntent().toString()); 如果您想查看所有文本。这个解决方案有点老套,但它在你的代码中更干净,功能也是一样的。