ブロードキャストが実行されるときはいつでも、フォアグラウンドアクティビティに対するアラートを表示したいと思います。
ブロードキャストが実行されるときはいつでも、フォアグラウンドアクティビティに対するアラートを表示したいと思います。
回答:
ことを知ってActivityManagerは管理活動を、私たちから情報を得ることができます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以降、このメソッドはサードパーティのアプリケーションで使用できなくなりました。ドキュメント中心の最近の機能の導入により、呼び出し元に個人情報が漏洩する可能性があります。下位互換性のために、データの小さなサブセットが返されます。少なくとも、呼び出し元のタスク、および場合によっては、機密性が低いことがわかっているhomeなどのその他のタスクです。
(注: 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();
WeakReferences
Androidで使用することをお勧めすることは決してありません。GCは、あなたが思うよりも速くそれらを収集します。
WeakReference
キャッシングにはお勧めしません。これはキャッシングではありません。つまり、mCurrentActivity
生きているときに参照するだけなのでWeakReference
、Activity
が上にある間は収集されません。ただしWeakReference
、変数がクリアされていない場合は、再開されていない(生きていない/上にない)アクティビティを参照する可能性があるため、@ NachoColomaの提案は間違っています。
Application .ActivityLifecycleCallbacks
、を使用できるようになるはずです。これはより中心的であり、すべてのアクティビティに管理コードを追加する必要はありません。developer.android.com/reference/android/app/…
@gezdyの回答の上に展開します。
すべてのアクティビティで、Application
手動コーディングで自分自身を「登録」する代わりに、レベル14以降、次のAPIを使用して、手動コーディングを減らして同様の目的を達成できます。
public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
ではApplication.ActivityLifecycleCallbacks
、これActivity
に「アタッチ」または「デタッチ」されているものを取得できますApplication
。
ただし、この手法はAPIレベル14以降でのみ使用できます。
implements Application.ActivityLifecycleCallbacks
を実装するメソッドを追加するだけです。次に、そのクラスのコンストラクター(またはインスタンスがアクティブ/準備完了になったときに実行されるonCreate、init、またはその他のメソッド)にgetApplication().registerActivityLifecycleCallbacks(this);
、最後の行として配置します。
アップデート2:これには公式APIが追加されています。代わりにActivityLifecycleCallbacksを使用してください。
更新:
@gezdyが指摘したように、私はそのことに感謝しています。すべてのonResumeを更新するのではなく、現在のアクティビティの参照もnullに設定して、メモリリークの問題を回避するために、すべてのActivityのonDestroyをnullに設定します。
しばらく前に私は同じ機能が必要でしたが、これが私がこれを達成した方法です。すべてのアクティビティで、これらのライフサイクルメソッドをオーバーライドします。
@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);
}
これで、ブロードキャストクラスで現在のアクティビティにアクセスして、アラートを表示できます。
Application
一度だけ作成され、静的変数のように正確にガベージコレクションされることはありません。
clearReferences()
し(this.equals(currActivity))
ます。
@lockwobr更新をありがとう
これはAPIバージョン16では100%動作しません。githubでコードを読んだ場合、関数「currentActivityThread」はKitkatで変更されていたため、バージョン19ishと言いたいです。 。
現在にアクセスする Activity
は非常に便利です。getActivity
不要な質問なしに現在のアクティビティを返す静的メソッドがあればいいのではないでしょうか。
Activity
クラスは非常に便利です。アプリケーションのUIスレッド、ビュー、リソースなどへのアクセスを提供します。多くのメソッドにはが必要ですContext
が、ポインタを取得するにはどうすればよいですか?ここにいくつかの方法があります:
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ポインターは導入されません。
上記のコードスニペットには例外処理がなく、単純に、最初に実行中のアクティビティが探しているものであると想定しています。追加のチェックをいくつか追加したい場合があります。
Map
インタフェース代わりにHashMap
、またはArrayMap
。@AZ_の回答を編集しました。
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クラスに実装されているといいのですが。
私たちのチームが満足できる解決策を見つけることができなかったので、私たちは自分たちで開発しました。ActivityLifecycleCallbacks
現在のアクティビティを追跡し、サービスを通じて公開するために使用します。詳細はこちら:https : //stackoverflow.com/a/38650587/10793
後方互換性のために:
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
は、Application
クラスからハンドルを保持して取得できComponentName
ますActivity
が、必要なものが実行中のタスクリストの上にあるかどうかを判断するために必要です。そして、これが質問に完全に答えない場合、受け入れられた答えもそうではありません。
topActivity
Android Qからのみ利用可能
個人的には「Cheok Yan Cheng」が言ったように行いましたが、「リスト」を使用してすべてのアクティビティの「バックスタック」を作成しました。
現在のアクティビティを確認するには、リストの最後のアクティビティクラスを取得する必要があります。
「アプリケーション」を拡張するアプリケーションを作成し、これを実行します。
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を参照してください。
アプリケーションが閉じられたら、最後のレルムインスタンスを閉じます。他のすべてのアクティビティから拡張され、プライベートRealmHelperインスタンスを持つBaseActivity内でそれを初期化します。REALMの詳細については、REALM情報リンクを参照してください。 たとえば、アプリケーション「onCreate」内でインスタンス化される「RealmHelper」クラス内に静的な「RealmHelper」インスタンスがあります。レルムは「スレッドリンク」されており、レルムインスタンスは別のスレッド内で機能できないため、新しい「RealmHelper」を作成する同期サービスがあります。したがって、Realmのドキュメント「システムリソースリークを回避するには、開いているすべてのRealmインスタンスを閉じる必要があります」に従うために、これを実現するために、「Application.ActivityLifecycleCallbacks」を使用しました。
最後に、アプリケーションの同期が完了したときにトリガーされるレシーバーがあり、同期が終了すると、「IEndSyncCallback」「onEndSync」メソッドが呼び出されます。同期によってデータが更新され、アプリの同期後に他の操作を実行する必要がある場合は、ビューのデータを更新します。
これですべてです。これがお役に立てば幸いです。またね :)
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"));
}
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, ..."
中developer.android.com/reference/android/app/...
他の答えは好きではありません。ActivityManagerは、現在のアクティビティを取得するために使用するためのものではありません。スーパークラスとonDestroyに依存するものも壊れやすく、最適なデザインではありません。
正直なところ、私がこれまでに思いついた最高のものは、アクティビティが作成されたときに設定されるアプリケーションの列挙型を維持することです。
別の推奨事項は、可能であれば、複数のアクティビティを使用しないことです。これは、フラグメントを使用するか、私の好みのカスタムビューで行うことができます。
かなり単純な解決策は、シングルトンマネージャークラスを作成することです。このクラスには、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;
}
}
私は3年遅れのようですが、誰かが私のようにこれを見つけた場合に備えて、とにかく答えます。
私はこれを単に使用することでこれを解決しました:
if (getIntent().toString().contains("MainActivity")) {
// Do stuff if the current activity is MainActivity
}
「getIntent()。toString()」には、パッケージ名やアクティビティのインテントフィルターなど、他のテキストが多数含まれていることに注意してください。技術的には、アクティビティではなく現在のインテントをチェックしていますが、結果は同じです。たとえば、Log.d( "test"、getIntent()。toString());を使用するだけです。すべてのテキストを表示したい場合。この解決策は少しハックですが、コードははるかにクリーンで、機能は同じです。