Всякий раз, когда выполняется моя трансляция, я хочу показать предупреждение о деятельности переднего плана.
Как получить текущий контекст активности переднего плана в android?
Ответ 1
Зная, что ActivityManager управляет Activity, мы можем получать информацию из ActivityManager. Мы получаем текущий передний план, запускающий Activity by
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, этот метод больше не доступен для сторонних приложений: введение центрированных на документе рецентов означает, что он может передавать информацию о человеке вызывающей стороне. Для обратной совместимости он по-прежнему будет возвращать небольшое подмножество своих данных: по крайней мере, собственные задачи вызывающего абонента и, возможно, некоторые другие задачи, например домашние, которые, как известно, не являются чувствительными.
Ответ 2
(Примечание: Официальный API был добавлен в API 14: см. этот ответ fooobar.com/questions/30151/...)
НЕ ИСПОЛЬЗУЙТЕ ПРЕДЫДУЩИЙ (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();
Ответ 3
Я расширяюсь в верхней части ответа @gezdy.
В каждой Деятельности вместо того, чтобы "зарегистрироваться" с помощью Application
с помощью ручного кодирования, мы можем использовать следующий API начиная с 14-го уровня, чтобы помочь нам достичь аналогичной цели с меньшим количеством ручного кодирования.
public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
В Application.ActivityLifecycleCallbacks
вы можете получить, какой Activity
"прикреплен" к или "отсоединен" от этого Application
.
Однако этот метод доступен только с уровня API 14.
Ответ 4
Обновление 2: Для этого добавлен официальный API, используйте взамен ActivityLifecycleCallbacks.
ОБНОВИТЬ:
Как указано @gezdy, и я благодарен за это. установите ссылку на null тоже для текущей активности, вместо обновления только для каждого onResume, установите для нее значение null для каждого Activity onDestroy, чтобы избежать проблемы утечки памяти.
Некоторое время назад мне нужна была та же функциональность, и вот метод, которым я достиг этого. В каждой вашей деятельности переопределите эти методы жизненного цикла.
@Override
protected void onResume() {
super.onResume();
appConstantsObj.setCurrentActivity(this);
}
@Override
protected void onPause() {
clearReferences();
super.onPause();
}
@Override
protected void onDestroy() {
clearReferences();
super.onDestroy();
}
private void clearReferences(){
Activity currActivity = appConstantsObj.getCurrentActivity();
if (this.equals(currActivity))
appConstantsObj.setCurrentActivity(null);
}
Теперь в вашем классе вещания вы можете получить доступ к текущей активности, чтобы показать предупреждение о ней.
Ответ 5
@lockwobr Спасибо за обновление
Это не работает в 100% случаев в API версии 16, если вы читаете код на github, функция "currentActivityThread" была изменена в Kitkat, поэтому я хочу сказать, что версия 19ish, довольно сложно сопоставить версию API с выпусками в github,
Доступ к текущей Activity
очень удобен. Разве не было бы неплохо иметь статический метод getActivity
возвращающий текущую активность без лишних вопросов?
Класс Activity
очень полезен. Он предоставляет доступ к потоку пользовательского интерфейса приложений, представлениям, ресурсам и многому другому. Многочисленные методы требуют Context
, но как получить указатель? Вот несколько способов:
- Отслеживание состояния приложений с использованием переопределенных методов жизненного цикла. Вы должны сохранить текущую активность в статической переменной, и вам нужен доступ к коду всех операций.
- Отслеживание состояния приложений с использованием Инструментов. Объявите Инструментарий в манифесте, внедрите его и используйте его методы для отслеживания изменений в Деятельности. Передача указателя Activity на методы и классы, используемые в ваших Activity. Внедрение указателя с использованием одной из библиотек внедрения кода. Все эти подходы довольно неудобны; К счастью, есть намного более простой способ получить текущую активность.
- Похоже, что системе нужен доступ ко всем действиям без проблем, упомянутых выше. Так что, скорее всего, есть способ получить Activity, используя только статические вызовы. Я потратил много времени, копаясь в источниках Android на grepcode.com, и нашел то, что искал. Существует класс с именем
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, которая искала. Возможно, вы захотите добавить некоторые дополнительные проверки.
Ответ 6
getCurrentActivity() также находится в ReactContextBaseJavaModule.
(Поскольку этот вопрос изначально был задан, у многих приложений Android также есть приложение ReactNative - гибридное приложение.)
класс ReactContext в ReactNative имеет весь набор логических функций для поддержания mCurrentActivity, который возвращается в getCurrentActivity().
Примечание. Я хочу, чтобы getCurrentActivity() реализован в классе приложений Android.
Ответ 7
Я не мог найти решение, в котором наша команда была бы счастлива, поэтому мы катались самостоятельно. Мы используем ActivityLifecycleCallbacks
, чтобы отслеживать текущую активность, а затем выставлять ее через службу. Подробнее здесь: fooobar.com/questions/30105/...
Ответ 8
Я сделал следующее в Котлине
- Создать класс приложения
-
Изменить класс приложения следующим образом
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()
Ответ 9
Лично я сделал, как сказал "Чок Ян Ченг", но использовал "Список", чтобы получить "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", чтобы:
-
Bind/Unbind Merlin Instance (используется для получения события, когда приложение теряет или получает соединение, например, когда вы закрываете мобильные данные или когда вы открываете его). Это полезно после того, как намеренное действие "OnConnectivityChanged" было отключено. Для получения дополнительной информации о MERLIN см.: MERLIN INFO LINK
-
Закрыть мой последний экземпляр области, когда приложение закрыто; Я начну его внутри BaseActivity, которое расширено от всех других действий и имеет частный экземпляр RealmHelper. Для получения дополнительной информации о REALM см.: REALM INFO LINK. Например, у меня есть статический экземпляр "RealmHelper" внутри моего класса "RealmHelper", который создается внутри моего приложения "onCreate". У меня есть служба синхронизации, в которой я создаю новый "RealmHelper", потому что Realm "связан с потоками", а экземпляр области не может работать в другом потоке. Поэтому для того, чтобы следовать документации Realm "Вам нужно закрыть все открытые экземпляры областей, чтобы избежать утечек системных ресурсов", для достижения этой цели я использовал "Application.ActivityLifecycleCallbacks", как вы можете видеть вверх.
-
Наконец, у меня есть получатель, который запускается, когда я заканчиваю синхронизацию моего приложения, затем, когда заканчивается синхронизация, он вызывает метод "IEndSyncCallback" "onEndSync", в котором я проверяю, есть ли у меня определенный класс Activity в моем Списке ActivityBackStack, потому что мне нужно выполнить некоторую операцию, если я уже прошел этот пункт в моем приложении.
Это все, надеюсь, это полезно. Увидимся :)
Ответ 10
Для обратной совместимости:
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 {
cn = am.getRunningTasks(1).get(0).topActivity;
}
Ответ 11
Ответ 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"));
}
Ответ 12
Мне не нравятся другие ответы. ActivityManager не предназначен для использования в текущей деятельности. Суперкласс и в зависимости от onDestroy также хрупкий и не лучший дизайн.
Честно говоря, лучшее, что я придумал до сих пор, - это просто сохранить перечисление в моем приложении, которое устанавливается, когда создается действие.
Другая рекомендация может заключаться в том, чтобы просто избегать использования нескольких действий, если это возможно. Это можно сделать либо с использованием фрагментов, либо в моих предпочтениях пользовательских представлений.
Ответ 13
Довольно простое решение - создать одноуровневый менеджерский класс, в котором вы можете хранить ссылку на одно или несколько Деяний или что-то еще, что вы хотите получить доступ к всему приложению.
Вызвать UberManager.getInstance().setMainActivity( activity );
в основном действии onCreate.
Вызовите UberManager.getInstance().getMainActivity();
в любом месте приложения, чтобы получить его. (Я использую это, чтобы иметь возможность использовать Toast из потока, отличного от UI.)
Убедитесь, что вы добавляете вызов 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;
}
}
Ответ 14
Мне нравится 3 года, но я все равно отвечу, если кто-то найдет это, как я.
Я решил это, просто используя это:
if (getIntent().toString().contains("MainActivity")) {
// Do stuff if the current activity is MainActivity
}
Обратите внимание, что "getIntent(). toString()" включает в себя кучу другого текста, такого как имя вашего пакета и любые фильтры намерений для вашей активности. Технически мы проверяем текущее намерение, а не активность, но результат тот же. Просто используйте, например. Log.d( "test", getIntent(). ToString()); если вы хотите увидеть весь текст. Это решение немного взломанно, но оно намного чище в вашем коде, и функциональность одинакова.