Yayınım yürütüldüğünde ön plan etkinliğine karşı uyarı göstermek istiyorum.
Yayınım yürütüldüğünde ön plan etkinliğine karşı uyarı göstermek istiyorum.
Yanıtlar:
Bilerek ActivityManager yöneten Aktivite , bu yüzden bilgi kazanabilir ActivityManager . Şu anki ön planın çalıştığını görebiliyoruz
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
GÜNCELLEME 2018/10/03
getRunningTasks () DEPRECATED. aşağıdaki çözümlere bakın.
Bu yöntem API düzeyi 21'de kullanımdan kaldırılmıştır. Build.VERSION_CODES.LOLLIPOP'tan itibaren, bu yöntem artık üçüncü taraf uygulamaları tarafından kullanılamamaktadır: belge merkezli sonrakların girilmesi, kişi bilgilerini arayan kişiye sızdırabileceği anlamına gelir. Geriye dönük uyumluluk için, yine de verilerinin küçük bir alt kümesini döndürür: en azından arayanın kendi görevleri ve muhtemelen ev gibi hassas olmadığı bilinen diğer bazı görevler.
( Not: API 14'te resmi bir API eklendi: Bu yanıta bakın https://stackoverflow.com/a/29786451/119733 )
ÖNCEKİ (waqas716) yanıtı KULLANMAYIN.
Etkinliğe statik başvuru nedeniyle bellek sızıntısı sorunu yaşarsınız. Daha fazla ayrıntı için aşağıdaki bağlantıya bakın http://android-developers.blogspot.fr/2009/01/avoiding-memory-leaks.html
Bundan kaçınmak için aktivite referanslarını yönetmelisiniz. Manifest dosyasına uygulamanın adını ekleyin:
<application
android:name=".MyApp"
....
</application>
Uygulama sınıfınız:
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;
}
}
Yeni bir Etkinlik oluşturun:
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);
}
}
Bu nedenle, artık faaliyetleriniz için Activity sınıfını genişletmek yerine, MyBaseActivity'yi uzatın. Artık geçerli etkinliğinizi uygulama veya Etkinlik bağlamından şu şekilde alabilirsiniz:
Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();
WeakReferences
GC kullanmak düşündüğünüzden daha hızlı toplar Android kullanmak için tavsiye etmem .
WeakReference
için kullanılması önerilmez, bu önbellekleme değildir, bu mCurrentActivity
sadece hayatta olduğunda ona bir referans olacaktır, böylece üstte WeakReference
iken asla toplanmayacaktır Activity
. Ancak @NachoColoma'nın önerdiği yanlıştır, çünkü WeakReference
değişken temizlenmezse yine de devam etmeyen (canlı değil / üstte değil) bir aktiviteye başvurabilir!
Application .ActivityLifecycleCallbacks
daha merkezi olacak ve tüm etkinliklerinize herhangi bir yönetim kodu eklemek zorunda kalmayacaksınız. Ayrıca bkz. Developer.android.com/reference/android/app/…
@ Gezdy'nin cevabının en üstünde yer alıyorum.
Her Faaliyette, Application
manuel kodlama ile kendini "kayıt altına almak" yerine, daha az manuel kodlama ile benzer bir amaca ulaşmamıza yardımcı olmak için seviye 14'ten bu yana aşağıdaki API'yı kullanabiliriz.
public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
İçinde Application.ActivityLifecycleCallbacks
, hangisinin buna Activity
"bağlı" veya "ayrılmış" olduğunu elde edebilirsiniz Application
.
Bununla birlikte, bu teknik yalnızca API seviye 14'ten beri mevcuttur.
implements Application.ActivityLifecycleCallbacks
ve bunu uygulamak için yöntemler ekleyin. Daha sonra bu sınıfın yapıcısı (veya örnek etkin / hazır olduğunda çalışan onCreate veya init veya başka bir yöntem) getApplication().registerActivityLifecycleCallbacks(this);
son satır olarak koyulur .
Güncelleme 2 : Bunun için resmi bir API eklendi, lütfen bunun yerine ActivityLifecycleCallbacks kullanın.
GÜNCELLEME:
@Gezdy'nin işaret ettiği gibi, bunun için minnettarım. referansı null değerine de ayarlasadece her onResume cihazında güncelleme yapmak yerine mevcut etkinlik için de null değerine ayarlayın bellek sızıntısı sorununu önlemek için her Aktivitenin onDestroy öğesinde null değerine ayarlayın.
Bir süre önce aynı işlevselliğe ihtiyacım vardı ve işte bunu nasıl başardığım yöntemi. Her etkinliğinizde bu yaşam döngüsü yöntemlerini geçersiz kılar.
@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);
}
Artık yayın sınıfınızda, üzerinde etkinlik göstermek için geçerli etkinliğe erişebilirsiniz.
Application
yalnızca bir kez oluşturulur ve hiçbir zaman tam olarak statik bir değişken gibi toplanmaz.
clearReferences()
için (this.equals(currActivity))
.
@lockwobr Güncelleme için teşekkürler
Github'daki kodu okursanız, api sürüm 16'daki zamanın% 100'ü çalışmaz, "currentActivityThread" fonksiyonu Kitkat'te değişti, bu yüzden 19ish sürümünü söylemek istiyorum, api sürümünü github'daki sürümlerle eşleştirmek biraz zor .
Akıma erişime sahip olmak Activity
çok kullanışlıdır. Statik olması güzel olmaz mıydıgetActivity
Mevcut Etkinliği gereksiz bir soruyla döndüren yöntemin ?
Activity
Sınıf çok yararlıdır. Uygulamanın kullanıcı arayüzü iş parçacığına, görünümlerine, kaynaklarına ve çok daha fazlasına erişim sağlar. Birçok yöntem a gerektirir Context
, ancak işaretçiyi nasıl edinebilirim? İşte bazı yollar:
ActivityThread
. Bu sınıfın tüm Etkinliklere erişimi vardır ve daha da iyisi, akımı elde etmek için statik bir yöntemi vardır ActivityThread
. Yalnızca küçük bir sorun var - Etkinlik listesinde paket erişimi var.Yansıma kullanarak çözmek kolay:
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;
}
Böyle bir yöntem uygulamanın herhangi bir yerinde kullanılabilir ve bahsedilen tüm yaklaşımlardan çok daha uygundur. Dahası, göründüğü kadar güvenli değil gibi görünüyor. Herhangi bir yeni potansiyel sızıntı veya boş gösterici getirmez.
Yukarıdaki kod snippet'inde istisna yönetimi yoktur ve ilk çalışan Etkinliğin aradığımız faaliyet olduğunu saf bir şekilde varsayar. Bazı ek denetimler eklemek isteyebilirsiniz.
Map
bunun yerine arayüz kullanmalıdır . @AZ_ yanıtı düzenledim. HashMap
ArrayMap
Kotlin'de aşağıdakileri yaptım
Uygulama Sınıfını Aşağıdaki gibi Düzenleyin
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 sınıfını oluşturma
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
}
}
artık aşağıdakileri arayarak herhangi bir sınıfta kullanabilirsiniz: FTApplication.currentActivity()
getCurrentActivity (), ReactContextBaseJavaModule öğesinde de bulunur.
(Bu soru başlangıçta sorulduğundan, birçok Android uygulamasının da ReactNative bileşeni - hibrit uygulaması vardır.)
ReactNative içindeki class ReactContext, getCurrentActivity () içinde döndürülen mCurrentActivity'yi korumak için tüm mantık kümesine sahiptir.
Not: Keşke getCurrentActivity () Android Uygulama sınıfında uygulanır.
Ekibimizin mutlu olacağı bir çözüm bulamadık, bu yüzden kendi ekibimizi yuvarladık. Biz kullanmak ActivityLifecycleCallbacks
mevcut etkinlik izlemek ve daha sonra bir hizmet aracılığıyla mazur bırakmayın. Daha fazla ayrıntı burada: https://stackoverflow.com/a/38650587/10793
Geriye dönük uyumluluk için:
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
bir Application
sınıf tutabilir ve bir tanıtıcı elde edebilirsiniz - ComponentName
istenen Activity
ise çalışan görevler listesinin üstünde olup olmadığını belirlemek için gereklidir . Ve eğer bu soruya tam olarak cevap vermezse, kabul edilen cevap da cevap vermez.
topActivity
sadece Android Q'dan kullanılabilir
Şahsen "Cheok Yan Cheng" dediği gibi yaptım, ama tüm faaliyetlerimin bir "Backstack" için bir "Liste" kullandım.
Geçerli Etkinliğin Hangisi olduğunu kontrol etmek istiyorsanız, listedeki son etkinlik sınıfını almanız yeterlidir.
"Uygulama" yı genişleten bir uygulama oluşturun ve bunu yapın:
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() }
}
}
Benim durumumda "Application.ActivityLifecycleCallbacks" kullandım:
Bağlama / Açma Merlin Örneği (uygulama mobil bağlantıyı kapattığınızda veya açtığınızda uygulama kaybedildiğinde veya bağlantı kurulduğunda olay almak için kullanılır). "OnConnectivityChanged" niyet eylemi devre dışı bırakıldıktan sonra yararlıdır. MERLIN hakkında daha fazla bilgi için bkz: MERLIN INFO LINK
Uygulama kapandığında son Bölge örneğimi kapat; Diğer tüm etkinliklerden genişletilmiş ve özel bir RealmHelper Eşgörünümüne sahip olan bir BaseActivity içinde başlatacağım. REALM hakkında daha fazla bilgi için bakınız: REALM INFO LINK Örneğin, "onCreate" uygulamamın içinde başlatılan "RealmHelper" sınıfımın içinde statik bir "RealmHelper" örneğim var. Ben yeni "RealmHelper" oluşturduğum bir senkronizasyon hizmetim var, çünkü Realm "Thread-Linked" ve bir Realm Örneği farklı bir Thread içinde çalışamıyor. Bu yüzden "Sistem Kaynakları Sızıntılarını önlemek için Tüm Açılmış Bölge Örneklerini Kapatmanız Gerekiyor" Bölgesel Belgeleri takip etmek için, bu şeyi gerçekleştirmek için gördüğünüz gibi "Application.ActivityLifecycleCallbacks" kullandım.
Sonunda benim uygulama senkronize etmek için bitirdiğinde tetiklenen bir alıcı var, sonra senkronizasyon sona erdiğim zaman "IEndSyncCallback" "onEndSync" yöntemini arayacağım, çünkü benim ActivitiesBackStack Listemde belirli bir Aktivite Sınıfı varsa bakacağım senkronizasyon güncellendiyse görünümdeki verileri güncellemek için ve uygulama senkronizasyonundan sonra başka işlemler yapmam gerekebilir.
Hepsi bu, umarım bu yardımcı olur. Görüşürüz :)
Waqas716'nın cevabı iyidir. Daha az kod ve bakım gerektiren belirli bir durum için bir geçici çözüm oluşturdum.
Statik bir yöntem ön planda olduğundan şüphelendiğim bir etkinlik bir görünüm getirerek etrafında özel bir çalışma buldum. Tüm aktiviteleri tekrarlayabilir ve martin cevabından aktivite adını isteyip istemediğinizi kontrol edebilirsiniz.
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
Sonra görünüm null olmadığını kontrol edin ve getContext () üzerinden bağlam olsun.
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, ..."
ama geliştirici.android.com
Diğer cevaplardan hiç hoşlanmıyorum. ActivityManager'ın mevcut etkinliği almak için kullanılması amaçlanmamıştır. Süper sınıflandırma ve onDestroy'a bağlı olarak en iyi tasarım değil kırılgandır.
Dürüst olmak gerekirse, şimdiye kadar bulduğum en iyi şey, Uygulamamda bir etkinlik oluşturulduğunda ayarlanan bir numaralandırmayı korumaktır.
Başka bir öneri, mümkünse birden fazla etkinlik kullanmaktan kaçınmak olabilir. Bu, parçaların kullanılmasıyla veya tercih edilen özel görünümlerimde yapılabilir.
Oldukça basit bir çözüm, bir veya daha fazla Faaliyete veya uygulama boyunca erişmek istediğiniz herhangi bir şeye referans depolayabileceğiniz tekli bir yönetici sınıfı oluşturmaktır.
Aramak UberManager.getInstance().setMainActivity( activity );
Ana etkinliğin onCreate'sini .
Aramak UberManager.getInstance().getMainActivity();
için uygulamanızın herhangi bir yerini . (UI olmayan bir iş parçacığından Tost kullanabilmek için bunu kullanıyorum.)
UberManager.getInstance().cleanup();
Uygulamanız yok edilirken bir arama eklediğinizden emin olun .
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 yıl geç kaldım ama birisinin bunu benim yaptığım gibi bulması durumunda yine de cevaplayacağım.
Bunu sadece bunu kullanarak çözdüm:
if (getIntent().toString().contains("MainActivity")) {
// Do stuff if the current activity is MainActivity
}
"GetIntent (). ToString ()" öğesinin paket adınız ve etkinliğiniz için herhangi bir niyet filtresi gibi bir grup metni içerdiğini unutmayın. Teknik olarak şu andaki amacı kontrol ediyoruz, faaliyeti değil, sonuç aynı. Sadece Log.d ("test", getIntent (). ToString ()); tüm metni görmek istiyorsanız. Bu çözüm biraz hileli ama kodunuzda çok daha temiz ve işlevsellik aynı.