Jak uzyskać bieżący kontekst działań na pierwszym planie w systemie Android?

171

Zawsze, gdy moja transmisja jest wykonywana, chcę pokazać alert o działaniach na pierwszym planie.

Deepali
źródło
skąd chcesz uzyskać kontekst działania. Czy to będzie Twoja aktywność w aplikacji, czy inna aplikacja.
AAnkit,
to jest aktywność w aplikacji. Zrobiłem kodowanie alertów dialogowych w funkcji broadcastreceiver onreceive ().
Deepali,
aktywność w aplikacji! czy to Twoja aplikacja? i dlaczego chcesz tego, z jakiegokolwiek powodu, czy istnieje alternatywa dla tego samego
AAnkit,
Chcę wykazać czujność przy mojej aktywności na pierwszym planie. Czy jest to inny sposób na pokazanie czujności na pierwszym planie bez kontekstu.
Deepali
1
w onreceive tylko u dostać kontekst jako param, można powiedzieć context.getApplicationContext ()
AAnkit

Odpowiedzi:

39

Wiedząc, że ActivityManager zarządza Aktywnością , możemy uzyskać informacje z ActivityManager . Aktualną działającą aktywność na pierwszym planie otrzymujemy wg

ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;

UPDATE 2018/10/03
getRunningTasks () jest WYCOFANE. zobacz poniższe rozwiązania.

Ta metoda została wycofana na poziomie API 21. Począwszy od Build.VERSION_CODES.LOLLIPOP, ta metoda nie jest już dostępna dla aplikacji innych firm: wprowadzenie ostatnich zorientowanych na dokumenty oznacza, że ​​może ona wyciekać informacje o osobie do wywołującego. W celu zapewnienia kompatybilności wstecznej nadal zwróci niewielki podzbiór swoich danych: przynajmniej własne zadania wywołującego i prawdopodobnie inne zadania, takie jak dom, o których wiadomo, że nie są wrażliwe.

KAlO2
źródło
16
nie sądzę Martin, z pomocy SDK getRunningTasks "Uwaga: ta metoda jest przeznaczona tylko do debugowania i prezentowania interfejsów użytkownika do zarządzania zadaniami. Nigdy nie powinno się jej używać dla podstawowej logiki aplikacji"
ruhalde
3
Najwyraźniej obsługuje to tylko ograniczony podzbiór uruchomionych zadań w systemie Android 5 / Lollipop.
Sam
7
Dokumentacja dla ActivityManager.getRunningTasks () mówi: „Ta metoda została wycofana na poziomie API 21”.
markshep
210

( Uwaga: oficjalny interfejs API został dodany do API 14: Zobacz tę odpowiedź https://stackoverflow.com/a/29786451/119733 )

NIE UŻYWAJ POPRZEDNIEJ (waqas716) odpowiedzi.

Będziesz miał problem z wyciekiem pamięci z powodu statycznego odniesienia do działania. Aby uzyskać więcej informacji, zobacz poniższy link http://android-developers.blogspot.fr/2009/01/avoiding-memory-leaks.html

Aby tego uniknąć, należy zarządzać odniesieniami do działań. Dodaj nazwę aplikacji w pliku manifestu:

<application
    android:name=".MyApp"
    ....
 </application>

Twoja klasa aplikacji:

  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;
        }
  }

Utwórz nowe działanie:

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);
    }
}

Tak więc zamiast rozszerzać klasę Activity dla swoich działań, po prostu rozszerz MyBaseActivity. Teraz możesz pobrać swoją bieżącą aktywność z aplikacji lub kontekstu działania w następujący sposób:

Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();
gezdy
źródło
9
Możesz po prostu użyć WeakReference i osiągnąć ten sam wynik przy mniejszej ilości kodu.
Nacho Coloma
5
@Nacho Nigdy nie polecałbym używania WeakReferencesw Androidzie, GC zbiera je szybciej niż myślisz.
rekire
4
@MaximKorobov Tak, jest to możliwe, jeśli wywołasz finish () z onCreate (), jeśli używasz swojej aktywności tylko do uruchomienia innej aktywności i ją zatrzymasz. W tym scenariuszu pomija onPause () i onStoo (). Zobacz dolną notatkę: developer.android.com/training/basics/activity-lifecycle/…
Rodrigo Leitão
2
@rekire @NachoColoma Użycie WeakReferencenie jest zalecane do buforowania, to nie jest buforowanie, to znaczy mCurrentActivitybędzie mieć do niego odniesienie tylko wtedy, gdy jest żywy, więc WeakReferencenigdy nie zostaną zebrane, gdy Activityjest na wierzchu. Jednak to, co sugeruje @NachoColoma, jest błędne, ponieważ WeakReferencemoże nadal odnosić się do nie wznowionej (nie aktywnej / nie na wierzchu) aktywności, jeśli zmienna nie zostanie wyczyszczona!
TWiStErRob
14
Począwszy od poziomu 14 Android API powinno być możliwe użycie Application .ActivityLifecycleCallbacks, które byłoby bardziej centralne i nie musiałbyś dodawać żadnego kodu zarządzającego do wszystkich swoich działań. Zobacz także developer.android.com/reference/android/app/…
Filou
68

