Immer wenn meine Sendung ausgeführt wird, möchte ich eine Warnung für die Vordergrundaktivität anzeigen.
Immer wenn meine Sendung ausgeführt wird, möchte ich eine Warnung für die Vordergrundaktivität anzeigen.
Antworten:
Zu wissen , dass Activitymanager verwaltet Aktivität , so können wir Informationen aus gewinnen Activitymanager . Wir bekommen den aktuellen Vordergrund, in dem Aktivität ausgeführt wird
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
UPDATE 2018/10/03
getRunningTasks () ist DEPRECATED. siehe die Lösungen unten.
Diese Methode wurde in API-Level 21 nicht mehr unterstützt. Ab Build.VERSION_CODES.LOLLIPOP steht diese Methode nicht mehr für Anwendungen von Drittanbietern zur Verfügung: Durch die Einführung dokumentenzentrierter Neuerungen können Personeninformationen an den Anrufer weitergegeben werden. Aus Gründen der Abwärtskompatibilität wird immer noch eine kleine Teilmenge seiner Daten zurückgegeben: zumindest die eigenen Aufgaben des Anrufers und möglicherweise einige andere Aufgaben wie "Home", von denen bekannt ist, dass sie nicht vertraulich sind.
( Hinweis: In API 14 wurde eine offizielle API hinzugefügt: Siehe diese Antwort https://stackoverflow.com/a/29786451/119733 )
VERWENDEN SIE KEINE VORHERIGE (waqas716) Antwort.
Aufgrund des statischen Verweises auf die Aktivität tritt ein Speicherverlustproblem auf. Weitere Informationen finden Sie unter folgendem Link: http://android-developers.blogspot.fr/2009/01/avoiding-memory-leaks.html
Um dies zu vermeiden, sollten Sie Aktivitätsreferenzen verwalten. Fügen Sie den Namen der Anwendung in die Manifestdatei ein:
<application
android:name=".MyApp"
....
</application>
Ihre Anwendungsklasse:
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;
}
}
Erstellen Sie eine neue Aktivität:
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);
}
}
Anstatt jetzt die Aktivitätsklasse für Ihre Aktivitäten zu erweitern, erweitern Sie einfach MyBaseActivity. Jetzt können Sie Ihre aktuelle Aktivität wie folgt aus der Anwendung oder dem Aktivitätskontext abrufen:
Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();
WeakReferences
in Android zu verwenden. Der GC sammelt sie schneller als Sie denken.
WeakReference
wird für das Caching nicht empfohlen. Dies ist kein Caching. Dies ist der mCurrentActivity
Wille, der nur dann einen Verweis darauf hat, wenn er lebt, sodass der WeakReference
Wille niemals gesammelt wird, solange er Activity
oben ist. Was @NachoColoma jedoch vorschlägt, ist falsch, da das WeakReference
möglicherweise immer noch auf eine nicht wieder aufgenommene Aktivität (nicht aktiv / nicht oben) verweist, wenn die Variable nicht gelöscht wird!
Application .ActivityLifecycleCallbacks
, was zentraler wäre und Sie müssten bei all Ihren Aktivitäten keinen Verwaltungscode hinzufügen. Siehe auch developer.android.com/reference/android/app/…
Ich erweitere die Antwort von @ gezdy.
Anstatt sich bei jeder Aktivität Application
bei der manuellen Codierung "registrieren" zu müssen , können wir seit Stufe 14 die folgende API verwenden, um einen ähnlichen Zweck mit weniger manueller Codierung zu erreichen.
public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
In Application.ActivityLifecycleCallbacks
können Sie bekommen, was daran Activity
"befestigt" oder "losgelöst" ist Application
.
Diese Technik ist jedoch erst seit API-Level 14 verfügbar.
implements Application.ActivityLifecycleCallbacks
, und fügen die Methoden hinzu, um dies zu implementieren. Geben Sie dann im Konstruktor dieser Klasse (oder in onCreate oder init oder einer anderen Methode, die ausgeführt wird, wenn die Instanz aktiv / bereit wird) getApplication().registerActivityLifecycleCallbacks(this);
die letzte Zeile ein.
Update 2 : Hierzu wurde eine offizielle API hinzugefügt. Verwenden Sie stattdessen ActivityLifecycleCallbacks .
AKTUALISIEREN:
Wie von @gezdy gezeigt, und ich bin dafür dankbar. Setzen Sie den Verweis für die aktuelle Aktivität ebenfalls auf null , anstatt ihn nur bei jedem onResume zu aktualisieren. Setzen Sie ihn bei onDestroy jeder Aktivität auf null, um Speicherverlustprobleme zu vermeiden.
Vor einiger Zeit brauchte ich die gleiche Funktionalität und hier ist die Methode, wie ich dies erreicht habe. Überschreiben Sie bei jeder Aktivität diese Lebenszyklusmethoden.
@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);
}
Jetzt können Sie in Ihrer Broadcast-Klasse auf die aktuelle Aktivität zugreifen, um eine Warnung anzuzeigen.
Application
wird nur einmal erstellt und niemals wie eine statische Variable gesammelt.
clearReferences()
zu (this.equals(currActivity))
.
@lockwobr Danke für das Update
Dies funktioniert nicht 100% der Zeit in API-Version 16, wenn Sie den Code auf Github lesen, wurde die Funktion "currentActivityThread" in Kitkat geändert, daher möchte ich Version 19ish sagen, eine schwer zu vergleichende API-Version mit Releases in Github .
Der Zugriff auf den Strom Activity
ist sehr praktisch. Wäre es nicht schön, eine Statik zu haben?getActivity
Methode die aktuelle Aktivität ohne unnötige Fragen zurückgibt?
Die Activity
Klasse ist sehr nützlich. Es bietet Zugriff auf den UI-Thread, die Ansichten, Ressourcen und vieles mehr der Anwendung. Zahlreiche Methoden erfordern a Context
, aber wie bekommt man den Zeiger? Hier sind einige Möglichkeiten:
ActivityThread
. Diese Klasse hat Zugriff auf alle Aktivitäten und, was noch besser ist, über eine statische Methode zum Abrufen des aktuellen Werts ActivityThread
. Es gibt nur ein kleines Problem: Die Aktivitätsliste hat Paketzugriff.Einfach durch Reflektion zu lösen:
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;
}
Eine solche Methode kann überall in der App verwendet werden und ist viel bequemer als alle genannten Ansätze. Außerdem scheint es nicht so unsicher zu sein, wie es aussieht. Es werden keine neuen potenziellen Lecks oder Nullzeiger eingeführt.
Das obige Code-Snippet enthält keine Ausnahmebehandlung und geht naiv davon aus, dass die erste ausgeführte Aktivität die ist, nach der wir suchen. Möglicherweise möchten Sie einige zusätzliche Überprüfungen hinzufügen.
Map
stattdessen die Schnittstelle HashMap
oder verwendet werden ArrayMap
. Ich habe die Antwort @AZ_ bearbeitet.
Ich habe das Folgende in Kotlin gemacht
Bearbeiten Sie die Anwendungsklasse wie folgt
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
}
}
}
Erstellen Sie die ActivityLifecycleCallbacks-Klasse
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
}
}
Sie können es jetzt in jeder Klasse verwenden, indem Sie Folgendes aufrufen: FTApplication.currentActivity()
getCurrentActivity () befindet sich auch in ReactContextBaseJavaModule.
(Da diese Frage ursprünglich gestellt wurde, haben viele Android-Apps auch eine ReactNative-Komponente - eine Hybrid-App.)
Die Klasse ReactContext in ReactNative verfügt über die gesamte Logik zur Aufrechterhaltung von mCurrentActivity, die in getCurrentActivity () zurückgegeben wird.
Hinweis: Ich wünschte, getCurrentActivity () wäre in der Android-Anwendungsklasse implementiert.
Ich konnte keine Lösung finden, mit der unser Team zufrieden wäre, also haben wir unsere eigene gerollt. Wir verwenden ActivityLifecycleCallbacks
, um die aktuellen Aktivitäten zu verfolgen und sie dann über einen Dienst verfügbar zu machen. Weitere Details finden Sie hier: https://stackoverflow.com/a/38650587/10793
Aus Gründen der Abwärtskompatibilität:
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;
}
WeakReference
Handle von einer Application
Klasse bekommen - während das ComponentName
erforderlich ist, um festzustellen, ob das Gewünschte ganz Activity
oben auf der Liste der laufenden Aufgaben steht. Und wenn dies die Frage nicht vollständig beantwortet, wird die akzeptierte Antwort auch nicht vollständig beantwortet.
topActivity
ist nur von Android Q
Persönlich habe ich getan, wie "Cheok Yan Cheng" sagte, aber ich habe eine "Liste" verwendet, um einen "Backstack" aller meiner Aktivitäten zu haben.
Wenn Sie überprüfen möchten, welche Aktivität aktuell ist, müssen Sie nur die letzte Aktivitätsklasse in der Liste abrufen.
Erstellen Sie eine Anwendung, die "Anwendung" erweitert, und führen Sie folgende Schritte aus:
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() }
}
}
In meinem Fall habe ich "Application.ActivityLifecycleCallbacks" verwendet, um:
Merlin-Instanz binden / binden (wird verwendet, um ein Ereignis abzurufen, wenn die App die Verbindung verliert oder eine Verbindung herstellt, z. B. wenn Sie mobile Daten schließen oder wenn Sie sie öffnen). Dies ist nützlich, nachdem die Absichtsaktion "OnConnectivityChanged" deaktiviert wurde. Weitere Informationen zu MERLIN finden Sie unter: MERLIN INFO LINK
Schließen Sie meine letzte Realm-Instanz, wenn die Anwendung geschlossen wird. Ich werde es in einer BaseActivity initiieren, die von allen anderen Aktivitäten erweitert wird und über eine private RealmHelper-Instanz verfügt. Weitere Informationen zu REALM finden Sie unter: REALM INFO LINK Zum Beispiel habe ich eine statische "RealmHelper" -Instanz in meiner "RealmHelper" -Klasse, die in meiner Anwendung "onCreate" instanziiert wird. Ich habe einen Synchronisationsdienst, in dem ich einen neuen "RealmHelper" erstelle, da Realm "Thread-verknüpft" ist und eine Realm-Instanz nicht in einem anderen Thread funktionieren kann. Um der Realm-Dokumentation "Sie müssen alle geöffneten Realm-Instanzen schließen, um Systemressourcenlecks zu vermeiden" zu folgen, habe ich "Application.ActivityLifecycleCallbacks" verwendet, wie Sie sehen können.
Schließlich habe ich einen Empfänger, der ausgelöst wird, wenn ich die Synchronisierung meiner Anwendung abgeschlossen habe. Wenn die Synchronisierung beendet ist, wird die Methode "IEndSyncCallback" "onEndSync" aufgerufen, in der ich nachschaue, ob ich eine bestimmte Aktivitätsklasse in meiner ActivitiesBackStack-Liste habe, weil ich sie benötige um die Daten in der Ansicht zu aktualisieren, wenn die Synchronisierung sie aktualisiert hat und ich nach der App-Synchronisierung möglicherweise andere Vorgänge ausführen muss.
Das ist alles, hoffe das ist hilfreich. Bis später :)
Die Antwort von waqas716 ist gut. Ich habe eine Problemumgehung für einen bestimmten Fall erstellt, die weniger Code und Wartung erfordert.
Ich habe eine bestimmte Problemumgehung gefunden, indem eine statische Methode eine Ansicht von der Aktivität abgerufen hat, von der ich vermute, dass sie im Vordergrund steht. Sie können alle Aktivitäten durchlaufen und prüfen, ob Sie möchten oder den Aktivitätsnamen aus Martins Antwort erhalten
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
Ich überprüfe dann, ob die Ansicht nicht null ist und erhalte den Kontext über 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"));
}
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, ..."
in developer.android.com/reference/android/app/…
Ich mag keine der anderen Antworten. Der ActivityManager ist nicht dazu gedacht, die aktuelle Aktivität abzurufen. Super Classing und je nach onDestroy ist auch fragil und nicht das beste Design.
Ehrlich gesagt ist das Beste, was ich bisher gefunden habe, nur eine Aufzählung in meiner Anwendung beizubehalten, die festgelegt wird, wenn eine Aktivität erstellt wird.
Eine andere Empfehlung könnte sein, wenn möglich nur die Verwendung mehrerer Aktivitäten zu scheuen. Dies kann entweder mit Fragmenten oder in meinen bevorzugten benutzerdefinierten Ansichten erfolgen.
Eine ziemlich einfache Lösung besteht darin, eine Singleton-Manager-Klasse zu erstellen, in der Sie einen Verweis auf eine oder mehrere Aktivitäten oder auf alles andere speichern können, auf das Sie in der gesamten App zugreifen möchten.
Anruf UberManager.getInstance().setMainActivity( activity );
onCreate der Hauptaktivität auf.
Anruf UberManager.getInstance().getMainActivity();
irgendwo in Ihrer App an, um sie abzurufen. (Ich verwende dies, um Toast von einem Nicht-UI-Thread verwenden zu können.)
Stellen Sie sicher, dass Sie einen Anruf hinzufügen, UberManager.getInstance().cleanup();
wenn Ihre App zerstört wird.
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;
}
}
Ich bin ungefähr 3 Jahre zu spät, aber ich werde es trotzdem beantworten, falls jemand dies so findet wie ich.
Ich habe das gelöst, indem ich einfach folgendes benutzt habe:
if (getIntent().toString().contains("MainActivity")) {
// Do stuff if the current activity is MainActivity
}
Beachten Sie, dass "getIntent (). ToString ()" eine Reihe anderer Texte enthält, z. B. Ihren Paketnamen und alle Absichtsfilter für Ihre Aktivität. Technisch überprüfen wir die aktuelle Absicht, nicht die Aktivität, aber das Ergebnis ist das gleiche. Verwenden Sie einfach zB Log.d ("test", getIntent (). ToString ()); wenn Sie den gesamten Text sehen möchten. Diese Lösung ist etwas hackig, aber in Ihrem Code ist sie viel sauberer und die Funktionalität ist dieselbe.