195

ブロードキャストが実行されるたびに、フォアグラウンド アクティビティにアラートを表示したいと考えています。

4

15 に答える 15

223

(注: 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();
于 2012-12-21T17:32:06.620 に答える
70

アップデート3:このために追加された公式APIがあります。代わりにActivityLifecycleCallbacksを使用してください。

于 2012-07-10T10:50:37.340 に答える
53

@lockwobr更新ありがとう

これは、api バージョン 16 では 100% の時間は機能しません。github でコードを読むと、関数「currentActivityThread」が Kitkat で変更されたので、バージョン 19ish と言いたいのですが、API バージョンを github のリリースに一致させるのは難しいです.

現在にアクセスできることActivityは非常に便利です。getActivity不必要な質問なしで現在のアクティビティを返す静的メソッドがあればいいと思いませんか?

Activityクラスは非常に便利です。アプリケーションの UI スレッド、ビュー、リソースなどへのアクセスを提供します。多くのメソッドには が必要ですContextが、ポインタを取得するにはどうすればよいでしょうか? 以下にいくつかの方法を示します。

  • オーバーライドされたライフサイクル メソッドを使用してアプリケーションの状態を追跡します。現在のアクティビティを静的変数に保存する必要があり、すべてのアクティビティのコードにアクセスする必要があります。
  • インストルメンテーションを使用してアプリケーションの状態を追跡します。マニフェストでインストルメンテーションを宣言して実装し、そのメソッドを使用してアクティビティの変更を追跡します。アクティビティで使用されるメソッドとクラスへのアクティビティ ポインターを渡します。コード挿入ライブラリの 1 つを使用してポインターを挿入します。これらのアプローチはすべてかなり不便です。幸いなことに、現在のアクティビティを取得するはるかに簡単な方法があります。
  • システムは、上記の問題なしですべてのアクティビティにアクセスする必要があるようです。したがって、ほとんどの場合、静的呼び出しのみを使用してアクティビティを取得する方法があります。grepcode.com で多くの時間をかけて Android のソースを調べたところ、探していたものが見つかりました。というクラスがありActivityThreadます。このクラスはすべてのアクティビティにアクセスでき、さらに良いことに、現在の を取得するための静的メソッドがありますActivityThread。ちょっとした問題が 1 つだけあります。アクティビティ リストにはパッケージ アクセスがあります。

リフレクションを使用して簡単に解決できます。

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

このような方法は、アプリ内のどこでも使用でき、前述のすべての方法よりもはるかに便利です。さらに、見た目ほど危険ではないようです。新しい潜在的なリークや null ポインターは導入されません。

上記のコード スニペットには例外処理がなく、単純に、最初に実行されているアクティビティが探しているものであると想定しています。追加のチェックを追加することもできます。

ブログ投稿

于 2015-02-10T03:06:23.130 に答える
41

ActivityManagerがActivityを管理することを知っているので、 ActivityManagerから情報を取得できます。現在フォアグラウンドで実行中のアクティビティを取得します

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

UPDATE 2018/10/03
getRunningTasks () は非推奨です。以下の解決策を参照してください。

このメソッドは API レベル 21 で非推奨になりました。Build.VERSION_CODES.LOLLIPOP の時点で、このメソッドはサード パーティのアプリケーションでは使用できなくなりました。ドキュメント中心の最近の機能の導入により、呼び出し元に個人情報が漏洩する可能性があります。後方互換性のために、データの小さなサブセットを返します: 少なくとも呼び出し元自身のタスク、および場合によっては機密ではないことが知られているホームなどの他のタスクです。

于 2012-09-08T05:02:30.400 に答える
4

私たちのチームが満足できる解決策を見つけることができなかったので、独自の解決策を考え出しました。ActivityLifecycleCallbacks現在のアクティビティを追跡し、サービスを通じて公開するために使用します。詳細はこちら: https://stackoverflow.com/a/38650587/10793

于 2016-07-29T04:52:59.213 に答える
-1

waqas716 さんの回答は良いです。少ないコードとメンテナンスを必要とする特定のケースの回避策を作成しました。

フォアグラウンドにあると思われるアクティビティから静的メソッドにビューをフェッチさせることで、特定の回避策を見つけました。すべてのアクティビティを反復して、マーティンの回答からアクティビティ名を希望または取得するかどうかを確認できます

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

次に、ビューが null でないかどうかを確認し、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"));
}
于 2012-10-31T09:24:02.690 に答える
-3

かなり単純な解決策は、シングルトン マネージャー クラスを作成することです。このクラスには、1 つ以上のアクティビティへの参照、またはアプリ全体でアクセスしたいものすべてを格納できます。

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;
    }
}
于 2016-06-10T17:09:25.283 に答える
-7

私は3年遅れていますが、誰かが私のようにこれを見つけた場合に備えて、とにかく答えます.

これを使用するだけでこれを解決しました:

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

「getIntent().toString()」には、パッケージ名やアクティビティのインテント フィルターなど、他のテキストが多数含まれていることに注意してください。技術的には、アクティビティではなく現在のインテントをチェックしていますが、結果は同じです。たとえば、Log.d("test", getIntent().toString()); を使用してください。すべてのテキストを見たい場合。この解決策は少しハックですが、コード内でよりクリーンになり、機能は同じです。

于 2016-05-03T10:40:51.540 に答える