Rozszerzam odpowiedź @ gezdy.

W każdym działaniu, zamiast „rejestrować się” za Applicationpomocą ręcznego kodowania, możemy skorzystać z następującego interfejsu API od poziomu 14, aby pomóc nam osiągnąć podobny cel przy mniejszym ręcznym kodowaniu.

public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)

http://developer.android.com/reference/android/app/Application.html#registerActivityLifecycleCallbacks%28android.app.Application.ActivityLifecycleCallbacks%29

W programie Application.ActivityLifecycleCallbacksmożna uzyskać informacje o tym, co Activityjest „dołączone” lub „odłączone” od tegoApplication .

Jednak ta technika jest dostępna tylko od poziomu API 14.

Cheok Yan Cheng
źródło
1
O co chodzi ze wszystkimi innymi odpowiedziami? Oczywiście jest to API zaprojektowane do tego celu. Dziękuję, Cheok Yan Cheng
Michael Bushe
2
@MichaelBushe - w 2012 roku, kiedy napisano inne odpowiedzi, w zależności od poziomu API 14 nie można było polegać na każdym urządzeniu, biorąc pod uwagę, że API zostało wydane dopiero niedawno (październik 2011).
ToolmakerSteve
4
Znaleziono odpowiedź pokazującą, jak korzystać z tego podejścia: stackoverflow.com/a/11082332/199364 Zaletą jest to, że nie trzeba nic robić z samymi czynnościami ; cały kod znajduje się w Twojej niestandardowej klasie wywołania zwrotnego. Po prostu tworzysz klasę, która to robi implements Application.ActivityLifecycleCallbacksi dodajesz metody do zaimplementowania tego. Następnie w konstruktorze tej klasy (lub onCreate, init lub innej metodzie, która działa, gdy instancja staje się aktywna / gotowa), umieść getApplication().registerActivityLifecycleCallbacks(this);jako ostatnią linię.
ToolmakerSteve
Myślę, że twoja odpowiedź jest najlepsza
burulangtu
2
świetna odpowiedź. jedyną wadą jest to, że nadal musisz zapisać to ćwiczenie w jakimś miejscu, jeśli chcesz zapytać klasę o bieżące zajęcie. więc nadal musisz unikać wycieku pamięci i zerować odniesienie.
Raphael C
56

Aktualizacja 2 : W tym celu dodano oficjalny interfejs API, zamiast tego użyj ActivityLifecycleCallbacks .

AKTUALIZACJA:

Jak wskazał @gezdy i jestem za to wdzięczny. ustaw odniesienie na null również dla bieżącego działania, zamiast aktualizować tylko przy każdym onResume, ustaw go na null w przypadku onDestroy każdego działania, aby uniknąć problemu z wyciekiem pamięci.

Jakiś czas temu potrzebowałem tej samej funkcjonalności i oto metoda, jak to osiągnąłem. W każdej swojej działalności zastąp te metody cyklu życia.

@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);
}

Teraz w swojej klasie transmisji możesz uzyskać dostęp do bieżącej aktywności, aby pokazać jej alert.

