ตามพื้นหลังฉันหมายถึงไม่มีกิจกรรมของแอปพลิเคชันที่ผู้ใช้สามารถมองเห็นได้ในตอนนี้?
ตามพื้นหลังฉันหมายถึงไม่มีกิจกรรมของแอปพลิเคชันที่ผู้ใช้สามารถมองเห็นได้ในตอนนี้?
คำตอบ:
มีสองสามวิธีในการตรวจสอบว่าแอปพลิเคชันของคุณทำงานในพื้นหลังหรือไม่ แต่มีเพียงแอปพลิเคชั่นเดียวที่เชื่อถือได้อย่างสมบูรณ์:
ทางออกที่เหมาะสม (หน่วยกิตไปแดน , CommonsWareและNeTeInStEiN )
ติดตามการแสดงผลของแอพลิเคชันของคุณได้ด้วยตัวเองโดยใช้Activity.onPause, Activity.onResumeวิธีการ เก็บสถานะ "การมองเห็น" ในคลาสอื่น ตัวเลือกที่ดีคือการนำไปใช้ของคุณเองApplicationหรือ a Service(นอกจากนี้ยังมีรูปแบบต่าง ๆของโซลูชันนี้หากคุณต้องการตรวจสอบการมองเห็นกิจกรรมจากบริการ)
ตัวอย่าง
ใช้Applicationคลาสที่กำหนดเอง(สังเกตisActivityVisible()วิธีสแตติก)
public class MyApplication extends Application {
public static boolean isActivityVisible() {
return activityVisible;
}
public static void activityResumed() {
activityVisible = true;
}
public static void activityPaused() {
activityVisible = false;
}
private static boolean activityVisible;
}
ลงทะเบียนคลาสแอปพลิเคชันของคุณในAndroidManifest.xml:
<application
android:name="your.app.package.MyApplication"
android:icon="@drawable/icon"
android:label="@string/app_name" >
เพิ่มonPauseและเพิ่มonResumeลงActivityในทุกโครงการ (คุณอาจสร้างบรรพบุรุษร่วมกันสำหรับกิจกรรมของคุณหากคุณต้องการ แต่ถ้ากิจกรรมของคุณได้ขยายออกไปจากMapActivity/ ListActivityฯลฯ แล้วคุณยังต้องเขียนสิ่งต่อไปนี้ด้วยตนเอง):
@Override
protected void onResume() {
super.onResume();
MyApplication.activityResumed();
}
@Override
protected void onPause() {
super.onPause();
MyApplication.activityPaused();
}
อัปเดต
ActivityLifecycleCallbacksถูกเพิ่มใน API ระดับ 14 (Android 4.0) คุณสามารถใช้พวกเขาเพื่อติดตามว่าผู้ใช้สามารถมองเห็นกิจกรรมของแอปพลิเคชันของคุณหรือไม่ ตรวจสอบคำตอบของ Cornstalksด้านล่างเพื่อดูรายละเอียด
ฉันใช้ผิดเพื่อแนะนำวิธีแก้ไขปัญหาต่อไปนี้:
คุณสามารถตรวจสอบแอปพลิเคชันเบื้องหน้า / พื้นหลัง
ActivityManager.getRunningAppProcesses()ซึ่งส่งกลับรายการของเรกRunningAppProcessInfoคอร์ด เมื่อต้องการตรวจสอบว่าแอปพลิเคชันของคุณอยู่ในRunningAppProcessInfo.importanceฟิลด์ตรวจสอบเบื้องหน้าเพื่อดูว่ามีความเท่าเทียมกันRunningAppProcessInfo.IMPORTANCE_FOREGROUNDในขณะที่RunningAppProcessInfo.processNameเท่ากับชื่อแพคเกจแอปพลิเคชันของคุณนอกจากนี้ถ้าคุณโทร
ActivityManager.getRunningAppProcesses()จากเธรด UI แอปพลิเคชันของคุณมันจะให้ความสำคัญIMPORTANCE_FOREGROUNDกับงานของคุณไม่ว่าจะอยู่ในเบื้องหน้าหรือไม่ก็ตาม เรียกว่าในเธรดพื้นหลัง (ตัวอย่างเช่นผ่านAsyncTask) และมันจะกลับผลลัพธ์ที่ถูกต้อง
ในขณะที่วิธีนี้อาจใช้งานได้ (และใช้งานได้จริงในเวลาส่วนใหญ่) ฉันขอแนะนำอย่างยิ่งให้ไม่ใช้งาน และนี่คือเหตุผล ดังที่ Dianne Hackborn เขียนว่า :
API เหล่านี้ไม่ได้มีไว้สำหรับแอปพลิเคชันในการอิงการไหลของ UI แต่จะทำสิ่งต่าง ๆ เช่นแสดงแอพที่กำลังรันหรือตัวจัดการงานหรือผู้ใช้
ใช่มีรายการเก็บไว้ในหน่วยความจำสำหรับสิ่งเหล่านี้ อย่างไรก็ตามจะถูกปิดในกระบวนการอื่นจัดการโดยเธรดที่แยกจากคุณและไม่ใช่สิ่งที่คุณสามารถเชื่อถือได้ (a) การเห็นในเวลาเพื่อทำการตัดสินใจที่ถูกต้องหรือ (b) มีภาพที่สอดคล้องกันในเวลาที่คุณกลับมา บวกกับการตัดสินใจเกี่ยวกับกิจกรรม "ถัดไป" ที่จะไปทำ ณ จุดที่สวิตช์เกิดขึ้นเสมอและจะไม่เกิดขึ้นจนกว่าจะถึงจุดที่แน่นอน (ซึ่งสถานะกิจกรรมถูกล็อคลงเพื่อทำการสวิตช์) รู้จริงแน่นอนว่าสิ่งต่อไปจะเป็นอย่างไร
และการดำเนินการและพฤติกรรมระดับโลกที่นี่ไม่ได้รับประกันว่าจะยังคงเหมือนเดิมในอนาคต
ฉันหวังว่าฉันจะอ่านมันก่อนที่ฉันจะโพสต์คำตอบเกี่ยวกับ SO แต่หวังว่ามันจะไม่สายเกินไปที่จะยอมรับข้อผิดพลาดของฉัน
อีกวิธีหนึ่งที่ไม่ถูกต้องห้องสมุด
Droid-Fu ที่กล่าวถึงในหนึ่งในคำตอบที่ใช้ActivityManager.getRunningTasksสำหรับisApplicationBroughtToBackgroundวิธีการของมัน ดูความคิดเห็นของ Dianne ด้านบนและไม่ใช้วิธีนั้น
OnStop isActivityVisible
คำตอบ user1269737 เป็นที่เหมาะสม (Google / Android ได้รับการอนุมัติ) วิธีการที่จะทำเช่นนี้ ไปอ่านคำตอบของพวกเขาและให้ +1
ฉันจะทิ้งคำตอบดั้งเดิมไว้ที่นี่เพื่อเห็นแก่ลูกหลาน นี่คือการกลับมาที่ดีที่สุดในปี 2012 แต่ตอนนี้ Android ได้รับการสนับสนุนที่เหมาะสมสำหรับเรื่องนี้
คีย์กำลังใช้งานActivityLifecycleCallbacks(โปรดทราบว่าต้องใช้ Android API ระดับ 14 (Android 4.0)) เพียงตรวจสอบว่าจำนวนกิจกรรมที่หยุดแล้วเท่ากับจำนวนกิจกรรมที่เริ่ม หากพวกเขาเท่ากันใบสมัครของคุณจะถูก background หากมีกิจกรรมเริ่มต้นมากขึ้นแอปพลิเคชันของคุณจะยังคงปรากฏให้เห็น หากมีการดำเนินการต่อมากกว่ากิจกรรมที่หยุดชั่วคราวแอปพลิเคชันของคุณไม่เพียงมองเห็นได้ แต่ยังอยู่ในเบื้องหน้า มี 3 สถานะหลักที่กิจกรรมของคุณสามารถเข้าได้คือ: มองเห็นได้และในเบื้องหน้ามองเห็นได้ แต่ไม่อยู่ในเบื้องหน้าและไม่สามารถมองเห็นได้และไม่ปรากฏในเบื้องหน้า (เช่นในพื้นหลัง)
สิ่งที่ดีมากเกี่ยวกับวิธีการนี้ก็คือว่ามันไม่ได้มีประเด็นที่ไม่ตรงกันgetRunningTasks()ไม่ แต่คุณยังไม่ได้มีการปรับเปลี่ยนทุกActivityในใบสมัครของคุณไปยังชุด / สิ่งที่ไม่มีการตั้งค่าใน/onResumed() onPaused()เป็นโค้ดเพียงไม่กี่บรรทัดที่มีอยู่ในตัวและทำงานได้ตลอดทั้งแอปพลิเคชันของคุณ นอกจากนี้ยังไม่จำเป็นต้องใช้การอนุญาตแบบขี้ขลาด
MyLifecycleHandler.java:
public class MyLifecycleHandler implements ActivityLifecycleCallbacks {
// I use four separate variables here. You can, of course, just use two and
// increment/decrement them instead of using four and incrementing them all.
private int resumed;
private int paused;
private int started;
private int stopped;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
}
@Override
public void onActivityPaused(Activity activity) {
++paused;
android.util.Log.w("test", "application is in foreground: " + (resumed > paused));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
}
@Override
public void onActivityStopped(Activity activity) {
++stopped;
android.util.Log.w("test", "application is visible: " + (started > stopped));
}
// If you want a static function you can use to check if your application is
// foreground/background, you can use the following:
/*
// Replace the four variables above with these four
private static int resumed;
private static int paused;
private static int started;
private static int stopped;
// And these two public static functions
public static boolean isApplicationVisible() {
return started > stopped;
}
public static boolean isApplicationInForeground() {
return resumed > paused;
}
*/
}
MyApplication.java:
// Don't forget to add it to your manifest by doing
// <application android:name="your.package.MyApplication" ...
public class MyApplication extends Application {
@Override
public void onCreate() {
// Simply add the handler, and that's it! No need to add any code
// to every activity. Everything is contained in MyLifecycleHandler
// with just a few lines of code. Now *that's* nice.
registerActivityLifecycleCallbacks(new MyLifecycleHandler());
}
}
@Mewzer ได้ถามคำถามที่ดีเกี่ยวกับวิธีการนี้ที่ฉันต้องการตอบกลับในคำตอบนี้สำหรับทุกคน:
onStop()ไม่ได้ถูกเรียกในสถานการณ์ที่หน่วยความจำเหลือน้อย นั่นเป็นปัญหาใช่ไหม
ไม่เอกสารสำหรับการonStop()พูด:
โปรดทราบว่าวิธีนี้อาจไม่เคยถูกเรียกใช้ในสถานการณ์ที่หน่วยความจำเหลือน้อยซึ่งระบบมีหน่วยความจำไม่เพียงพอที่จะทำให้กระบวนการของกิจกรรมของคุณทำงานหลังจากที่มีการเรียกใช้เมธอด onPause ()
กุญแจสำคัญในที่นี้คือ "ทำให้กระบวนการของกิจกรรมของคุณทำงานต่อไป ... " ถ้าถึงสถานการณ์ความทรงจำไม่ถึงขั้นตอนนี้กระบวนการของคุณก็จะถูกทำลาย (ไม่ใช่แค่กิจกรรมของคุณ) ซึ่งหมายความว่าวิธีการตรวจสอบ backgrounded-ness นี้ยังคงใช้ได้เนื่องจากก) คุณไม่สามารถตรวจสอบพื้นหลังได้หากกระบวนการของคุณถูกฆ่าและ b) หากกระบวนการของคุณเริ่มต้นอีกครั้ง (เนื่องจากมีการสร้างกิจกรรมใหม่) สมาชิก ตัวแปร (ไม่ว่าจะคงที่หรือไม่) เพื่อจะถูกรีเซ็ตMyLifecycleHandler0
สิ่งนี้ใช้ได้กับการเปลี่ยนแปลงการกำหนดค่าหรือไม่
โดยค่าเริ่มต้นไม่มี คุณต้องกำหนดอย่างชัดเจนconfigChanges=orientation|screensize( |ด้วยสิ่งอื่นที่คุณต้องการ) ในไฟล์รายการและจัดการการเปลี่ยนแปลงการกำหนดค่ามิฉะนั้นกิจกรรมของคุณจะถูกทำลายและสร้างใหม่ onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResumeหากคุณไม่ได้ตั้งค่านี้วิธีการกิจกรรมของคุณจะถูกเรียกในลำดับนี้: อย่างที่คุณเห็นไม่มีการเหลื่อมกัน (โดยปกติกิจกรรมสองอย่างซ้อนทับกันสั้นมากเมื่อสลับระหว่างสองซึ่งเป็นวิธีการตรวจจับการแบ็คกราวน์พื้นหลังนี้) เพื่อให้ได้สิ่งนี้คุณต้องตั้งค่าconfigChangesเพื่อไม่ให้กิจกรรมของคุณถูกทำลาย โชคดีที่ฉันต้องตั้งค่าconfigChangesมีอยู่แล้วในโครงการทั้งหมดของฉันเพราะมันไม่เป็นที่พึงปรารถนาสำหรับกิจกรรมทั้งหมดของฉันที่จะถูกทำลายบนหน้าจอหมุน / ปรับขนาดดังนั้นฉันไม่เคยพบว่าสิ่งนี้เป็นปัญหา (ขอบคุณ dpimka สำหรับการรีเฟรชความทรงจำของฉันและแก้ไขฉัน!)
หมายเหตุหนึ่ง:
เมื่อฉันพูดว่า "พื้นหลัง" ที่นี่ในคำตอบนี้ฉันหมายถึง "แอพของคุณจะไม่ปรากฏอีกต่อไป" กิจกรรม Android สามารถมองเห็นได้ แต่ไม่อยู่ในเบื้องหน้า (ตัวอย่างเช่นหากมีการซ้อนทับการแจ้งเตือนที่โปร่งใส) นั่นเป็นเหตุผลที่ฉันได้อัปเดตคำตอบนี้เพื่อสะท้อนว่า
มันเป็นสิ่งสำคัญที่จะรู้ว่า Android มีช่วงเวลาที่ถูกทอดทิ้งแปลกเมื่อมีการเปลี่ยนกิจกรรมที่ไม่มีอะไรในเบื้องหน้า ด้วยเหตุผลนี้หากคุณตรวจสอบว่าแอปพลิเคชันของคุณอยู่ในเบื้องหน้าเมื่อสลับระหว่างกิจกรรม (ในแอปเดียวกัน) คุณจะได้รับแจ้งว่าคุณไม่ได้อยู่ในเบื้องหน้า (แม้ว่าแอปของคุณจะยังเป็นแอปที่ใช้งานอยู่ )
คุณสามารถตรวจสอบถ้า app ของคุณอยู่ในเบื้องหน้าในของคุณActivity's onPause()วิธีการหลังจากที่ super.onPause()แค่จำรัฐที่ไม่ถูกต้องที่ฉันเพิ่งพูดถึง
คุณสามารถตรวจสอบว่าแอปของคุณจะมองเห็นได้ (คือถ้ามันไม่ได้อยู่ในพื้นหลัง) ในของคุณActivity's onStop()วิธีการหลังจากที่ super.onStop()
onStop() super.onStop()ไม่ต้องตรวจสอบสำหรับ backgrounding onPause()ใน
GOOGLE SOLUTION - ไม่ใช่แฮ็คเหมือนโซลูชันก่อนหน้า ใช้ProcessLifecycleOwner
Kotlin:
class ArchLifecycleApp : Application(), LifecycleObserver {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded() {
//App in background
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded() {
// App in foreground
}
}
Java:
public class ArchLifecycleApp extends Application implements LifecycleObserver {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onAppBackgrounded() {
//App in background
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppForegrounded() {
// App in foreground
}
}
ใน app.gradle
dependencies {
...
implementation "android.arch.lifecycle:extensions:1.1.0"
//New Android X dependency is this -
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
}
allprojects {
repositories {
...
google()
jcenter()
maven { url 'https://maven.google.com' }
}
}
คุณสามารถอ่านเพิ่มเติมเกี่ยวกับส่วนประกอบของวงจรชีวิตที่เกี่ยวข้องได้ที่นี่ - https://developer.android.com/topic/lไลบรารี/architecture /lifecycle
companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }จากนั้นคุณจะได้สถานะพื้นหน้าด้วยArchLifecycleApp.isForeground()
The LifecycleOwner for the whole application process. Note that if your application has multiple processes, this provider does not know about other processes. สิ่งนี้ไม่ทำงานกับmultiple processesแอพมี api บางอย่างที่เราสามารถทำได้อย่างงดงามหรือไม่?
เริ่มต้นไลบรารีการสนับสนุนเวอร์ชัน 26 คุณสามารถใช้ProcessLifecycleOwnerเพียงเพิ่มไปยังการพึ่งพาของคุณเช่นที่อธิบายไว้ที่นี่ตัวอย่างเช่น:
dependencies {
def lifecycle_version = "1.1.1"
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
// alternatively - Lifecycles only (no ViewModel or LiveData).
// Support library depends on this lightweight import
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" // use kapt for Kotlin
}
และจากนั้นก็สอบถามProcessLifecycleOwnerเมื่อใดก็ตามที่คุณต้องการสำหรับสถานะแอปตัวอย่าง:
//Check if app is in background
ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED;
//Check if app is in foreground
ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
ตั้งแต่ Android API 16 มีวิธีง่าย ๆ ในการตรวจสอบว่าแอปอยู่เบื้องหน้าหรือไม่ มันอาจจะไม่สามารถจะเข้าใจผิดได้ แต่ไม่มีวิธีการใน Android จะเข้าใจผิดได้ วิธีนี้ดีพอที่จะใช้เมื่อบริการของคุณได้รับการอัปเดตจากเซิร์ฟเวอร์และต้องตัดสินใจว่าจะแสดงการแจ้งเตือนหรือไม่ (เพราะถ้า UI อยู่เบื้องหน้าผู้ใช้จะสังเกตเห็นการอัปเดตโดยไม่มีการแจ้งเตือน)
RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
JobServiceตรวจสอบว่าบริการกำลังทำงานในพื้นหลัง
คำตอบของไอดอลนั้นเกิดข้อผิดพลาดและมีความซับซ้อนมากขึ้นแม้ว่าจะยกเลิกการตรวจสอบแอปพลิเคชัน Android ในเบื้องหน้าหรือไม่? และที่นี่การกำหนดแอปพลิเคชันเบื้องหน้าปัจจุบันจากงานหรือบริการเบื้องหลัง
มีวิธีที่ง่ายกว่านี้มากขึ้น:
บนBaseActivity ที่กิจกรรมทั้งหมดขยาย:
protected static boolean isVisible = false;
@Override
public void onResume()
{
super.onResume();
setVisible(true);
}
@Override
public void onPause()
{
super.onPause();
setVisible(false);
}
เมื่อใดก็ตามที่คุณต้องตรวจสอบถ้ามีกิจกรรมแอพลิเคชันของคุณอยู่ในเบื้องหน้าเพียงแค่ตรวจสอบ isVisible() ;
เพื่อทำความเข้าใจวิธีการนี้ให้ตรวจสอบคำตอบของวงจรชีวิตของกิจกรรมแบบเคียงข้างกัน: วงจรชีวิตของกิจกรรมแบบเคียงข้างกัน
Idolon's answer is error prone- น่าเสียดายที่ฉันต้องเห็นด้วยกับคุณ จากความคิดเห็นของ Dianne Hackborn ใน Google Groups ฉันได้อัปเดตคำตอบของฉันแล้ว โปรดตรวจสอบรายละเอียด
onPause, onStop, หรือonResumeเหตุการณ์ที่เรียกว่า แล้วคุณจะทำอย่างไรถ้าไม่มีเหตุการณ์เหล่านี้ถูกไล่ออก?!
ฉันลองใช้วิธีแก้ปัญหาที่แนะนำซึ่งใช้Application.ActivityLifecycleCallbacksและอื่น ๆ อีกมากมาย แต่ไม่ได้ผลตามที่คาดไว้ ขอบคุณSargeฉันจึงได้วิธีแก้ปัญหาที่ง่ายและตรงไปตรงมาซึ่งฉันอธิบายไว้ด้านล่าง
พวกเขาที่สำคัญของการแก้ปัญหาคือความเป็นจริงของการทำความเข้าใจว่าถ้าเรามี activitya และ ActivityB และเราเรียก ActivityB จาก activitya (และไม่โทร
ActivityA.finish) แล้ว ActivityB ของonStart()จะถูกเรียกว่าก่อนที่จะonStop()activitya
นั่นเป็นความแตกต่างที่สำคัญระหว่างonStop()และonPause()ไม่มีใครพูดถึงในบทความที่ฉันอ่าน
ดังนั้นตามพฤติกรรมวงจรชีวิตของกิจกรรมนี้คุณสามารถนับจำนวนครั้งonStart()และonPause()เรียกใช้ในโปรแกรมของคุณได้หลายครั้ง โปรดทราบว่าสำหรับแต่ละ Activityโปรแกรมของคุณคุณต้องแทนที่onStart()และonStop()เพื่อเพิ่ม / ลดตัวแปรสแตติกที่ใช้สำหรับการนับ ด้านล่างเป็นรหัสที่ใช้ตรรกะนี้ โปรดทราบว่าฉันกำลังใช้คลาสที่ขยายApplicationดังนั้นอย่าลืมประกาศManifest.xmlภายใน Application tag: android:name=".Utilities"ถึงแม้ว่ามันจะสามารถนำไปใช้งานได้โดยใช้คลาสที่กำหนดเองง่าย ๆ เช่นกัน
public class Utilities extends Application
{
private static int stateCounter;
public void onCreate()
{
super.onCreate();
stateCounter = 0;
}
/**
* @return true if application is on background
* */
public static boolean isApplicationOnBackground()
{
return stateCounter == 0;
}
//to be called on each Activity onStart()
public static void activityStarted()
{
stateCounter++;
}
//to be called on each Activity onStop()
public static void activityStopped()
{
stateCounter--;
}
}
ตอนนี้ในแต่ละกิจกรรมของโปรแกรมของเราเราควรแทนที่onStart()และonStop()และเพิ่ม / ลดลงตามที่แสดงด้านล่าง:
@Override
public void onStart()
{
super.onStart();
Utilities.activityStarted();
}
@Override
public void onStop()
{
Utilities.activityStopped();
if(Utilities.isApplicationOnBackground())
{
//you should want to check here if your application is on background
}
super.onStop();
}
ด้วยตรรกะนี้มี 2 กรณีที่เป็นไปได้:
stateCounter = 0 : จำนวนการหยุดเท่ากับจำนวนกิจกรรมที่เริ่มต้นซึ่งหมายความว่าแอปพลิเคชันทำงานบนพื้นหลังstateCounter > 0 : จำนวนการเริ่มต้นมีขนาดใหญ่กว่าจำนวนการหยุดซึ่งหมายความว่าแอปพลิเคชันทำงานบนพื้นหน้าประกาศ: stateCounter < 0จะหมายถึงว่ามีกิจกรรมที่หยุดมากกว่าแทนที่จะเริ่มซึ่งเป็นไปไม่ได้ หากคุณพบกรณีนี้หมายความว่าคุณไม่ได้เพิ่ม / ลดจำนวนตัวนับเท่าที่ควร
คุณพร้อมที่จะไป คุณควรตรวจสอบว่าใบสมัครของคุณอยู่ในพื้นหลังด้านในonStop()หรือไม่
if(Utilities.isApplicationOnBackground()) … Utilitiesเพราะมิฉะนั้นเฉพาะกิจกรรมที่เฉพาะเจาะจงจะตอบสนองต่อเหตุการณ์
ไม่มีทางที่คุณติดตามด้วยตัวคุณเองเพื่อกำหนดว่ากิจกรรมใด ๆ ของคุณสามารถมองเห็นได้หรือไม่ บางทีคุณควรพิจารณาถามคำถาม StackOverflow ใหม่โดยอธิบายว่าคุณพยายามทำอะไรจากประสบการณ์ของผู้ใช้ดังนั้นเราอาจให้แนวคิดการใช้งานทางเลือกแก่คุณ
Serviceจะถูกดำเนินการโดย ถ้าเป็นเช่นนั้นให้กิจกรรมของคุณแจ้งบริการตามที่ปรากฏและหายไป หากServiceกำหนดว่าไม่มีกิจกรรมที่มองเห็นได้และจะยังคงมีวิธีนั้นอยู่เป็นระยะเวลาหนึ่งให้หยุดการถ่ายโอนข้อมูลที่จุดหยุดตรรกะถัดไป ใช่นี่จะต้องใช้รหัสสำหรับแต่ละกิจกรรมของคุณ แต่ตอนนี้นั่นเป็น AFAIK ที่หลีกเลี่ยงไม่ได้
MyActivityClassสืบทอดจากและการใช้วิธีวงจรชีวิตและทำให้กิจกรรมทั้งหมดของคุณได้รับมรดกจากActivity MyActivityClassนี้จะไม่ทำงานPreferenceActivityหรือMapActivityแม้ว่า (ดูคำถามนี้ )
คุณสามารถใช้ComponentCallbacks2เพื่อตรวจสอบว่าแอปอยู่ในพื้นหลังหรือไม่ BTW การติดต่อกลับนี้มีเฉพาะใน API ระดับ 14 (Ice Cream Sandwich) และสูงกว่า
คุณจะได้รับวิธีการ:
public abstract void onTrimMemory (int level)
หากระดับComponentCallbacks2.TRIM_MEMORY_UI_HIDDENนั้นเป็นแอปที่อยู่ในพื้นหลัง
คุณสามารถนำอินเตอร์เฟสนี้ไปใช้กับactivity, serviceและอื่น ๆ ได้
public class MainActivity extends AppCompatActivity 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) {
// app is in background
}
}
}
การสร้างคำตอบบน @Cornstalks เพื่อรวมคุณสมบัติที่มีประโยชน์สองอย่าง
คุณสมบัติพิเศษ:
App.java
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(AppLifecycleHandler.getInstance());
}
}
AppLifecycleHandler.java
public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
private int resumed;
private int started;
private final String DebugName = "AppLifecycleHandler";
private boolean isVisible = false;
private boolean isInForeground = false;
private static AppLifecycleHandler instance;
public static AppLifecycleHandler getInstance() {
if (instance == null) {
instance = new AppLifecycleHandler();
}
return instance;
}
private AppLifecycleHandler() {
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
android.util.Log.w(DebugName, "onActivityResumed -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
setForeground((resumed > 0));
}
@Override
public void onActivityPaused(Activity activity) {
--resumed;
android.util.Log.w(DebugName, "onActivityPaused -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
setForeground((resumed > 0));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
android.util.Log.w(DebugName, "onActivityStarted -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
setVisible((started > 0));
}
@Override
public void onActivityStopped(Activity activity) {
--started;
android.util.Log.w(DebugName, "onActivityStopped -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
setVisible((started > 0));
}
private void setVisible(boolean visible) {
if (isVisible == visible) {
// no change
return;
}
// visibility changed
isVisible = visible;
android.util.Log.w(DebugName, "App Visiblility Changed -> application is visible: " + isVisible);
// take some action on change of visibility
}
private void setForeground(boolean inForeground) {
if (isInForeground == inForeground) {
// no change
return;
}
// in foreground changed
isInForeground = inForeground;
android.util.Log.w(DebugName, "App In Foreground Changed -> application is in foreground: " + isInForeground);
// take some action on change of in foreground
}
public static boolean isApplicationVisible() {
return AppLifecycleHandler.getInstance().started > 0;
}
public static boolean isApplicationInForeground() {
return AppLifecycleHandler.getInstance().resumed > 0;
}
}
ทางออกที่ดีที่สุดที่ฉันใช้กับตัวจับเวลา
คุณเริ่มจับเวลาใน onPause () และยกเลิกตัวจับเวลาเดียวกันใน onResume () มี 1 อินสแตนซ์ของตัวจับเวลา (โดยปกติจะกำหนดไว้ในคลาสแอปพลิเคชัน) ตัวจับเวลาถูกตั้งค่าให้เรียกใช้ Runnable หลังจาก 2 วินาที (หรือช่วงเวลาใดที่คุณคิดว่าเหมาะสม) เมื่อตัวจับเวลาเริ่มทำงานคุณตั้งค่าสถานะที่ทำเครื่องหมายแอปพลิเคชันว่าเป็นพื้นหลัง
ในเมธอด onResume () ก่อนที่คุณจะยกเลิกตัวจับเวลาคุณสามารถสอบถามการตั้งค่าพื้นหลังเพื่อดำเนินการเริ่มต้นใด ๆ (เช่นเริ่มการดาวน์โหลดหรือเปิดใช้งานบริการตำแหน่ง)
โซลูชันนี้ช่วยให้คุณมีกิจกรรมหลายอย่างใน back stack และไม่ต้องการการอนุญาตใด ๆ
โซลูชันนี้ทำงานได้ดีหากคุณใช้ Event Bus เช่นกันเนื่องจากตัวจับเวลาของคุณสามารถไล่เหตุการณ์และส่วนต่าง ๆ ของแอพของคุณสามารถตอบสนองได้
หากคุณเปิดใช้งานการตั้งค่าของนักพัฒนา "อย่าเก็บการกระทำ" - ตรวจสอบเฉพาะกิจกรรมที่สร้างไว้ไม่เพียงพอ คุณต้องตรวจสอบisSaveInstanceStateด้วย วิธีการที่กำหนดเองของฉันคือisApplicationRunning () การตรวจสอบคือแอพ android กำลังทำงาน:
นี่คือรหัสการทำงานของฉัน:
public class AppLifecycleService implements Application.ActivityLifecycleCallbacks {
private int created;
private boolean isSaveInstanceState;
private static AppLifecycleService instance;
private final static String TAG = AppLifecycleService.class.getName();
public static AppLifecycleService getInstance() {
if (instance == null) {
instance = new AppLifecycleService();
}
return instance;
}
public static boolean isApplicationRunning() {
boolean isApplicationRunning = true;
if (getCountCreatedActvities() == 0 && !isSaveInstanceState()) {
isApplicationRunning = false;
}
return isApplicationRunning;
}
public static boolean isSaveInstanceState() {
return AppLifecycleService.getInstance().isSaveInstanceState;
}
public static int getCountCreatedActvities() {
return AppLifecycleService.getInstance().created;
}
private AppLifecycleService() {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
this.isSaveInstanceState = true;
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
++created;
}
@Override
public void onActivityDestroyed(Activity activity) {
--created;
}
@Override
public void onActivityResumed(Activity activity) { }
@Override
public void onActivityPaused(Activity activity) { }
@Override
public void onActivityStarted(Activity activity) { }
@Override
public void onActivityStopped(Activity activity) { }
}
ทางออกที่ถูกต้องเพียงข้อเดียว:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
MyApp.mainActivity = this;
super.onCreate(savedInstanceState);
...
}
public class MyApp extends Application implements LifecycleObserver {
public static MainActivity mainActivity = null;
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onAppBackgrounded() {
// app in background
if (mainActivity != null) {
...
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void onAppForegrounded() {
// app in foreground
if (mainActivity != null) {
...
}
}
}
หากต้องการ piggyback เกี่ยวกับสิ่งที่ CommonsWare และ Key ได้กล่าวไว้คุณอาจขยายคลาสแอพพลิเคชั่นและให้กิจกรรมทั้งหมดของคุณเรียกว่าในเมธอด onPause / onResume สิ่งนี้จะช่วยให้คุณทราบว่ากิจกรรมใด (IES) ที่มองเห็นได้ แต่สิ่งนี้อาจจัดการได้ดีกว่า
คุณอธิบายรายละเอียดเกี่ยวกับสิ่งที่คุณมีในใจได้ไหม? เมื่อคุณพูดว่าทำงานในพื้นหลังคุณหมายถึงเพียงแค่ให้แอปพลิเคชันของคุณยังคงอยู่ในหน่วยความจำแม้ว่าจะไม่ได้อยู่บนหน้าจอในปัจจุบัน? คุณเคยใช้บริการเป็นวิธีที่ถาวรกว่าในการจัดการแอพของคุณเมื่อไม่ได้โฟกัสหรือไม่?
Applicationไม่ได้หรือonPause() onResume()
ฉันใช้งาน ActivityLifecycleCallbacks ของฉันเอง ฉันกำลังใช้ SherlockActivity แต่สำหรับคลาส Activity ปกติอาจใช้ได้
ก่อนอื่นฉันจะสร้างส่วนต่อประสานที่มีวิธีการทั้งหมดเพื่อติดตามวงจรชีวิตของกิจกรรม:
public interface ActivityLifecycleCallbacks{
public void onActivityStopped(Activity activity);
public void onActivityStarted(Activity activity);
public void onActivitySaveInstanceState(Activity activity, Bundle outState);
public void onActivityResumed(Activity activity);
public void onActivityPaused(Activity activity);
public void onActivityDestroyed(Activity activity);
public void onActivityCreated(Activity activity, Bundle savedInstanceState);
}
ประการที่สองฉันใช้อินเทอร์เฟซนี้ในคลาสของแอปพลิเคชันของฉัน:
public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
}
@Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
@Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
}
@Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
}
@Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
}
}
ประการที่สามฉันสร้างชั้นเรียนที่ยื่นออกมาจาก SherlockActivity:
public class MySherlockActivity extends SherlockActivity {
protected MyApplication nMyApplication;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
nMyApplication = (MyApplication) getApplication();
nMyApplication.onActivityCreated(this, savedInstanceState);
}
protected void onResume() {
// TODO Auto-generated method stub
nMyApplication.onActivityResumed(this);
super.onResume();
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
nMyApplication.onActivityPaused(this);
super.onPause();
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
nMyApplication.onActivityDestroyed(this);
super.onDestroy();
}
@Override
protected void onStart() {
nMyApplication.onActivityStarted(this);
super.onStart();
}
@Override
protected void onStop() {
nMyApplication.onActivityStopped(this);
super.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
nMyApplication.onActivitySaveInstanceState(this, outState);
super.onSaveInstanceState(outState);
}
}
ประการที่สี่คลาสทั้งหมดที่ขยายจาก SherlockActivity ฉันแทนที่ MySherlockActivity:
public class MainActivity extends MySherlockActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
ตอนนี้ใน logcat คุณจะเห็นบันทึกที่ตั้งโปรแกรมไว้ในส่วนต่อประสานที่เกิดขึ้นใน MyApplication
กิจกรรมจะหยุดชั่วคราวเมื่อไดอะล็อกมาเหนือดังนั้นโซลูชันที่แนะนำทั้งหมดจึงเป็นครึ่งโซลูชั่น คุณต้องสร้าง hooks สำหรับกล่องโต้ตอบด้วย
เนื่องจากยังไม่ได้กล่าวถึงฉันจะแนะนำให้ผู้อ่านสำรวจProcessLifecycleOwnerพร้อมใช้งานผ่านองค์ประกอบของสถาปัตยกรรม Android
ระบบแยกความแตกต่างระหว่างแอปพื้นหน้าและพื้นหลัง (คำจำกัดความของพื้นหลังเพื่อจุดประสงค์ในการ จำกัด บริการแตกต่างจากคำจำกัดความที่ใช้โดยการจัดการหน่วยความจำแอปอาจอยู่ในพื้นหลังซึ่งเกี่ยวข้องกับการจัดการหน่วยความจำแต่ในส่วนหน้า ถือว่าอยู่เบื้องหน้าหากสิ่งใดสิ่งหนึ่งต่อไปนี้เป็นจริง:
หากไม่มีเงื่อนไขเหล่านี้เป็นจริงแอปนั้นจะถือว่าอยู่ในพื้นหลัง
วิธีแก้ปัญหาอื่นสำหรับโพสต์เก่านี้ (สำหรับผู้ที่อาจช่วยได้):
<application android:name=".BaseApplication" ... >
public class BaseApplication extends Application {
private class Status {
public boolean isVisible = true;
public boolean isFocused = true;
}
private Map<Activity, Status> activities;
@Override
public void onCreate() {
activities = new HashMap<Activity, Status>();
super.onCreate();
}
private boolean hasVisibleActivity() {
for (Status status : activities.values())
if (status.isVisible)
return true;
return false;
}
private boolean hasFocusedActivity() {
for (Status status : activities.values())
if (status.isFocused)
return true;
return false;
}
public void onActivityCreate(Activity activity, boolean isStarting) {
if (isStarting && activities.isEmpty())
onApplicationStart();
activities.put(activity, new Status());
}
public void onActivityStart(Activity activity) {
if (!hasVisibleActivity() && !hasFocusedActivity())
onApplicationForeground();
activities.get(activity).isVisible = true;
}
public void onActivityWindowFocusChanged(Activity activity, boolean hasFocus) {
activities.get(activity).isFocused = hasFocus;
}
public void onActivityStop(Activity activity, boolean isFinishing) {
activities.get(activity).isVisible = false;
if (!isFinishing && !hasVisibleActivity() && !hasFocusedActivity())
onApplicationBackground();
}
public void onActivityDestroy(Activity activity, boolean isFinishing) {
activities.remove(activity);
if(isFinishing && activities.isEmpty())
onApplicationStop();
}
private void onApplicationStart() {Log.i(null, "Start");}
private void onApplicationBackground() {Log.i(null, "Background");}
private void onApplicationForeground() {Log.i(null, "Foreground");}
private void onApplicationStop() {Log.i(null, "Stop");}
}
public class MyActivity extends BaseActivity {...}
public class BaseActivity extends Activity {
private BaseApplication application;
@Override
protected void onCreate(Bundle state) {
application = (BaseApplication) getApplication();
application.onActivityCreate(this, state == null);
super.onCreate(state);
}
@Override
protected void onStart() {
application.onActivityStart(this);
super.onStart();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
application.onActivityWindowFocusChanged(this, hasFocus);
super.onWindowFocusChanged(hasFocus);
}
@Override
protected void onStop() {
application.onActivityStop(this, isFinishing());
super.onStop();
}
@Override
protected void onDestroy() {
application.onActivityDestroy(this, isFinishing());
super.onDestroy();
}
}
ดูความคิดเห็นในฟังก์ชั่น onActivityDestroyed
ทำงานกับ SDK เป้าหมายรุ่น 14>:
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;
public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
public static int active = 0;
@Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
active--;
}
@Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
active++;
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
@Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
active++;
}
@Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
active--;
}
@Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
active--;
// if active var here ever becomes zero, the app is closed or in background
if(active == 0){
...
}
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
active++;
}
}
คุณควรใช้การตั้งค่าที่ใช้ร่วมกันเพื่อจัดเก็บทรัพย์สินและดำเนินการโดยใช้บริการที่มีผลผูกพันจากกิจกรรมของคุณ หากคุณใช้การผูกเท่านั้น (นั่นคือไม่เคยใช้ startService) บริการของคุณจะทำงานก็ต่อเมื่อคุณผูกไว้ (ผูก onResume และ unbind onPause) ที่จะทำให้มันทำงานในเบื้องหน้าเท่านั้นและหากคุณต้องการทำงานต่อ พื้นหลังคุณสามารถใช้บริการเริ่มหยุดปกติ
ฉันคิดว่าคำถามนี้ควรชัดเจนกว่านี้ เมื่อไหร่? ที่ไหน? สถานการณ์เฉพาะของคุณคืออะไรที่คุณต้องการรู้ไหมหากแอปของคุณอยู่ในพื้นหลัง
ฉันเพิ่งแนะนำวิธีแก้ปัญหาของฉันในแบบของฉัน
ฉันทำสิ่งนี้โดยใช้ฟิลด์ "สำคัญ" ของRunningAppProcessInfoคลาสในทุกกิจกรรมของonStopแอปของฉันซึ่งสามารถทำได้โดยการBaseActivityจัดกิจกรรมอื่น ๆ เพื่อขยายซึ่งใช้onStopวิธีการตรวจสอบคุณค่าของ "ความสำคัญ" นี่คือรหัส:
public static boolean isAppRunning(Context context) {
ActivityManager activityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appProcesses = activityManager
.getRunningAppProcesses();
for (RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(context.getPackageName())) {
if (appProcess.importance != RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE) {
return true;
}
}
}
return false;
}
ฉันขอแนะนำให้อ่านหน้านี้: http://developer.android.com/reference/android/app/Activity.html
กล่าวโดยย่อกิจกรรมของคุณจะไม่ปรากฏอีกต่อไปหลังจากonStop()ถูกเรียก
onStop; ระหว่างonPauseและonStopก็มองเห็นแต่ไม่ได้อยู่เบื้องหน้า
onStop()ถูกเรียกอีกต่อไปซึ่งสอดคล้องกับสิ่งที่คุณเขียน
onPauseเรียกว่า: การแก้ไขล่าสุดได้แก้ไขคุณ
สิ่งที่เกี่ยวกับการใช้ getApplicationState (). isInForeground ()?
ในความคิดของฉันคำตอบมากมายแนะนำให้โหลดโค้ดจำนวนมากและทำให้เกิดความซับซ้อนและอ่านไม่ออก
เมื่อมีคนถามในดังนั้นวิธีการสื่อสารระหว่างServiceและActivityผมมักจะให้คำแนะนำการใช้LocalBroadcastManager
ทำไม?
ก็ด้วยการอ้างถึงเอกสาร:
คุณรู้ว่าข้อมูลที่คุณกำลังออกอากาศจะไม่ปล่อยให้แอปของคุณดังนั้นไม่จำเป็นต้องกังวลเกี่ยวกับการรั่วไหลของข้อมูลส่วนตัว
แอปพลิเคชันอื่นไม่สามารถส่งการออกอากาศเหล่านี้ไปยังแอปของคุณได้ดังนั้นคุณไม่จำเป็นต้องกังวลเกี่ยวกับช่องโหว่ด้านความปลอดภัยที่สามารถใช้ประโยชน์ได้
มันมีประสิทธิภาพมากกว่าการส่งการออกอากาศทั่วโลกผ่านระบบ
ไม่อยู่ในเอกสาร:
Activity, Application...ลักษณะ
ดังนั้นคุณต้องการตรวจสอบว่ามีสิ่งใดActivityอยู่ในเบื้องหน้าหรือไม่ คุณมักจะทำเช่นนั้นในServiceหรือApplicationชั้นเรียน
ซึ่งหมายความว่าActivityวัตถุของคุณกลายเป็นผู้ส่งสัญญาณ (ฉันเปิด / ปิด) ของคุณServiceในมืออื่น ๆ ที่จะกลายเป็นReceiverที่จะกลายเป็น
มีสองช่วงเวลาที่คุณอยู่Activityจะบอกคุณว่ามันจะไปในเบื้องหน้าหรือในพื้นหลัง (ใช่เพียงสอง ... ไม่ใช่ 6)
เมื่อสิ่งนั้นActivityเข้าสู่เบื้องหน้าonResume()เมธอดจะถูกทริกเกอร์ (เรียกอีกอย่างว่าหลังจากonCreate())
เมื่อActivityไปในด้านหลังonPause()เรียกว่า
นี่คือช่วงเวลาที่คุณActivityควรส่งสัญญาณไปยังคุณServiceเพื่ออธิบายสถานะของมัน
ในกรณีที่มีหลายค่าActivityให้จดจำเครื่องหมายActivityลงในพื้นหลังก่อนจากนั้นอีกอันหนึ่งจะเข้าสู่เบื้องหน้า
ดังนั้นสถานการณ์จะเป็น: *
Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON
Service/ Applicationก็จะให้ฟังสำหรับสัญญาณเหล่านั้นและดำเนินการตาม
รหัส (TLDR)
คุณServiceต้องดำเนินการBroadcastReceiverเพื่อฟังสัญญาณ
this.localBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// received data if Activity is on / off
}
}
public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL")
ลงทะเบียนReceiverในService::onCreate()
@Override
protected void onCreate() {
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}
ยกเลิกการลงทะเบียน Service::onDestroy()
@Override
protected void onDestroy() {
// I'm dead, no need to listen to anything anymore.
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}
ตอนนี้คุณActivityต้องสื่อสารสถานะของพวกเขา
ใน Activity::onResume()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
ใน Activity::onPause()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
สถานการณ์ที่ธรรมดามาก
ผู้พัฒนา: ฉันต้องการที่จะส่งข้อมูลจากฉันและปรับปรุง
ServiceActivityฉันจะตรวจสอบว่าActivityอยู่ในเบื้องหน้าได้อย่างไร
มักจะไม่จำเป็นต้องตรวจสอบว่าActivityอยู่ในเบื้องหน้าหรือไม่ เพียงแค่ส่งข้อมูลผ่านทางจากคุณLocalBroadcastManager ServiceหากเปิดActivityอยู่ระบบจะตอบกลับและดำเนินการ
สำหรับสถานการณ์ทั่วไปมากนี้Serviceจะกลายเป็นผู้ส่งและนำไปปฏิบัติActivityBroadcastReceiver
ดังนั้นสร้างในของคุณReceiver ActivityลงทะเบียนในและยกเลิกการลงทะเบียนในonResume() ไม่จำเป็นต้องใช้วิธีวงจรชีวิตอื่น ๆonPause()ไม่มีความจำเป็นต้องใช้วิธีการวงจรชีวิตอื่น
กำหนดReceiverพฤติกรรมในonReceive()(อัปเดต ListView ทำสิ่งนี้ทำเช่นนั้น ... )
วิธีนี้Activityจะฟังก็ต่อเมื่ออยู่ในเบื้องหน้าและจะไม่มีอะไรเกิดขึ้นหากอยู่ด้านหลังหรือถูกทำลาย
ในกรณีที่มีหลายตัวเลือกActivityใดActivityจะเปิดขึ้นจะตอบสนอง (ถ้าพวกเขายังใช้Receiver)
หากทุกคนอยู่ในพื้นหลังไม่มีใครตอบสนองและสัญญาณก็จะหายไป
ส่งข้อมูลจากServiceทางIntent(ดูรหัสด้านบน) โดยระบุรหัสสัญญาณ
fun isAppInForeground(): Boolean {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager ?: return false
val appProcesses = activityManager.runningAppProcesses ?: return false
val packageName = packageName
for (appProcess in appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName == packageName) {
return true
}
}
return false
}
ไม่มีคำตอบใดที่เหมาะสำหรับกรณีเฉพาะหากคุณทราบว่ากิจกรรม specfic อยู่ใน forground และหากคุณเป็น SDK ที่ไม่สามารถเข้าถึงแอปพลิเคชันได้โดยตรง สำหรับฉันฉันอยู่ในเธรดพื้นหลังที่เพิ่งได้รับการแจ้งเตือนแบบพุชสำหรับข้อความแชทใหม่และต้องการแสดงการแจ้งเตือนของระบบหากหน้าจอแชทไม่ได้อยู่ในเบื้องหน้า
การใช้สิ่งActivityLifecycleCallbacksที่ได้รับการแนะนำในคำตอบอื่น ๆ ฉันได้สร้างคลาส util ขนาดเล็กที่ใช้ตรรกะว่าMyActivityอยู่ในพื้นหน้าหรือไม่
class MyActivityMonitor(context: Context) : Application.ActivityLifecycleCallbacks {
private var isMyActivityInForeground = false
init {
(context.applicationContext as Application).registerActivityLifecycleCallbacks(this)
}
fun isMyActivityForeground() = isMyActivityInForeground
override fun onActivityPaused(activity: Activity?) {
if (activity is MyActivity) {
isMyActivityInForeground = false
}
}
override fun onActivityResumed(activity: Activity?) {
if (activity is MyActivity) {
isMyActivityInForeground = true
}
}
}
ในกิจกรรมของฉันบนรีโมตและ onPause ฉันเขียนบูลีน isVisible ให้กับ SharedPrefences
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
Editor editor = sharedPrefs.edit();
editor.putBoolean("visible", false);
editor.commit();
และอ่านที่อื่นเมื่อจำเป็นผ่าน
// Show a Toast Notification if App is not visible (ie in background. Not running, etc)
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
if(!sharedPrefs.getBoolean("visible", true)){...}
อาจจะไม่หรูหรา แต่ก็ใช้งานได้สำหรับฉัน ...
มันอาจจะสายเกินไปที่จะตอบ แต่ถ้ามีใครบางคนมาเยี่ยมชมแล้วนี่คือคำตอบที่ฉันแนะนำเหตุผลที่แอปต้องการทราบว่าสถานะอยู่ในพื้นหลังหรือมาเบื้องหน้าอาจมีหลายคน เพื่อแสดงขนมปังปิ้งและการแจ้งเตือนเมื่อผู้ใช้อยู่ใน BG 2. เพื่อทำงานบางอย่างสำหรับผู้ใช้ครั้งแรกที่มาจาก BG เช่นแบบสำรวจความคิดเห็นวาดใหม่ ฯลฯ
การแก้ปัญหาโดย Idolon และอื่น ๆ จะดูแลส่วนแรก แต่ไม่ได้สำหรับส่วนที่สอง หากมีหลายกิจกรรมในแอปของคุณและผู้ใช้กำลังสลับระหว่างกิจกรรมเหล่านั้นตามเวลาที่คุณอยู่ในกิจกรรมที่สองการตั้งค่าสถานะที่มองเห็นได้จะเป็นเท็จ ดังนั้นจึงไม่สามารถใช้งานได้อย่างแน่นอน
ฉันทำสิ่งที่ CommonsWare แนะนำ "ถ้าบริการกำหนดว่าไม่มีกิจกรรมที่มองเห็นได้และยังคงเป็นเช่นนั้นตามระยะเวลาให้หยุดการถ่ายโอนข้อมูลที่จุดหยุดตรรกะถัดไป"
บรรทัดตัวหนามีความสำคัญและสามารถใช้เพื่อให้ได้ไอเท็มที่สอง ดังนั้นสิ่งที่ฉันทำคือเมื่อฉันได้รับ onActivityPaused () อย่าเปลี่ยนการมองเห็นเป็นเท็จโดยตรงแทนที่จะมีการจับเวลา 3 วินาที (นั่นคือสูงสุดที่กิจกรรมถัดไปควรจะเปิดตัว) และถ้าไม่มี onActivityResumed ( ) โทรใน 3 วินาทีถัดไปเปลี่ยนเป็นเท็จ ในทำนองเดียวกัน onActivityResumed () หากมีตัวจับเวลาฉันจะยกเลิกมัน ในการสรุปผลที่มองเห็นได้คือ isAppInBackground
ขออภัยไม่สามารถคัดลอกรหัส ...
ฉันอยากจะแนะนำให้คุณใช้วิธีอื่นในการทำเช่นนี้
ฉันเดาว่าคุณต้องการที่จะแสดงหน้าจอเริ่มต้นขึ้นในขณะที่โปรแกรมกำลังเริ่มต้นถ้ามันทำงานอยู่ในแบ็กเอนด์แล้วอย่าแสดงมัน
แอปพลิเคชันของคุณสามารถเขียนเวลาปัจจุบันไปยังไฟล์ที่ต้องการได้อย่างต่อเนื่อง ขณะที่แอปพลิเคชันของคุณเริ่มต้นให้ตรวจสอบการประทับเวลาล่าสุดหาก current_time-last_time> ช่วงเวลาที่คุณระบุสำหรับการเขียนเวลาล่าสุดหมายความว่าแอปพลิเคชันของคุณหยุดทำงานไม่ว่าระบบหรือผู้ใช้จะถูกฆ่า