Saya mencoba untuk menulis aplikasi yang melakukan sesuatu yang spesifik ketika dibawa kembali ke latar depan setelah beberapa waktu. Apakah ada cara untuk mendeteksi kapan aplikasi dikirim ke latar belakang atau dibawa ke latar depan?
Saya mencoba untuk menulis aplikasi yang melakukan sesuatu yang spesifik ketika dibawa kembali ke latar depan setelah beberapa waktu. Apakah ada cara untuk mendeteksi kapan aplikasi dikirim ke latar belakang atau dibawa ke latar depan?
Jawaban:
Metode onPause()
dan onResume()
dipanggil ketika aplikasi dibawa ke latar belakang dan ke latar depan lagi. Namun, mereka juga dipanggil ketika aplikasi dimulai untuk pertama kalinya dan sebelum dimatikan. Anda dapat membaca lebih lanjut di Activity .
Tidak ada pendekatan langsung untuk mendapatkan status aplikasi saat berada di latar belakang atau latar depan, tetapi bahkan saya telah menghadapi masalah ini dan menemukan solusinya dengan onWindowFocusChanged
dan onStop
.
Untuk detail lebih lanjut, periksa di sini Android: Solusi untuk mendeteksi ketika aplikasi Android pergi ke latar belakang dan kembali ke latar depan tanpa getRunningTasks atau getRunningAppProcesses .
PEMBARUAN Maret 2018 : Sekarang ada solusi yang lebih baik. Lihat ProcessLifecycleOwner . Anda perlu menggunakan komponen arsitektur baru 1.1.0 (terbaru saat ini) tetapi dirancang khusus untuk melakukan ini.
Ada contoh sederhana yang disediakan dalam jawaban ini tetapi saya menulis contoh aplikasi dan posting blog tentang itu.
Sejak saya menulis ini kembali pada tahun 2014, berbagai solusi muncul. Beberapa bekerja, beberapa dianggap bekerja , tetapi memiliki kekurangan (termasuk saya!) Dan kami, sebagai komunitas (Android) belajar untuk hidup dengan konsekuensinya dan menulis solusi untuk kasus-kasus khusus.
Jangan pernah menganggap satu cuplikan kode adalah solusi yang Anda cari, tidak mungkin demikian; lebih baik lagi, cobalah untuk memahami apa yang dilakukannya dan mengapa ia melakukannya.
The MemoryBoss
kelas tidak pernah benar-benar digunakan oleh saya seperti yang tertulis di sini, itu hanya bagian dari kode semu yang terjadi dengan pekerjaan.
Kecuali ada alasan yang sah bagi Anda untuk tidak menggunakan komponen arsitektur baru (dan ada beberapa, terutama jika Anda menargetkan apis super lama), maka lanjutkan dan gunakan. Mereka jauh dari sempurna, tetapi juga tidak ComponentCallbacks2
.
PEMBARUAN / CATATAN (November 2015) : Orang-orang telah membuat dua komentar, pertama adalah yang >=
harus digunakan alih-alih ==
karena dokumentasi menyatakan bahwa Anda tidak harus memeriksa nilai yang tepat . Ini bagus untuk sebagian besar kasus, tetapi ingatlah bahwa jika Anda hanya peduli melakukan sesuatu ketika aplikasi pergi ke latar belakang, Anda harus menggunakan == dan juga menggabungkannya dengan solusi lain (seperti callback Daur Hidup Aktivitas), atau Anda mungkin tidak mendapatkan efek yang Anda inginkan. Contohnya (dan ini terjadi pada saya) adalah jika Anda ingin mengunciaplikasi Anda dengan layar kata sandi ketika pergi ke latar belakang (seperti 1 Kata sandi jika Anda terbiasa dengan itu), Anda mungkin secara tidak sengaja mengunci aplikasi Anda jika kehabisan memori dan tiba-tiba menguji >= TRIM_MEMORY
, karena Android akan memicu LOW MEMORY
panggilan dan itu lebih tinggi dari milikmu. Jadi berhati-hatilah bagaimana / apa yang Anda uji.
Selain itu, beberapa orang bertanya tentang cara mendeteksi ketika Anda kembali.
Cara paling sederhana yang dapat saya pikirkan dijelaskan di bawah ini, tetapi karena beberapa orang tidak terbiasa dengan itu, saya menambahkan beberapa kode pseudo di sini. Dengan asumsi Anda memiliki YourApplication
dan MemoryBoss
kelas - kelas, di class BaseActivity extends Activity
(Anda perlu membuat satu jika Anda tidak memilikinya).
@Override
protected void onStart() {
super.onStart();
if (mApplication.wasInBackground()) {
// HERE YOU CALL THE CODE YOU WANT TO HAPPEN ONLY ONCE WHEN YOUR APP WAS RESUMED FROM BACKGROUND
mApplication.setWasInBackground(false);
}
}
Saya merekomendasikan onStart karena Dialog dapat menjeda suatu kegiatan, jadi saya yakin Anda tidak ingin aplikasi Anda berpikir "itu pergi ke latar belakang" jika semua yang Anda lakukan adalah menampilkan dialog layar penuh, tetapi jarak tempuh Anda mungkin bervariasi.
Dan itu saja. Kode di blok if akan hanya akan dieksekusi sekali , bahkan jika Anda pergi ke kegiatan lain, yang baru (yang juga extends BaseActivity
) akan melaporkan wasInBackground
ini false
sehingga tidak akan mengeksekusi kode, sampai onMemoryTrimmed
disebut dan bendera diatur ke benar lagi .
Semoga itu bisa membantu.
UPDATE / CATATAN (April 2015) : Sebelum Anda pergi semua Salin dan Tempel pada kode ini, perhatikan bahwa saya telah menemukan beberapa contoh di mana itu mungkin tidak 100% dapat diandalkan dan harus dikombinasikan dengan metode lain untuk mencapai hasil terbaik. Khususnya, ada dua contoh yang diketahui di mana onTrimMemory
panggilan kembali tidak dijamin akan dieksekusi:
Jika ponsel Anda mengunci layar saat aplikasi Anda terlihat (mis. Perangkat Anda mengunci setelah beberapa menit), panggilan balik ini tidak dipanggil (atau tidak selalu) karena layar kunci hanya di atas, tetapi aplikasi Anda masih "berjalan" walaupun tertutup.
Jika perangkat Anda relatif rendah pada memori (dan di bawah tekanan memori), Sistem Operasi tampaknya mengabaikan panggilan ini dan langsung ke tingkat yang lebih kritis.
Sekarang, tergantung seberapa penting bagi Anda untuk mengetahui kapan aplikasi Anda pergi ke latar belakang, Anda mungkin atau mungkin tidak perlu memperluas solusi ini bersama dengan melacak siklus hidup aktivitas dan yang lainnya.
Ingatlah selalu hal di atas dan miliki tim QA yang baik;)
AKHIR PEMBARUAN
Mungkin terlambat tetapi ada metode yang dapat diandalkan di Ice Cream Sandwich (API 14) dan di atasnya .
Ternyata ketika aplikasi Anda tidak memiliki UI yang lebih terlihat, panggilan balik dipicu. Callback, yang dapat Anda terapkan dalam kelas khusus, disebut ComponentCallbacks2 (ya, dengan dua). Callback ini hanya tersedia di API Level 14 (Ice Cream Sandwich) dan di atasnya.
Anda pada dasarnya mendapat panggilan ke metode:
public abstract void onTrimMemory (int level)
Levelnya adalah 20 atau lebih khusus
public static final int TRIM_MEMORY_UI_HIDDEN
Saya telah menguji ini dan selalu berhasil, karena level 20 hanyalah "saran" agar Anda ingin melepaskan beberapa sumber daya karena aplikasi Anda tidak lagi terlihat.
Mengutip dokumen resmi:
Level untuk onTrimMemory (int): proses telah menunjukkan antarmuka pengguna, dan tidak lagi melakukannya. Alokasi besar dengan UI harus dirilis pada saat ini untuk memungkinkan memori dikelola dengan lebih baik.
Tentu saja, Anda harus menerapkan ini untuk benar-benar melakukan apa yang dikatakannya (membersihkan memori yang belum pernah digunakan dalam waktu tertentu, membersihkan beberapa koleksi yang telah duduk tidak digunakan, dll. Kemungkinannya tidak terbatas (lihat dokumen resmi untuk kemungkinan lainnya lebih lanjut) level kritis ).
Tapi, yang menarik, OS memberitahu Anda: HEY, aplikasi Anda pergi ke latar belakang!
Itulah yang ingin Anda ketahui sejak awal.
Bagaimana Anda menentukan kapan Anda kembali?
Yah itu mudah, saya yakin Anda memiliki "BaseActivity" sehingga Anda dapat menggunakan onResume () Anda untuk menandai fakta bahwa Anda kembali. Karena satu-satunya saat Anda mengatakan Anda tidak kembali adalah ketika Anda benar-benar menerima panggilan ke onTrimMemory
metode di atas .
Berhasil. Anda tidak mendapatkan positif palsu. Jika suatu kegiatan dilanjutkan, Anda kembali, 100% dari waktu. Jika pengguna kembali ke belakang, Anda mendapat onTrimMemory()
panggilan lain .
Anda harus memasukkan Aktivitas Anda (atau lebih baik, kelas khusus).
Cara termudah untuk menjamin bahwa Anda selalu menerima ini adalah dengan membuat kelas sederhana seperti ini:
public class MemoryBoss implements ComponentCallbacks2 {
@Override
public void onConfigurationChanged(final Configuration newConfig) {
}
@Override
public void onLowMemory() {
}
@Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// We're in the Background
}
// you might as well implement some memory cleanup here and be a nice Android dev.
}
}
Untuk menggunakan ini, dalam implementasi Aplikasi Anda ( Anda memilikinya, KANAN? ), Lakukan sesuatu seperti:
MemoryBoss mMemoryBoss;
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
mMemoryBoss = new MemoryBoss();
registerComponentCallbacks(mMemoryBoss);
}
}
Jika Anda membuat, Interface
Anda bisa menambahkan else
itu if
dan menerapkan ComponentCallbacks
(tanpa 2) yang digunakan dalam apa pun di bawah API 14. Callback itu hanya memiliki onLowMemory()
metode dan tidak dipanggil ketika Anda pergi ke latar belakang , tetapi Anda harus menggunakannya untuk memangkas memori .
Sekarang luncurkan Aplikasi Anda dan tekan home. AndaonTrimMemory(final int level)
Metode harus dipanggil (petunjuk: tambahkan logging).
Langkah terakhir adalah membatalkan registrasi dari callback. Mungkin tempat terbaik adalah onTerminate()
metode Aplikasi Anda, tetapi metode itu tidak dipanggil di perangkat nyata:
/** * This method is for use in emulated process environments. It will * never be called on a production Android device, where processes are * removed by simply killing them; no user code (including this callback) * is executed when doing so. */
Jadi, kecuali Anda benar-benar memiliki situasi di mana Anda tidak lagi ingin didaftarkan, Anda dapat dengan aman mengabaikannya, karena proses Anda sedang sekarat di tingkat OS.
Jika Anda memutuskan untuk membatalkan registrasi di beberapa titik (jika Anda, misalnya, memberikan mekanisme mematikan aplikasi untuk membersihkan dan mati), Anda dapat melakukan:
unregisterComponentCallbacks(mMemoryBoss);
Dan itu saja.
level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
yang menghindari masalah dalam pembaruan Anda, poin 2. Mengenai poin 1, itu bukan masalah bagi saya, karena aplikasi tidak benar-benar pergi ke latar belakang, jadi itulah cara yang seharusnya berfungsi.
Begini cara saya berhasil menyelesaikan ini. Ini berfungsi pada premis bahwa menggunakan referensi waktu antara transisi aktivitas kemungkinan besar akan memberikan bukti yang memadai bahwa aplikasi telah "dilatar belakangi" atau tidak.
Pertama, saya telah menggunakan contoh android.app.Application (sebut saja MyApplication) yang memiliki Timer, TimerTask, konstanta untuk mewakili jumlah milidetik maksimum yang dapat diambil oleh transisi dari satu aktivitas ke aktivitas lainnya (saya pergi dengan nilai 2s), dan boolean untuk menunjukkan apakah aplikasi tersebut "di latar belakang":
public class MyApplication extends Application {
private Timer mActivityTransitionTimer;
private TimerTask mActivityTransitionTimerTask;
public boolean wasInBackground;
private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000;
...
Aplikasi ini juga menyediakan dua metode untuk memulai dan menghentikan timer / tugas:
public void startActivityTransitionTimer() {
this.mActivityTransitionTimer = new Timer();
this.mActivityTransitionTimerTask = new TimerTask() {
public void run() {
MyApplication.this.wasInBackground = true;
}
};
this.mActivityTransitionTimer.schedule(mActivityTransitionTimerTask,
MAX_ACTIVITY_TRANSITION_TIME_MS);
}
public void stopActivityTransitionTimer() {
if (this.mActivityTransitionTimerTask != null) {
this.mActivityTransitionTimerTask.cancel();
}
if (this.mActivityTransitionTimer != null) {
this.mActivityTransitionTimer.cancel();
}
this.wasInBackground = false;
}
Bagian terakhir dari solusi ini adalah untuk menambahkan panggilan ke masing-masing metode ini dari peristiwa onResume () dan onPause () dari semua aktivitas atau, lebih disukai, dalam Kegiatan dasar yang mewarisi semua Aktivitas konkret Anda:
@Override
public void onResume()
{
super.onResume();
MyApplication myApp = (MyApplication)this.getApplication();
if (myApp.wasInBackground)
{
//Do specific came-here-from-background code
}
myApp.stopActivityTransitionTimer();
}
@Override
public void onPause()
{
super.onPause();
((MyApplication)this.getApplication()).startActivityTransitionTimer();
}
Jadi dalam kasus ketika pengguna hanya menavigasi antara aktivitas aplikasi Anda, onPause () dari aktivitas yang berangkat memulai timer, tetapi hampir segera aktivitas yang dimasukkan membatalkan timer sebelum dapat mencapai waktu transisi maks. Dan begitu pula InBackground akan salah .
Di sisi lain ketika suatu Kegiatan datang ke latar depan dari Peluncur, bangun perangkat, mengakhiri panggilan telepon, dll., Kemungkinan besar tugas penghitung waktu dieksekusi sebelum acara ini, dan dengan demikian InBackground disetel ke true .
Sunting: komponen arsitektur baru membawa sesuatu yang menjanjikan: ProcessLifecycleOwner , lihat jawaban @ vokilam
class YourApplication : Application() {
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(AppLifecycleTracker())
}
}
class AppLifecycleTracker : Application.ActivityLifecycleCallbacks {
private var numStarted = 0
override fun onActivityStarted(activity: Activity?) {
if (numStarted == 0) {
// app went to foreground
}
numStarted++
}
override fun onActivityStopped(activity: Activity?) {
numStarted--
if (numStarted == 0) {
// app went to background
}
}
}
Iya. Saya tahu sulit untuk percaya solusi sederhana ini bekerja karena kami memiliki begitu banyak solusi aneh di sini.
Tapi ada harapan.
ProcessLifecycleOwner
tampaknya menjadi solusi yang menjanjikan juga.
ProcessLifecycleOwner akan mengirimkan
ON_START
,ON_RESUME
peristiwa, sebagai aktivitas pertama bergerak melalui peristiwa ini.ON_PAUSE
,,ON_STOP
acara akan dikirim dengan penundaan setelah aktivitas terakhir melewati mereka. Penundaan ini cukup lama untuk menjamin bahwaProcessLifecycleOwner
tidak akan mengirim peristiwa apa pun jika aktivitas dihancurkan dan diciptakan kembali karena perubahan konfigurasi.
Implementasi bisa sesederhana
class AppLifecycleListener : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onMoveToForeground() { // app moved to foreground
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onMoveToBackground() { // app moved to background
}
}
// register observer
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleListener())
Menurut kode sumber, nilai penundaan saat ini adalah 700ms
.
Juga menggunakan fitur ini memerlukan dependencies
:
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"
implementation "android.arch.lifecycle:extensions:1.0.0"
dan annotationProcessor "android.arch.lifecycle:compiler:1.0.0"
dari repositori Google (mis. google()
)
Berdasarkan jawaban Martín Marconcinis (terima kasih!) Saya akhirnya menemukan solusi yang andal (dan sangat sederhana).
public class ApplicationLifecycleHandler implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
private static final String TAG = ApplicationLifecycleHandler.class.getSimpleName();
private static boolean isInBackground = false;
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
if(isInBackground){
Log.d(TAG, "app went to foreground");
isInBackground = false;
}
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onConfigurationChanged(Configuration configuration) {
}
@Override
public void onLowMemory() {
}
@Override
public void onTrimMemory(int i) {
if(i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN){
Log.d(TAG, "app went to background");
isInBackground = true;
}
}
}
Kemudian tambahkan ini ke onCreate () dari kelas Aplikasi Anda
public class MyApp extends android.app.Application {
@Override
public void onCreate() {
super.onCreate();
ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler();
registerActivityLifecycleCallbacks(handler);
registerComponentCallbacks(handler);
}
}
Kami menggunakan metode ini. Kelihatannya terlalu sederhana untuk bekerja, tetapi telah teruji dengan baik di aplikasi kami dan ternyata bekerja dengan sangat baik dalam semua kasus, termasuk pergi ke layar beranda dengan tombol "home", dengan tombol "kembali", atau setelah kunci layar. Cobalah.
Gagasannya adalah, ketika di latar depan, Android selalu memulai aktivitas baru sebelum menghentikan yang sebelumnya. Itu tidak dijamin, tapi begitulah cara kerjanya. BTW, Flurry tampaknya menggunakan logika yang sama (hanya tebakan, saya tidak memeriksa itu, tapi itu mengait pada acara yang sama).
public abstract class BaseActivity extends Activity {
private static int sessionDepth = 0;
@Override
protected void onStart() {
super.onStart();
sessionDepth++;
if(sessionDepth == 1){
//app came to foreground;
}
}
@Override
protected void onStop() {
super.onStop();
if (sessionDepth > 0)
sessionDepth--;
if (sessionDepth == 0) {
// app went to background
}
}
}
Sunting: sesuai komentar, kami juga pindah ke onStart () di versi kode yang lebih baru. Juga, saya menambahkan panggilan super, yang hilang dari posting awal saya, karena ini lebih merupakan konsep daripada kode yang berfungsi.
onStop is called when the activity is no longer visible to the user
,.
Jika aplikasi Anda terdiri dari beberapa aktivitas dan / atau aktivitas bertumpuk seperti widget tab bar, maka mengesampingkan onPause () dan onResume () tidak akan berfungsi. Yaitu ketika memulai aktivitas baru, aktivitas saat ini akan dijeda sebelum yang baru dibuat. Hal yang sama berlaku ketika menyelesaikan (menggunakan tombol "kembali") suatu kegiatan.
Saya telah menemukan dua metode yang tampaknya berfungsi seperti yang diinginkan.
Yang pertama membutuhkan izin GET_TASKS dan terdiri dari metode sederhana yang memeriksa apakah aktivitas yang berjalan paling atas di perangkat milik aplikasi, dengan membandingkan nama paket:
private boolean isApplicationBroughtToBackground() {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
}
Metode ini ditemukan dalam kerangka Droid-Fu (sekarang disebut Ignition).
Metode kedua yang saya terapkan sendiri tidak memerlukan izin GET_TASKS, yang bagus. Sebaliknya itu sedikit lebih rumit untuk diterapkan.
Di kelas MainApplication Anda, Anda memiliki variabel yang melacak jumlah aktivitas yang berjalan di aplikasi Anda. Di onResume () untuk setiap aktivitas Anda meningkatkan variabel dan di onPause () Anda menguranginya.
Ketika jumlah aktivitas yang berjalan mencapai 0, aplikasi diletakkan di latar belakang JIKA kondisi berikut ini benar:
Ketika Anda dapat mendeteksi bahwa aplikasi telah mengundurkan diri ke latar belakang, mudah dideteksi ketika dibawa kembali ke latar depan juga.
Buat kelas yang diperluas Application
. Kemudian di dalamnya kita dapat menggunakan metode override-nya,onTrimMemory()
,.
Untuk mendeteksi jika aplikasi pergi ke latar belakang, kami akan menggunakan:
@Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Works for Activity
// Get called every-time when application went to background.
}
else if (level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { // Works for FragmentActivty
}
}
FragmentActivity
Anda juga mungkin ingin menambahkan level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE
juga.
Pertimbangkan untuk menggunakan onUserLeaveHint. Ini hanya akan dipanggil ketika aplikasi Anda masuk ke latar belakang. onPause akan memiliki kasus sudut untuk ditangani, karena dapat dipanggil karena alasan lain; misalnya jika pengguna membuka aktivitas lain di aplikasi Anda seperti halaman pengaturan Anda, metode onPause aktivitas utama Anda akan dipanggil meskipun mereka masih di aplikasi Anda; melacak apa yang terjadi akan mengarah ke bug ketika Anda bisa menggunakan callback onUserLeaveHint yang melakukan apa yang Anda minta.
Ketika pada UserLeaveHint dipanggil, Anda dapat mengatur flag boolean inBackground menjadi true. Saat onResume dipanggil, anggap saja Anda kembali ke latar depan jika flag inBackground diatur. Ini karena onResume juga akan dipanggil pada aktivitas utama Anda jika pengguna hanya di menu pengaturan Anda dan tidak pernah meninggalkan aplikasi.
Ingat bahwa jika pengguna menekan tombol beranda saat di layar pengaturan Anda, onUserLeaveHint akan dipanggil dalam aktivitas pengaturan Anda, dan ketika mereka kembali onResume akan dipanggil dalam aktivitas pengaturan Anda. Jika Anda hanya memiliki kode deteksi ini di aktivitas utama Anda, Anda akan kehilangan use case ini. Untuk memiliki kode ini di semua aktivitas Anda tanpa kode duplikat, miliki kelas aktivitas abstrak yang memperluas Aktivitas, dan masukkan kode umum Anda di dalamnya. Maka setiap aktivitas yang Anda miliki dapat memperluas aktivitas abstrak ini.
Sebagai contoh:
public abstract AbstractActivity extends Activity {
private static boolean inBackground = false;
@Override
public void onResume() {
if (inBackground) {
// You just came from the background
inBackground = false;
}
else {
// You just returned from another activity within your own app
}
}
@Override
public void onUserLeaveHint() {
inBackground = true;
}
}
public abstract MainActivity extends AbstractActivity {
...
}
public abstract SettingsActivity extends AbstractActivity {
...
}
ActivityLifecycleCallbacks mungkin menarik, tetapi tidak didokumentasikan dengan baik.
Padahal, jika Anda memanggil registerActivityLifecycleCallbacks (), Anda harus bisa mendapatkan panggilan balik untuk saat Aktivitas dibuat, dihancurkan, dll. Anda dapat memanggil getComponentName () untuk Aktivitas.
The android.arch.lifecycle menyediakan paket kelas dan interface yang memungkinkan Anda membangun komponen siklus hidup-sadar
Aplikasi Anda harus mengimplementasikan antarmuka LifecycleObserver:
public class MyApplication extends Application implements LifecycleObserver {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
private void onAppBackgrounded() {
Log.d("MyApp", "App in background");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
private void onAppForegrounded() {
Log.d("MyApp", "App in foreground");
}
}
Untuk melakukan itu, Anda perlu menambahkan ketergantungan ini ke file build.gradle Anda:
dependencies {
implementation "android.arch.lifecycle:extensions:1.1.1"
}
Seperti yang direkomendasikan oleh Google, Anda harus meminimalkan kode yang dieksekusi dalam metode aktivitas siklus hidup:
Pola umum adalah untuk mengimplementasikan aksi komponen dependen dalam metode siklus hidup dari aktivitas dan fragmen. Namun, pola ini mengarah pada organisasi kode yang buruk dan menjamurnya kesalahan. Dengan menggunakan komponen yang memperhatikan siklus hidup, Anda dapat memindahkan kode komponen tergantung dari metode siklus hidup dan ke dalam komponen itu sendiri.
Anda dapat membaca lebih lanjut di sini: https://developer.android.com/topic/libraries/architecture/lifecycle
Di Aplikasi Anda, tambahkan panggilan balik dan periksa aktivitas root dengan cara seperti ini:
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (activity.isTaskRoot() && !(activity instanceof YourSplashScreenActivity)) {
Log.e(YourApp.TAG, "Reload defaults on restoring from background.");
loadDefaults();
}
}
});
}
Saya telah membuat proyek di Github app-foreground-background-listen
Buat BaseActivity untuk semua Kegiatan di aplikasi Anda.
public class BaseActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
public static boolean isAppInFg = false;
public static boolean isScrInFg = false;
public static boolean isChangeScrFg = false;
@Override
protected void onStart() {
if (!isAppInFg) {
isAppInFg = true;
isChangeScrFg = false;
onAppStart();
}
else {
isChangeScrFg = true;
}
isScrInFg = true;
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
if (!isScrInFg || !isChangeScrFg) {
isAppInFg = false;
onAppPause();
}
isScrInFg = false;
}
public void onAppStart() {
// Remove this toast
Toast.makeText(getApplicationContext(), "App in foreground", Toast.LENGTH_LONG).show();
// Your code
}
public void onAppPause() {
// Remove this toast
Toast.makeText(getApplicationContext(), "App in background", Toast.LENGTH_LONG).show();
// Your code
}
}
Sekarang gunakan BaseActivity ini sebagai kelas super dari semua Aktivitas Anda seperti MainActivity meluas BaseActivity dan onAppStart akan dipanggil ketika Anda memulai aplikasi Anda dan onAppPause () akan dipanggil ketika aplikasi pergi latar belakang dari layar apa pun.
Ini cukup mudah ProcessLifecycleOwner
Tambahkan dependensi ini
implementation "android.arch.lifecycle:extensions:$project.archLifecycleVersion"
kapt "android.arch.lifecycle:compiler:$project.archLifecycleVersion"
Di Kotlin :
class ForegroundBackgroundListener : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun startSomething() {
Log.v("ProcessLog", "APP IS ON FOREGROUND")
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stopSomething() {
Log.v("ProcessLog", "APP IS IN BACKGROUND")
}
}
Kemudian dalam aktivitas dasar Anda:
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get()
.lifecycle
.addObserver(
ForegroundBackgroundListener()
.also { appObserver = it })
}
Lihat artikel saya tentang topik ini: https://medium.com/@egek92/how-to-actual-detect-foreground-background-changes-in-your-android-application-without-wanting-9719cc822c48
Anda dapat menggunakan ProcessLifecycleOwner melampirkan pengamat siklus hidup untuk itu.
public class ForegroundLifecycleObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onAppCreated() {
Timber.d("onAppCreated() called");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppStarted() {
Timber.d("onAppStarted() called");
}
@OnLifecycleEvent(Event.ON_RESUME)
public void onAppResumed() {
Timber.d("onAppResumed() called");
}
@OnLifecycleEvent(Event.ON_PAUSE)
public void onAppPaused() {
Timber.d("onAppPaused() called");
}
@OnLifecycleEvent(Event.ON_STOP)
public void onAppStopped() {
Timber.d("onAppStopped() called");
}
}
maka pada onCreate()
kelas Aplikasi Anda, Anda menyebutnya:
ProcessLifecycleOwner.get().getLifecycle().addObserver(new ForegroundLifecycleObserver());
dengan ini Anda akan dapat menangkap peristiwa ON_PAUSE
dan ON_STOP
aplikasi Anda yang terjadi ketika berjalan di latar belakang.
Tidak ada metode siklus langsung untuk memberi tahu Anda ketika seluruh Aplikasi berjalan latar / latar depan.
Saya telah melakukan ini dengan cara sederhana. Ikuti instruksi di bawah ini untuk mendeteksi fase latar belakang / latar depan aplikasi.
Dengan sedikit penyelesaian, itu mungkin. Di sini, ActivityLifecycleCallbacks datang untuk menyelamatkan. Biarkan saya berjalan selangkah demi selangkah.
Pertama, buat kelas yang memperluas aplikasi android.app.plikasi dan mengimplementasikan antarmuka ActivityLifecycleCallbacks . Di Application.onCreate (), daftarkan callback.
public class App extends Application implements
Application.ActivityLifecycleCallbacks {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
}
Daftarkan kelas "Aplikasi" di Manifest seperti di bawah ini <application android:name=".App"
,.
Akan ada setidaknya satu Kegiatan di negara mulai ketika aplikasi di latar depan dan tidak akan ada Kegiatan di negara mulai ketika aplikasi berada di latar belakang.
Deklarasikan 2 variabel seperti di bawah ini di kelas "Aplikasi".
private int activityReferences = 0;
private boolean isActivityChangingConfigurations = false;
activityReferences
akan menyimpan hitungan jumlah aktivitas dalam kondisi awal . isActivityChangingConfigurations
adalah tanda untuk menunjukkan jika Aktivitas saat ini mengalami perubahan konfigurasi seperti sakelar orientasi.
Dengan menggunakan kode berikut, Anda dapat mendeteksi jika Aplikasi datang di latar depan.
@Override
public void onActivityStarted(Activity activity) {
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
// App enters foreground
}
}
Ini adalah cara mendeteksi jika Aplikasi berjalan latar.
@Override
public void onActivityStopped(Activity activity) {
isActivityChangingConfigurations = activity.isChangingConfigurations();
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// App enters background
}
}
Bagaimana itu bekerja:
Ini adalah sedikit trik yang dilakukan dengan cara metode Siklus Hidup disebut secara berurutan. Biarkan saya menelaah sebuah skenario.
Asumsikan bahwa pengguna meluncurkan Aplikasi dan Kegiatan Peluncur A diluncurkan. Panggilan Siklus Hidup akan menjadi,
A.onCreate ()
A.onStart () (++ activityReferences == 1) (Aplikasi masuk Foreground)
A.onResume ()
Sekarang Aktivitas A memulai Kegiatan B.
A.onPause ()
B.onCreate ()
B.onStart () (++ activityReferences == 2)
B.onResume ()
A.onStop () (--activityReferences == 1)
Kemudian pengguna menavigasi kembali dari Kegiatan B,
B.onPause ()
A.onStart () (++ activityReferences == 2)
A.onResume ()
B.onStop () (--activityReferences == 1)
B.onDestroy ()
Kemudian pengguna menekan tombol Home,
A.onPause ()
A.onStop () (--activityReferences == 0) (Aplikasi memasuki Latar Belakang)
Dalam hal ini, jika pengguna menekan tombol Beranda dari Aktivitas B dan bukan tombol Kembali, tetap saja akan sama dan aktivitas referensi akan 0
. Oleh karena itu, kita dapat mendeteksi sebagai Aplikasi memasuki Latar Belakang.
Jadi, apa perannya isActivityChangingConfigurations
? Dalam skenario di atas, anggap Kegiatan B mengubah orientasi. Urutan panggilan balik akan menjadi,
B.onPause ()
B.onStop () (--activityReferences == 0) (Aplikasi memasuki Background ??)
B.onDestroy ()
B.onCreate ()
B.onStart () (++ activityReferences == 1) (Aplikasi masuk Foreground ??)
B.onResume ()
Itu sebabnya kami memiliki pemeriksaan tambahan isActivityChangingConfigurations
untuk menghindari skenario ketika Aktivitas melalui Konfigurasi berubah.
Saya menemukan metode yang baik untuk mendeteksi aplikasi apakah masuk foreground atau latar belakang. Ini kode saya . Semoga ini bisa membantu Anda.
/**
* Custom Application which can detect application state of whether it enter
* background or enter foreground.
*
* @reference http://www.vardhan-justlikethat.blogspot.sg/2014/02/android-solution-to-detect-when-android.html
*/
public abstract class StatusApplication extends Application implements ActivityLifecycleCallbacks {
public static final int STATE_UNKNOWN = 0x00;
public static final int STATE_CREATED = 0x01;
public static final int STATE_STARTED = 0x02;
public static final int STATE_RESUMED = 0x03;
public static final int STATE_PAUSED = 0x04;
public static final int STATE_STOPPED = 0x05;
public static final int STATE_DESTROYED = 0x06;
private static final int FLAG_STATE_FOREGROUND = -1;
private static final int FLAG_STATE_BACKGROUND = -2;
private int mCurrentState = STATE_UNKNOWN;
private int mStateFlag = FLAG_STATE_BACKGROUND;
@Override
public void onCreate() {
super.onCreate();
mCurrentState = STATE_UNKNOWN;
registerActivityLifecycleCallbacks(this);
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
// mCurrentState = STATE_CREATED;
}
@Override
public void onActivityStarted(Activity activity) {
if (mCurrentState == STATE_UNKNOWN || mCurrentState == STATE_STOPPED) {
if (mStateFlag == FLAG_STATE_BACKGROUND) {
applicationWillEnterForeground();
mStateFlag = FLAG_STATE_FOREGROUND;
}
}
mCurrentState = STATE_STARTED;
}
@Override
public void onActivityResumed(Activity activity) {
mCurrentState = STATE_RESUMED;
}
@Override
public void onActivityPaused(Activity activity) {
mCurrentState = STATE_PAUSED;
}
@Override
public void onActivityStopped(Activity activity) {
mCurrentState = STATE_STOPPED;
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
mCurrentState = STATE_DESTROYED;
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (mCurrentState == STATE_STOPPED && level >= TRIM_MEMORY_UI_HIDDEN) {
if (mStateFlag == FLAG_STATE_FOREGROUND) {
applicationDidEnterBackground();
mStateFlag = FLAG_STATE_BACKGROUND;
}
}else if (mCurrentState == STATE_DESTROYED && level >= TRIM_MEMORY_UI_HIDDEN) {
if (mStateFlag == FLAG_STATE_FOREGROUND) {
applicationDidDestroyed();
mStateFlag = FLAG_STATE_BACKGROUND;
}
}
}
/**
* The method be called when the application been destroyed. But when the
* device screen off,this method will not invoked.
*/
protected abstract void applicationDidDestroyed();
/**
* The method be called when the application enter background. But when the
* device screen off,this method will not invoked.
*/
protected abstract void applicationDidEnterBackground();
/**
* The method be called when the application enter foreground.
*/
protected abstract void applicationWillEnterForeground();
}
Sunting 2: Apa yang saya tulis di bawah ini sebenarnya tidak akan berfungsi. Google telah menolak aplikasi yang menyertakan panggilan ke ActivityManager.getRunningTasks (). Dari dokumentasi , jelas bahwa API ini hanya untuk tujuan debugging dan pengembangan. Saya akan memperbarui posting ini segera setelah saya punya waktu untuk memperbarui proyek GitHub di bawah ini dengan skema baru yang menggunakan timer dan hampir sama baiknya.
Sunting 1: Saya telah menulis posting blog dan membuat repositori GitHub sederhana untuk membuatnya sangat mudah.
Jawaban yang diterima dan diberi peringkat teratas bukanlah pendekatan yang terbaik. Implementasi jawaban teratas dari isApplicationBroughtToBackground () tidak menangani situasi di mana Aktivitas utama Aplikasi menghasilkan ke Aktivitas yang didefinisikan dalam Aplikasi yang sama, tetapi memiliki paket Java yang berbeda. Saya datang dengan cara untuk melakukan ini yang akan berhasil dalam kasus itu.
Panggil ini di onPause (), dan itu akan memberi tahu Anda jika aplikasi Anda masuk ke latar belakang karena aplikasi lain telah dimulai, atau pengguna telah menekan tombol beranda.
public static boolean isApplicationBroughtToBackground(final Activity activity) {
ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(1);
// Check the top Activity against the list of Activities contained in the Application's package.
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
try {
PackageInfo pi = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_ACTIVITIES);
for (ActivityInfo activityInfo : pi.activities) {
if(topActivity.getClassName().equals(activityInfo.name)) {
return false;
}
}
} catch( PackageManager.NameNotFoundException e) {
return false; // Never happens.
}
}
return true;
}
Jawaban yang benar di sini
Buat kelas dengan nama MyApp seperti di bawah ini:
public class MyApp implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
private Context context;
public void setContext(Context context)
{
this.context = context;
}
private boolean isInBackground = false;
@Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
isInBackground = true;
Log.d("status = ","we are out");
}
}
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
if(isInBackground){
isInBackground = false;
Log.d("status = ","we are in");
}
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onConfigurationChanged(Configuration configuration) {
}
@Override
public void onLowMemory() {
}
}
Lalu, di mana pun Anda inginkan (aktivitas pertama yang lebih baik diluncurkan di aplikasi), tambahkan kode di bawah ini:
MyApp myApp = new MyApp();
registerComponentCallbacks(myApp);
getApplication().registerActivityLifecycleCallbacks(myApp);
Selesai! Sekarang ketika aplikasi di latar belakang, kita mendapatkan log status : we are out
dan ketika kita masuk aplikasi, kita mendapatkan logstatus : we are out
Solusi saya terinspirasi oleh jawaban @ d60402 dan juga bergantung pada jendela waktu, tetapi tidak menggunakan Timer
:
public abstract class BaseActivity extends ActionBarActivity {
protected boolean wasInBackground = false;
@Override
protected void onStart() {
super.onStart();
wasInBackground = getApp().isInBackground;
getApp().isInBackground = false;
getApp().lastForegroundTransition = System.currentTimeMillis();
}
@Override
protected void onStop() {
super.onStop();
if( 1500 < System.currentTimeMillis() - getApp().lastForegroundTransition )
getApp().isInBackground = true;
}
protected SingletonApplication getApp(){
return (SingletonApplication)getApplication();
}
}
di mana SingletonApplication
merupakan perluasan Application
kelas:
public class SingletonApplication extends Application {
public boolean isInBackground = false;
public long lastForegroundTransition = 0;
}
Saya menggunakan ini dengan Google Analytics EasyTracker, dan itu berhasil. Bisa diperluas untuk melakukan apa yang Anda cari menggunakan integer sederhana.
public class MainApplication extends Application {
int isAppBackgrounded = 0;
@Override
public void onCreate() {
super.onCreate();
appBackgroundedDetector();
}
private void appBackgroundedDetector() {
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
EasyTracker.getInstance(MainApplication.this).activityStart(activity);
}
@Override
public void onActivityResumed(Activity activity) {
isAppBackgrounded++;
if (isAppBackgrounded > 0) {
// Do something here
}
}
@Override
public void onActivityPaused(Activity activity) {
isAppBackgrounded--;
}
@Override
public void onActivityStopped(Activity activity) {
EasyTracker.getInstance(MainApplication.this).activityStop(activity);
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
});
}
}
Saya tahu ini sedikit terlambat tetapi saya pikir semua jawaban ini memiliki beberapa masalah sementara saya melakukannya seperti di bawah ini dan itu bekerja dengan sempurna.
buat callback daur hidup aktivitas seperti ini:
class ActivityLifeCycle implements ActivityLifecycleCallbacks{
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
}
Activity lastActivity;
@Override
public void onActivityResumed(Activity activity) {
//if (null == lastActivity || (activity != null && activity == lastActivity)) //use this condition instead if you want to be informed also when app has been killed or started for the first time
if (activity != null && activity == lastActivity)
{
Toast.makeText(MyApp.this, "NOW!", Toast.LENGTH_LONG).show();
}
lastActivity = activity;
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
}
dan cukup daftarkan di kelas aplikasi Anda seperti di bawah ini:
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifeCycle());
}
Ini tampaknya menjadi salah satu pertanyaan paling rumit di Android karena (saat tulisan ini dibuat) Android tidak memiliki padanan applicationDidEnterBackground()
atau applicationWillEnterForeground()
panggilan balik iOS . Saya menggunakan Perpustakaan AppState yang disatukan oleh @jenzz .
[AppState adalah] perpustakaan Android sederhana dan reaktif berdasarkan RxJava yang memonitor perubahan status aplikasi. Ini memberi tahu pelanggan setiap kali aplikasi masuk ke latar belakang dan kembali ke latar depan.
Ternyata ini adalah persis apa yang saya butuhkan, terutama karena aplikasi saya memiliki beberapa kegiatan sehingga hanya memeriksa onStart()
atau onStop()
pada suatu kegiatan tidak akan memotongnya.
Pertama saya menambahkan dependensi ini ke gradle:
dependencies {
compile 'com.jenzz.appstate:appstate:3.0.1'
compile 'com.jenzz.appstate:adapter-rxjava2:3.0.1'
}
Maka itu masalah sederhana menambahkan baris ini ke tempat yang sesuai dalam kode Anda:
//Note that this uses RxJava 2.x adapter. Check the referenced github site for other ways of using observable
Observable<AppState> appState = RxAppStateMonitor.monitor(myApplication);
//where myApplication is a subclass of android.app.Application
appState.subscribe(new Consumer<AppState>() {
@Override
public void accept(@io.reactivex.annotations.NonNull AppState appState) throws Exception {
switch (appState) {
case FOREGROUND:
Log.i("info","App entered foreground");
break;
case BACKGROUND:
Log.i("info","App entered background");
break;
}
}
});
Bergantung pada bagaimana Anda berlangganan yang diamati, Anda mungkin harus berhenti berlangganan untuk menghindari kebocoran memori. Lagi info lebih lanjut di halaman github .
Ini adalah versi jawaban @ d60402 yang dimodifikasi: https://stackoverflow.com/a/15573121/4747587
Lakukan semua yang disebutkan di sana. Tetapi alih-alih memiliki Base Activity
dan menjadikannya sebagai orangtua untuk setiap aktivitas dan yang menimpa onResume()
danonPause
, lakukan di bawah ini:
Di kelas aplikasi Anda, tambahkan baris:
registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback);
Ini callback
memiliki semua metode siklus aktivitas dan sekarang Anda dapat mengganti onActivityResumed()
danonActivityPaused()
.
Lihatlah Gist ini: https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b
Anda dapat mencapai ini dengan mudah dengan bantuan ActivityLifecycleCallbacks
dan ComponentCallbacks2
sesuatu seperti di bawah ini.
Buat kelas yang AppLifeCycleHandler
mengimplementasikan antarmuka di atas.
package com.sample.app;
import android.app.Activity;
import android.app.Application;
import android.content.ComponentCallbacks2;
import android.content.res.Configuration;
import android.os.Bundle;
/**
* Created by Naveen on 17/04/18
*/
public class AppLifeCycleHandler
implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
AppLifeCycleCallback appLifeCycleCallback;
boolean appInForeground;
public AppLifeCycleHandler(AppLifeCycleCallback appLifeCycleCallback) {
this.appLifeCycleCallback = appLifeCycleCallback;
}
@Override
public void onActivityResumed(Activity activity) {
if (!appInForeground) {
appInForeground = true;
appLifeCycleCallback.onAppForeground();
}
}
@Override
public void onTrimMemory(int i) {
if (i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
appInForeground = false;
appLifeCycleCallback.onAppBackground();
}
}
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onConfigurationChanged(Configuration configuration) {
}
@Override
public void onLowMemory() {
}
interface AppLifeCycleCallback {
void onAppBackground();
void onAppForeground();
}
}
Di kelas Anda yang meluas Application
implement AppLifeCycleCallback
untuk mendapatkan callback ketika aplikasi beralih antara latar depan dan latar belakang. Sesuatu seperti di bawah ini.
public class BaseApplication extends Application implements AppLifeCycleHandler.AppLifeCycleCallback{
@Override
public void onCreate() {
super.onCreate();
AppLifeCycleHandler appLifeCycleHandler = new AppLifeCycleHandler(this);
registerActivityLifecycleCallbacks(appLifeCycleHandler);
registerComponentCallbacks(appLifeCycleHandler);
}
@Override
public void onAppBackground() {
Log.d("LifecycleEvent", "onAppBackground");
}
@Override
public void onAppForeground() {
Log.d("LifecycleEvent", "onAppForeground");
}
}
Semoga ini membantu.
EDIT Sebagai alternatif, Anda sekarang dapat menggunakan komponen arsitektur sadar siklus hidup.
Karena saya tidak menemukan pendekatan apa pun, yang juga menangani rotasi tanpa memeriksa perangko waktu, saya pikir saya juga membagikan bagaimana kami sekarang melakukannya di aplikasi kami. Satu-satunya tambahan untuk jawaban ini https://stackoverflow.com/a/42679191/5119746 adalah, bahwa kami juga mempertimbangkan orientasi tersebut.
class MyApplication : Application(), Application.ActivityLifecycleCallbacks {
// Members
private var mAppIsInBackground = false
private var mCurrentOrientation: Int? = null
private var mOrientationWasChanged = false
private var mResumed = 0
private var mPaused = 0
Kemudian, untuk callback kami memiliki resume terlebih dahulu:
// ActivityLifecycleCallbacks
override fun onActivityResumed(activity: Activity?) {
mResumed++
if (mAppIsInBackground) {
// !!! App came from background !!! Insert code
mAppIsInBackground = false
}
mOrientationWasChanged = false
}
Dan padaAktivitas Berhenti:
override fun onActivityStopped(activity: Activity?) {
if (mResumed == mPaused && !mOrientationWasChanged) {
// !!! App moved to background !!! Insert code
mAppIsInBackground = true
}
Dan kemudian, inilah tambahan: Memeriksa perubahan orientasi:
override fun onConfigurationChanged(newConfig: Configuration) {
if (newConfig.orientation != mCurrentOrientation) {
mCurrentOrientation = newConfig.orientation
mOrientationWasChanged = true
}
super.onConfigurationChanged(newConfig)
}
Itu dia. Semoga ini bisa membantu seseorang :)
Kami dapat memperluas solusi ini menggunakan LiveData
:
class AppForegroundStateLiveData : LiveData<AppForegroundStateLiveData.State>() {
private var lifecycleListener: LifecycleObserver? = null
override fun onActive() {
super.onActive()
lifecycleListener = AppLifecycleListener().also {
ProcessLifecycleOwner.get().lifecycle.addObserver(it)
}
}
override fun onInactive() {
super.onInactive()
lifecycleListener?.let {
this.lifecycleListener = null
ProcessLifecycleOwner.get().lifecycle.removeObserver(it)
}
}
internal inner class AppLifecycleListener : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onMoveToForeground() {
value = State.FOREGROUND
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onMoveToBackground() {
value = State.BACKGROUND
}
}
enum class State {
FOREGROUND, BACKGROUND
}
}
Sekarang kita bisa berlangganan LiveData ini dan menangkap acara yang diperlukan. Sebagai contoh:
appForegroundStateLiveData.observeForever { state ->
when(state) {
AppForegroundStateLiveData.State.FOREGROUND -> { /* app move to foreground */ }
AppForegroundStateLiveData.State.BACKGROUND -> { /* app move to background */ }
}
}
Jawaban ini sepertinya tidak benar. Metode-metode ini juga disebut ketika aktivitas lain dimulai dan berakhir. Yang bisa Anda lakukan adalah menjaga bendera global (ya, global buruk :) dan atur ini menjadi true setiap kali Anda memulai aktivitas baru. Setel ke false di onCreate setiap aktivitas. Lalu, di onPause Anda memeriksa tanda ini. Jika itu salah, aplikasi Anda masuk ke latar belakang, atau terbunuh.