Waqas
źródło
3
Ta odpowiedź powinna naprawdę uzyskać więcej głosów pozytywnych, proste rozwiązanie, ale potężne, gdy masz klasy, które muszą manipulować działaniami, ale same nie są działaniami.
ryvianstyron
Chodzi o statyczne odniesienie do obiektu aktywności. Możesz go stworzyć gdziekolwiek chcesz :). To nie ma znaczenia.
Waqas
Jest to odpowiednik Twojej poprzedniej odpowiedzi. Applicationjest tworzony tylko raz i nigdy nie zbiera śmieci, dokładnie tak jak zmienna statyczna.
zapl
1
Będą problemy z działaniami hierarchicznymi. Kiedy wracasz z czynności dziecka do czynności rodzica: (1) nazywana jest funkcją onPause dziecka; (2) onResume rodzica; (3) child's onDestroy ==> bieżąca aktywność będzie zerowa. Powinieneś sprawdzić, jak @gezdy w jego przykładzie w metodzie clearReferences.
Arts
4
@ waqas716 Proponuję uprościć warunek clearReferences()do (this.equals(currActivity)).
naXa
51

@lockwobr Dzięki za aktualizację

To nie działa w 100% w wersji API 16, jeśli czytasz kod na github, funkcja "currentActivityThread" została zmieniona w Kitkat, więc chcę powiedzieć, że wersja 19ish, trochę trudna do dopasowania wersji API do wydań na githubie .

Dostęp do prądu Activityjest bardzo wygodny. Czy nie byłoby miło mieć statyczną getActivitymetodę zwracającą bieżącą aktywność bez zbędnych pytań?

ActivityKlasa jest bardzo przydatna. Daje dostęp do wątku interfejsu użytkownika aplikacji, widoków, zasobów i wielu innych. Liczne metody wymagają Context, ale jak uzyskać wskaźnik? Oto kilka sposobów:

  • Śledzenie stanu aplikacji przy użyciu zastąpionych metod cyklu życia. Musisz przechowywać bieżące działanie w zmiennej statycznej i potrzebujesz dostępu do kodu wszystkich działań.
  • Śledzenie stanu aplikacji za pomocą Instrumentacji. Zadeklaruj Instrumentację w manifeście, zaimplementuj ją i użyj jej metod do śledzenia zmian aktywności. Przekazywanie wskaźnika działania do metod i klas używanych w działaniach. Wstrzyknięcie wskaźnika przy użyciu jednej z bibliotek wstrzykiwania kodu. Wszystkie te podejścia są raczej niewygodne ; na szczęście istnieje znacznie łatwiejszy sposób na zdobycie aktualnej Aktywności.
  • Wygląda na to, że system potrzebuje dostępu do wszystkich działań bez problemów wymienionych powyżej. Dlatego najprawdopodobniej istnieje sposób na uzyskanie działań przy użyciu tylko wywołań statycznych. Spędziłem dużo czasu przeszukując źródła Androida na grepcode.com i znalazłem to, czego szukałem. Jest klasa o nazwie ActivityThread. Ta klasa ma dostęp do wszystkich działań i, co jeszcze lepsze, ma statyczną metodę pobierania prądu ActivityThread. Jest tylko jeden mały problem - lista aktywności ma dostęp do pakietu.

Łatwe do rozwiązania za pomocą refleksji:

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;
}

Takiej metody można używać w dowolnym miejscu aplikacji i jest ona znacznie wygodniejsza niż wszystkie wymienione podejścia. Co więcej, wydaje się, że nie jest to tak niebezpieczne, jak się wydaje. Nie wprowadza żadnych nowych potencjalnych wycieków ani zerowych wskaźników.

Powyższy fragment kodu nie obsługuje wyjątków i naiwnie zakłada, że ​​pierwsze uruchomione działanie jest tym, którego szukamy. Możesz chcieć dodać dodatkowe kontrole.

Post na blogu

AZ_
źródło
2
w Kitkat i nowszych wersjach mActivities nie jest HashMap, ale ArrayMap, więc musisz zmienić tę linię: HashMap activity = (HashMap) activityField.get (activityThread); wyglądać tak: ArrayMap activity = (ArrayMap) activityField.get (activityThread);
Palejandro
7
@Palejandro do obsługi obu poziomów API (powyżej 18 i poniżej) powinien Mapzamiast tego używać interfejsu HashMaplub ArrayMap. Edytowałem odpowiedź @AZ_.
Yuriy Kolbasinskiy
2
To nie działa w 100% w wersji API 16 , jeśli czytasz kod na github, funkcja "currentActivityThread" została zmieniona w Kitkat, więc chcę powiedzieć, że wersja 19ish , trochę trudna do dopasowania wersji API do wydań na githubie .
lockwobr
@lockwobr dzięki, rozwiązanie zaktualizowane wraz z Tobą komentarz
:)
2
Dostęp do wewnętrznych interfejsów API przez odbicie nie jest obsługiwany i może nie działać na wszystkich urządzeniach lub w przyszłości.
Pei
9

