Setiap kali siaran saya dieksekusi, saya ingin menunjukkan peringatan untuk aktivitas foreground.
Setiap kali siaran saya dieksekusi, saya ingin menunjukkan peringatan untuk aktivitas foreground.
Jawaban:
Mengetahui bahwa ActivityManager mengelola Activity , sehingga kami dapat memperoleh informasi dari ActivityManager . Kami mendapatkan foreground running Activity saat ini oleh
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
PEMBARUAN 2018/10/03
getRunningTasks () DIHAPUSKAN. lihat solusi di bawah ini.
Metode ini sudah tidak digunakan lagi di API level 21. Pada Build.VERSION_CODES.LOLLIPOP, metode ini tidak lagi tersedia untuk aplikasi pihak ketiga: pengenalan terbaru dokumen-sentris berarti dapat membocorkan informasi orang ke pemanggil. Untuk kompatibilitas mundur, masih akan mengembalikan sebagian kecil dari datanya: setidaknya tugas-tugas pemanggil sendiri, dan mungkin beberapa tugas lain seperti rumah yang diketahui tidak sensitif.
( Catatan: API resmi ditambahkan di API 14: Lihat jawaban ini https://stackoverflow.com/a/29786451/119733 )
JANGAN GUNAKAN jawaban SEBELUMNYA (waqas716).
Anda akan memiliki masalah kebocoran memori, karena referensi statis untuk aktivitas tersebut. Untuk detail lebih lanjut lihat tautan berikut http://android-developers.blogspot.fr/2009/01/avoiding-memory-leaks.html
Untuk menghindari hal ini, Anda harus mengelola referensi kegiatan. Tambahkan nama aplikasi dalam file manifes:
<application
android:name=".MyApp"
....
</application>
Kelas aplikasi Anda:
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;
}
}
Buat Aktivitas baru:
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);
}
}
Jadi, sekarang alih-alih memperluas kelas Aktivitas untuk aktivitas Anda, cukup rentangkan MyBaseActivity. Sekarang, Anda bisa mendapatkan aktivitas Anda saat ini dari aplikasi atau konteks Aktivitas seperti itu:
Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();
WeakReferences
di Android GC mengumpulkan mereka lebih cepat dari yang Anda pikirkan.
WeakReference
tidak disarankan untuk caching, ini bukan caching, yaitu mCurrentActivity
hanya akan memiliki referensi untuk itu ketika masih hidup sehingga WeakReference
tidak akan pernah dikumpulkan saat Activity
berada di atas. Namun apa yang @NachoColoma sarankan salah karena WeakReference
masih dapat merujuk aktivitas yang tidak dilanjutkan (tidak hidup / tidak di atas) jika variabel tidak dihapus!
Application .ActivityLifecycleCallbacks
, yang akan lebih sentral dan Anda tidak perlu menambahkan kode manajemen dalam semua aktivitas Anda. Lihat juga developer.android.com/reference/android/app/…
Saya memperluas bagian atas jawaban @ gezdy.
Di setiap Kegiatan, alih-alih harus "mendaftar" sendiri dengan Application
pengkodean manual, kita dapat menggunakan API berikut sejak level 14, untuk membantu kami mencapai tujuan yang sama dengan pengkodean manual yang lebih sedikit.
public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
Di Application.ActivityLifecycleCallbacks
, Anda bisa mendapatkan yang Activity
"terlampir" atau "terlepas" dari ini Application
.
Namun, teknik ini hanya tersedia sejak API level 14.
implements Application.ActivityLifecycleCallbacks
, dan menambahkan metode untuk mengimplementasikannya. Kemudian di konstruktor kelas itu (atau onCreate atau init atau metode lain yang berjalan ketika instance menjadi aktif / siap), masukkan getApplication().registerActivityLifecycleCallbacks(this);
sebagai baris terakhir.
Pembaruan 2 : Ada api resmi yang ditambahkan untuk ini, silakan gunakan ActivityLifecycleCallbacks sebagai gantinya.
MEMPERBARUI:
Seperti yang ditunjukkan oleh @gezdy, dan saya bersyukur untuk itu. atur referensi ke nol juga untuk aktivitas saat ini, alih-alih memutakhirkan pada setiap onResume atur menjadi nol pada onDestroy setiap Aktivitas untuk menghindari masalah kebocoran memori.
Beberapa waktu yang lalu saya membutuhkan fungsi yang sama dan di sini adalah metode bagaimana saya mencapai ini. Dalam setiap aktivitas Anda, ganti metode-metode siklus hidup ini.
@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);
}
Sekarang di kelas siaran Anda, Anda dapat mengakses aktivitas saat ini untuk menunjukkan peringatan padanya.
Application
hanya dibuat sekali dan tidak pernah sampah dikumpulkan persis seperti variabel statis.
clearReferences()
menjadi (this.equals(currActivity))
.
@lockwobr Terima kasih telah memperbarui
Ini tidak bekerja 100% dari waktu di api versi 16, jika Anda membaca kode di github fungsi "currentActivityThread" diubah di Kitkat, jadi saya ingin mengatakan versi 19ish, agak sulit untuk mencocokkan versi api dengan rilis di github .
Memiliki akses ke arus Activity
sangat berguna. Bukankah lebih baik memiliki getActivity
metode statis mengembalikan Kegiatan saat ini tanpa pertanyaan yang tidak perlu?
The Activity
kelas sangat berguna. Ini memberi akses ke utas UI aplikasi, tampilan, sumber daya, dan banyak lagi. Banyak metode membutuhkan Context
, tetapi bagaimana cara mendapatkan pointer? Berikut ini beberapa cara:
ActivityThread
. Kelas ini memiliki akses ke semua Kegiatan dan, apa yang lebih baik, memiliki metode statis untuk mendapatkan arus ActivityThread
. Hanya ada satu masalah kecil - daftar Aktivitas memiliki akses paket.Mudah dipecahkan menggunakan refleksi:
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;
}
Metode seperti itu dapat digunakan di mana saja di aplikasi dan itu jauh lebih nyaman daripada semua pendekatan yang disebutkan. Selain itu, sepertinya itu tidak seaman kelihatannya. Itu tidak memperkenalkan potensi kebocoran baru atau null pointer.
Cuplikan kode di atas tidak memiliki penanganan pengecualian dan secara naif mengasumsikan bahwa Aktivitas berjalan pertama adalah yang kami cari. Anda mungkin ingin menambahkan beberapa cek tambahan.
Map
antarmuka HashMap
atau ArrayMap
. Saya sudah mengedit jawaban @AZ_.
Saya melakukan Mengikuti di Kotlin
Edit Kelas Aplikasi sebagai Berikut
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
}
}
}
Buat kelas 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
}
}
Anda sekarang dapat menggunakannya di kelas apa pun dengan memanggil yang berikut: FTApplication.currentActivity()
getCurrentActivity () juga ada di ReactContextBaseJavaModule.
(Karena pertanyaan ini awalnya ditanyakan, banyak aplikasi Android juga memiliki komponen ReactNative - aplikasi hybrid.)
class ReactContext di ReactNative memiliki seluruh rangkaian logika untuk mempertahankan mCurrentActivity yang dikembalikan di getCurrentActivity ().
Catatan: Saya berharap getCurrentActivity () diimplementasikan di kelas Aplikasi Android.
Saya tidak dapat menemukan solusi yang akan membuat tim kami senang, jadi kami menggulung sendiri. Kami menggunakan ActivityLifecycleCallbacks
untuk melacak aktivitas saat ini dan kemudian mengeksposnya melalui layanan. Lebih detail di sini: https://stackoverflow.com/a/38650587/10793
Untuk kompatibilitas mundur:
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
pegangan dari Application
kelas - sementara ComponentName
diperlukan untuk menentukan apakah yang diinginkan Activity
ada di atas daftar tugas yang sedang berjalan. Dan jika ini tidak sepenuhnya menjawab pertanyaan, jawaban yang diterima juga tidak.
topActivity
hanya tersedia dari Android Q
Secara pribadi saya melakukan apa yang dikatakan "Cheok Yan Cheng", tetapi saya menggunakan "Daftar" untuk memiliki "Backstack" dari semua kegiatan saya.
Jika Anda ingin memeriksa Yang merupakan Aktivitas Saat Ini, Anda hanya perlu mendapatkan kelas aktivitas terakhir dalam daftar.
Buat aplikasi yang memperluas "Aplikasi" dan lakukan ini:
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() }
}
}
Dalam kasus saya, saya menggunakan "Application.ActivityLifecycleCallbacks" untuk:
Bind / Unbind Merlin Instance (digunakan untuk mendapatkan acara ketika aplikasi kehilangan atau mendapatkan koneksi, misalnya ketika Anda menutup data seluler atau ketika Anda membukanya). Ini berguna setelah tindakan niat "OnConnectivityChanged" dinonaktifkan. Untuk info lebih lanjut tentang MERLIN, lihat: Tautan INFO MERLIN
Tutup Instansi Realm saya yang terakhir ketika aplikasi ditutup; Saya akan memasukkannya ke dalam BaseActivity yang diperluas dari semua kegiatan lainnya dan yang memiliki Instance RealmHelper pribadi. Untuk info lebih lanjut tentang REALM, lihat: REALM INFO LINK Misalnya saya punya contoh "RealmHelper" statis di dalam kelas "RealmHelper" saya yang dipakai di dalam aplikasi saya "onCreate". Saya memiliki layanan sinkronisasi tempat saya membuat "RealmHelper" yang baru karena Realm "Linked-Linked" dan Realm Instance tidak dapat bekerja di dalam Thread yang berbeda. Jadi untuk mengikuti Dokumentasi Realm "Anda Harus Menutup Semua Instansi Realm Terbuka untuk menghindari Kebocoran Sumber Daya Sistem", untuk mencapai hal ini saya menggunakan "Application.ActivityLifecycleCallbacks" seperti yang dapat Anda lihat.
Akhirnya saya memiliki penerima yang dipicu ketika saya selesai menyinkronkan aplikasi saya, kemudian ketika sinkronisasi berakhir itu akan memanggil metode "IEndSyncCallback" "onEndSync" di mana saya melihat jika saya memiliki Kelas Aktivitas tertentu di dalam daftar ActivitiesBackStack saya karena saya perlu untuk memperbarui data pada tampilan jika sinkronisasi memperbaruinya dan saya perlu melakukan operasi orang lain setelah sinkronisasi aplikasi.
Itu saja, semoga ini membantu. Sampai jumpa :)
Jawaban oleh waqas716 baik. Saya membuat solusi untuk kasus tertentu yang menuntut lebih sedikit kode dan pemeliharaan.
Saya menemukan pekerjaan khusus sekitar dengan memiliki metode statis mengambil pandangan dari aktivitas yang saya curigai berada di latar depan. Anda dapat mengulangi semua aktivitas dan memeriksa apakah Anda menginginkan atau mendapatkan nama aktivitas dari jawaban martin
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
Saya kemudian memeriksa apakah tampilan tidak nol dan mendapatkan konteksnya melalui 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, ..."
di developer.android.com/reference/android/app/...
Saya tidak suka jawaban yang lain. ActivityManager tidak dimaksudkan untuk digunakan untuk mendapatkan aktivitas saat ini. Super classing dan bergantung pada onDestroy juga rapuh dan bukan desain terbaik.
Jujur, yang terbaik yang saya hasilkan sejauh ini hanya mempertahankan enum di Aplikasi saya, yang akan ditetapkan ketika suatu aktivitas dibuat.
Rekomendasi lain mungkin untuk menghindari menggunakan beberapa kegiatan jika memungkinkan. Ini dapat dilakukan dengan menggunakan fragmen, atau dalam tampilan khusus preferensi saya.
Solusi yang agak sederhana adalah membuat kelas manajer tunggal, di mana Anda dapat menyimpan referensi ke satu atau lebih Kegiatan, atau apa pun yang Anda ingin akses ke seluruh aplikasi.
Panggilan UberManager.getInstance().setMainActivity( activity );
onCreate aktivitas utama.
Panggil UberManager.getInstance().getMainActivity();
di mana saja di aplikasi Anda untuk mengambilnya. (Saya menggunakan ini untuk dapat menggunakan Toast dari utas non UI.)
Pastikan Anda menambahkan panggilan UberManager.getInstance().cleanup();
saat aplikasi Anda dihancurkan.
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;
}
}
Saya terlambat 3 tahun tetapi saya tetap akan menjawabnya kalau-kalau ada orang yang menemukan saya seperti ini.
Saya memecahkan ini dengan hanya menggunakan ini:
if (getIntent().toString().contains("MainActivity")) {
// Do stuff if the current activity is MainActivity
}
Perhatikan bahwa "getIntent (). ToString ()" mencakup banyak teks lain seperti nama paket Anda dan filter maksud apa pun untuk aktivitas Anda. Secara teknis kami memeriksa maksud saat ini, bukan aktivitas, tetapi hasilnya sama. Cukup gunakan misalnya Log.d ("test", getIntent (). ToString ()); jika Anda ingin melihat semua teks. Solusi ini agak hacky tetapi jauh lebih bersih dalam kode Anda dan fungsinya sama.