Zrobiłem następujące w Kotlinie

  1. Utwórz klasę aplikacji
  2. Edytuj klasę aplikacji w następujący sposób

    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
        }
    }
    
     }
  3. Utwórz klasę 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
    }
    
    }
  4. możesz teraz używać go w dowolnej klasie, wywołując następujące polecenie: FTApplication.currentActivity()

Rashad.Z
źródło
5

getCurrentActivity () również znajduje się w ReactContextBaseJavaModule.
(Ponieważ to pytanie zostało zadane na początku, wiele aplikacji na Androida ma również komponent ReactNative - aplikację hybrydową).

klasa ReactContext w ReactNative ma cały zestaw logiki do obsługi mCurrentActivity, który jest zwracany w getCurrentActivity ().

Uwaga: Chciałbym, żeby metoda getCurrentActivity () została zaimplementowana w klasie aplikacji na Androida.

朱梅寧
źródło
w niektórych przypadkach ten kontekst z ReactContextBaseJavaModule jest pusty, czy wiesz dlaczego?
Moxor
4

Nie mogłem znaleźć rozwiązania, z którego nasz zespół byłby zadowolony, więc stworzyliśmy własne. Używamy ActivityLifecycleCallbacksdo śledzenia bieżącej aktywności, a następnie ujawniamy ją za pośrednictwem usługi. Więcej szczegółów tutaj: https://stackoverflow.com/a/38650587/10793

Muxa
źródło
2

Aby uzyskać zgodność wsteczną:

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;
}
Martin Zeitler
źródło
4
O ile nie ma sposobu, aby przejść z ComponentName do bieżącego wystąpienia działania, nie odpowiada to na pytanie IMO.
nasch
@nasch można zachować i uzyskać WeakReferenceuchwyt z Applicationklasy - podczas gdy ComponentNamewymagane jest określenie, czy żądane Activityznajduje się na górze listy uruchomionych zadań. A jeśli to nie w pełni odpowiada na pytanie, przyjęta odpowiedź też nie.
Martin Zeitler,
Zgadzam się, przyjęta odpowiedź również nie odpowiada w pełni na pytanie.
nasch
1
topActivityjest dostępny tylko z Androida Q
Eugen Martynov
1

Osobiście zrobiłem tak, jak powiedział „Cheok Yan Cheng”, ale użyłem „Listy”, aby mieć „backstack” do wszystkich moich działań.

Jeśli chcesz sprawdzić, które jest bieżącym działaniem, wystarczy pobrać ostatnią klasę aktywności na liście.

Utwórz aplikację, która rozszerza „Aplikacja” i wykonaj następujące czynności:

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()     }
}

}

W moim przypadku użyłem „Application.ActivityLifecycleCallbacks” do:

  • Bind / Unbind Merlin Instance (służy do uzyskiwania zdarzenia, gdy aplikacja utraci lub uzyska połączenie, na przykład gdy zamkniesz mobilną transmisję danych lub gdy ją otworzysz). Jest to przydatne po wyłączeniu akcji intencji „OnConnectivityChanged”. Więcej informacji o MERLINIE znajdziesz na: MERLIN INFO LINK

  • Zamknij moją ostatnią instancję Realm po zamknięciu aplikacji; Zainicjuję to wewnątrz BaseActivity, które jest rozszerzone ze wszystkich innych działań i które ma prywatną instancję RealmHelper. Aby uzyskać więcej informacji o REALM, zobacz: REALM INFO LINK Na przykład mam statyczną instancję "RealmHelper" wewnątrz mojej klasy "RealmHelper", która jest tworzona w mojej aplikacji "onCreate". Mam usługę synchronizacji, w której tworzę nowy „RealmHelper”, ponieważ Realm jest „powiązany z wątkami”, a instancja dziedziny nie może działać w innym wątku. Aby więc postępować zgodnie z dokumentacją dziedziny „Musisz zamknąć wszystkie otwarte instancje dziedziny, aby uniknąć wycieków zasobów systemowych”, aby to osiągnąć, użyłem „Application.ActivityLifecycleCallbacks”, jak widać powyżej.

  • Wreszcie mam odbiornik, który jest wyzwalany po zakończeniu synchronizacji aplikacji, a po zakończeniu synchronizacji wywoła metodę „IEndSyncCallback” „onEndSync”, w której sprawdzam, czy mam określoną klasę aktywności na mojej liście ActivitiesBackStack, ponieważ potrzebuję aby zaktualizować dane w widoku, jeśli synchronizacja je zaktualizowała i może być konieczne wykonanie innych operacji po synchronizacji aplikacji.

To wszystko, mam nadzieję, że to pomoże. Widzę cię :)

Z3R0
źródło
-1

Odpowiedź waqas716 jest dobra. Stworzyłem obejście dla konkretnego przypadku wymagające mniejszej ilości kodu i mniejszej obsługi.

Znalazłem specyficzne obejście, ponieważ metoda statyczna pobiera widok z działania, które podejrzewam, że znajduje się na pierwszym planie. Możesz iterować wszystkie działania i sprawdzić, czy chcesz, lub uzyskać nazwę działania z odpowiedzi Martina

ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity; 

Następnie sprawdzam, czy widok nie jest pusty i pobieram kontekst za pomocą metody 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"));
}
Gumowa kaczuszka
źródło
Szukam podobnego problemu tutaj stackoverflow.com/questions/22788289/… jak uzyskać „SuspectedActivity”? Czy to natywny interfejs API?
Stella
2
ALE z dokumentów dotyczących getRunningTasks: "Note: this method is only intended for debugging and presenting task management user interfaces. This should never be used for core logic in an application, ..." w developer.android.com/reference/android/app/ ...
ToolmakerSteve,
3
Dokumentacja dla ActivityManager.getRunningTasks () zawiera teraz informację „Ta metoda została wycofana na poziomie API 21”.
markshep
-2

Nie podoba mi się żadna inna odpowiedź. Menedżer aktywności nie jest przeznaczony do pobierania bieżącej aktywności. Super klasyfikacja i zależność od onDestroy jest również delikatna i nie jest najlepszym projektem.

Szczerze mówiąc, najlepsze, co do tej pory wymyśliłem, to po prostu utrzymanie wyliczenia w mojej aplikacji, które jest ustawiane podczas tworzenia działania.

Innym zaleceniem może być unikanie wykonywania wielu czynności, jeśli to możliwe. Można to zrobić za pomocą fragmentów lub według moich preferencji widoków niestandardowych.

stevebot
źródło
1
wyliczenie? W jaki sposób pomaga to zlokalizować bieżące wystąpienie działania pierwszego planu?
ToolmakerSteve
„Superklasyfikacja i poleganie na onDestroy jest również kruche” Jak to jest kruche?
ToolmakerSteve
-3

Dość prostym rozwiązaniem jest utworzenie pojedynczej klasy menedżera, w której można przechowywać odniesienie do jednego lub więcej działań lub czegokolwiek innego, do czego chcesz mieć dostęp w całej aplikacji.

Połączenie UberManager.getInstance().setMainActivity( activity ); do funkcji onCreate głównej aktywności.

Zadzwoń do UberManager.getInstance().getMainActivity();dowolnego miejsca w aplikacji, aby ją odzyskać. (Używam tego, aby móc używać Toast z wątku innego niż interfejs użytkownika).

Upewnij się, że dodajesz wywołanie, UberManager.getInstance().cleanup();gdy Twoja aplikacja jest niszczona.

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;
    }
}
MukRaker
źródło
Jest to uciążliwe i wymaga zmian we wszystkich działaniach. Odpowiedź przez AZ_ jest znacznie lepiej, gdyż całkowicie zlokalizowane i samodzielnym bez potrzeby innych zmian w kodzie.
markshep
-7

Spóźniłem się jakieś 3 lata, ale i tak odpowiem na wypadek, gdyby ktoś znalazł to tak, jak ja.

Rozwiązałem to, po prostu używając tego:

    if (getIntent().toString().contains("MainActivity")) {
        // Do stuff if the current activity is MainActivity
    }

Zwróć uwagę, że „getIntent (). ToString ()” zawiera kilka innych tekstów, takich jak nazwa pakietu i wszelkie filtry intencji dla Twojej aktywności. Technicznie rzecz biorąc, sprawdzamy obecny zamiar, a nie aktywność, ale wynik jest taki sam. Po prostu użyj np. Log.d ("test", getIntent (). ToString ()); jeśli chcesz zobaczyć cały tekst. To rozwiązanie jest trochę hackerskie, ale jest znacznie czystsze w kodzie, a funkcjonalność jest taka sama.

Simon Hyll
źródło