ตรวจสอบว่าแอปพลิเคชัน Android ทำงานในพื้นหลังหรือไม่


329

ตามพื้นหลังฉันหมายถึงไม่มีกิจกรรมของแอปพลิเคชันที่ผู้ใช้สามารถมองเห็นได้ในตอนนี้?



7
ฉันสับสนที่นี่ .. ทำไมหุ่นยนต์ไม่สามารถให้การแทนที่แบบง่าย ๆ ในคลาสแอปพลิเคชันสำหรับเรื่องนี้ เป็นการยากที่จะรู้สิ่งนี้ในระดับแพลตฟอร์มหรือไม่ @Override ป้องกันโมฆะ onApplicationSentToBackground () {}
Chuck D

2
@ChuckD - นั่นสมเหตุสมผลแล้วซึ่งเป็นสิ่งที่ Android SDK ดูเหมือนว่าจะหลีกเลี่ยงในบางครั้ง : /
ทำเครื่องหมาย


1
iOS มีสิ่งนี้ในโพดำไม่แน่ใจว่าทำไม Google จึงทำให้สิ่งนี้ยาก มันเป็นความต้องการที่ชัดเจน
Jerry Destremps

คำตอบ:


388

มีสองสามวิธีในการตรวจสอบว่าแอปพลิเคชันของคุณทำงานในพื้นหลังหรือไม่ แต่มีเพียงแอปพลิเคชั่นเดียวที่เชื่อถือได้อย่างสมบูรณ์:

  1. ทางออกที่เหมาะสม (หน่วยกิตไปแดน , 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ด้านล่างเพื่อดูรายละเอียด


  2. ฉันใช้ผิดเพื่อแนะนำวิธีแก้ไขปัญหาต่อไปนี้:

    คุณสามารถตรวจสอบแอปพลิเคชันเบื้องหน้า / พื้นหลังActivityManager.getRunningAppProcesses()ซึ่งส่งกลับรายการของเรกRunningAppProcessInfoคอร์ด เมื่อต้องการตรวจสอบว่าแอปพลิเคชันของคุณอยู่ในRunningAppProcessInfo.importanceฟิลด์ตรวจสอบเบื้องหน้าเพื่อดูว่ามีความเท่าเทียมกันRunningAppProcessInfo.IMPORTANCE_FOREGROUNDในขณะที่RunningAppProcessInfo.processNameเท่ากับชื่อแพคเกจแอปพลิเคชันของคุณ

    นอกจากนี้ถ้าคุณโทรActivityManager.getRunningAppProcesses()จากเธรด UI แอปพลิเคชันของคุณมันจะให้ความสำคัญIMPORTANCE_FOREGROUNDกับงานของคุณไม่ว่าจะอยู่ในเบื้องหน้าหรือไม่ก็ตาม เรียกว่าในเธรดพื้นหลัง (ตัวอย่างเช่นผ่านAsyncTask) และมันจะกลับผลลัพธ์ที่ถูกต้อง

    ในขณะที่วิธีนี้อาจใช้งานได้ (และใช้งานได้จริงในเวลาส่วนใหญ่) ฉันขอแนะนำอย่างยิ่งให้ไม่ใช้งาน และนี่คือเหตุผล ดังที่ Dianne Hackborn เขียนว่า :

    API เหล่านี้ไม่ได้มีไว้สำหรับแอปพลิเคชันในการอิงการไหลของ UI แต่จะทำสิ่งต่าง ๆ เช่นแสดงแอพที่กำลังรันหรือตัวจัดการงานหรือผู้ใช้

    ใช่มีรายการเก็บไว้ในหน่วยความจำสำหรับสิ่งเหล่านี้ อย่างไรก็ตามจะถูกปิดในกระบวนการอื่นจัดการโดยเธรดที่แยกจากคุณและไม่ใช่สิ่งที่คุณสามารถเชื่อถือได้ (a) การเห็นในเวลาเพื่อทำการตัดสินใจที่ถูกต้องหรือ (b) มีภาพที่สอดคล้องกันในเวลาที่คุณกลับมา บวกกับการตัดสินใจเกี่ยวกับกิจกรรม "ถัดไป" ที่จะไปทำ ณ จุดที่สวิตช์เกิดขึ้นเสมอและจะไม่เกิดขึ้นจนกว่าจะถึงจุดที่แน่นอน (ซึ่งสถานะกิจกรรมถูกล็อคลงเพื่อทำการสวิตช์) รู้จริงแน่นอนว่าสิ่งต่อไปจะเป็นอย่างไร

    และการดำเนินการและพฤติกรรมระดับโลกที่นี่ไม่ได้รับประกันว่าจะยังคงเหมือนเดิมในอนาคต

    ฉันหวังว่าฉันจะอ่านมันก่อนที่ฉันจะโพสต์คำตอบเกี่ยวกับ SO แต่หวังว่ามันจะไม่สายเกินไปที่จะยอมรับข้อผิดพลาดของฉัน

  3. อีกวิธีหนึ่งที่ไม่ถูกต้องห้องสมุด
    Droid-Fu ที่กล่าวถึงในหนึ่งในคำตอบที่ใช้ActivityManager.getRunningTasksสำหรับisApplicationBroughtToBackgroundวิธีการของมัน ดูความคิดเห็นของ Dianne ด้านบนและไม่ใช้วิธีนั้น


4
จะรู้ว่าถ้าคุณกดปุ่มบ้านหรือบาง app อื่น ๆ ได้รับโฟกัส: 1) ดำเนินการแก้ปัญหาที่ดี 2) ในการร้องขอไปยังOnStop isActivityVisible
Brais Gabin

28
น่าเสียดายที่โซลูชัน 'ถูกต้อง' ของคุณไม่ทำงานสำหรับฉัน พิจารณาว่าคุณหมุนเวียนกิจกรรมผ่านแอพของคุณ สิ่งที่เกิดขึ้นก็คือว่าสถานะ 'inForeground' ของคุณจะเป็นเช่นนี้: True, False (ระหว่างกิจกรรมที่ 1 ของ onPause และ onResume ของกิจกรรมที่ 2) จากนั้นเป็น True อีกครั้ง ฯลฯ คุณจะต้องมีการเรียงลำดับบางอย่าง
Radu

14
วิธีนี้ไม่ได้ผลหากคุณไม่สามารถควบคุมกิจกรรมทั้งหมดได้โดยตรง ตัวอย่างเช่นถ้าคุณมีกิจกรรมจาก sdk ของบุคคลที่สามหรือแม้กระทั่งเปิดตัวเจตนา ACTION_VIEW
user123321

66
Android เป็นซากที่เลวร้าย ไม่มีใครคิดว่ามีใครบางคนอาจต้องการเก็บข้อมูลระดับแอปไว้? ให้ฉันหยุดพัก

8
ดูเหมือนว่าคำตอบที่แท้จริงสำหรับคำถามนี้คือ "คุณไม่สามารถตรวจสอบได้อย่างถูกต้อง" วิธีการแก้ปัญหาที่เรียกว่า 'ถูกต้อง' นั้นเป็นวิธีแก้ปัญหาที่ดีที่สุดดังนั้นการใช้ ActivityLifecycleCallbacks คุณยังต้องพิจารณาการสลับระหว่างกิจกรรมที่จะลงทะเบียนเป็น "ไม่อยู่เบื้องหน้า" มันพัดใจของฉันว่าคุณไม่สามารถตรวจสอบสิ่งที่ง่ายเช่นนั้น ...
ซีรีน

263

อย่าใช้คำตอบนี้

คำตอบ 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()


1
สิ่งนี้ดูน่าสนใจ แต่จะเกิดอะไรขึ้นในสถานการณ์ที่หน่วยความจำเหลือน้อย ไม่รับประกันว่าจะเรียก onStop () เราสามารถเข้าสู่สถานการณ์ที่ไม่ได้เรียกใช้ onStop () และตัวนับที่หยุดทำงานไม่เพิ่มขึ้นหรือไม่ซึ่งหมายความว่าการตรวจสอบแบบแบ็คกราวน์ไม่น่าเชื่อถืออีกต่อไป? หรือสิ่งนี้จะไม่เกิดขึ้น?
Mewzer

1
นอกจากนี้สิ่งนี้จะเพิกเฉยต่อการเปลี่ยนแปลงการกำหนดค่าหรือไม่ หรือแอปพลิเคชันจะได้รับการพิจารณาเป็นพื้นหลังหากกิจกรรมนั้นถูกสร้างขึ้นอีกครั้งอันเป็นผลมาจากการเปลี่ยนแปลงการกำหนดค่า (เช่นเปลี่ยนการวางแนว)? ขออภัยสำหรับคำถาม แต่ฉันคิดว่าคุณกำลังเข้าสู่บางสิ่งบางอย่างและสนใจที่จะรู้ว่ามันใช้งานได้ในกรณีขอบ
Mewzer

1
@Mewzer: ฉันจะตอบเป็นความคิดเห็น แต่จะต้องใช้เวลาสักครู่เพื่อพิมพ์คำตอบเหล่านี้ดังนั้นโปรดกลับมาตรวจสอบอีกครั้งหลังจากนี้สักครู่แล้วฉันจะแก้ไขคำตอบของฉัน
Cornstalks

1
@Mewzer: คุณควรหาคำตอบตอนนี้ แจ้งให้เราทราบหากมีคำถามอื่น ๆ !
Cornstalks

2
@Mewzer: ฉันเพิ่งเพิ่มทราบว่าคุณอาจจะสนใจในโดยเฉพาะการตรวจสอบใน backgrounding. หลังจากที่onStop() super.onStop()ไม่ต้องตรวจสอบสำหรับ backgrounding onPause()ใน
Cornstalks

187

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


10
นี่ควรเป็นคำตอบที่ถูกต้องอย่างแน่นอน! มันใช้งานได้อย่างมีเสน่ห์: D
JaviOverflow

2
ทำงานได้อย่างสมบูรณ์แบบฉันยังแก้ไขอีกเล็กน้อยเพื่อให้สามารถเข้าถึงสถานะเบื้องหน้า / พื้นหลังได้ง่ายขึ้นนอกชั้นนี้: companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }จากนั้นคุณจะได้สถานะพื้นหน้าด้วยArchLifecycleApp.isForeground()
Jose Jet

2
โอ้ชายคนนี้ดีกว่าคำตอบเก่าของฉันมาก มี +1 จากฉัน ฉันอัปเดตคำตอบเพื่อชี้ให้คนอื่นเห็น
Cornstalks

2
แม้ว่านี่คือคำตอบที่ถูกต้องไม่จำเป็นต้องใช้การเรียกกลับคุณสามารถสอบถาม ProcessLifecycleOwner เมื่อใดก็ตามที่คุณต้องการ ตรวจสอบ stackoverflow.com/a/52678290/6600000
Keivan Esbati

2
ดังที่ doc กล่าวว่า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 บางอย่างที่เราสามารถทำได้อย่างงดงามหรือไม่?
acntwww

23

เริ่มต้นไลบรารีการสนับสนุนเวอร์ชัน 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);

2
ขอบคุณชายนี่คือวิธีที่ดีที่สุดและง่ายที่สุดที่เหมาะสมในส่วนใด ๆ ของรหัสของคุณเป็นพิเศษเมื่อใช้ fcm
Mihae Kheel

หากปิดแอปพลิเคชั่นอย่างสมบูรณ์แล้ววิธีการแรกจะกลับมาเป็นอย่างไร
Evgeniy Mishustin

@EvgeniyMishustin ที่ขึ้นอยู่กับสถานะปัจจุบันของแอปพลิเคชัน แต่โดยปกติแล้วคุณจะเห็น CREATED แล้วถูกทำลายและหลังจากนั้นคุณจะไม่ได้รับเหตุการณ์ใหม่
Keivan Esbati

ดังนั้นคำสั่ง "IF" ใดที่จะเห็นว่าแอป IF อยู่ในพื้นหลัง (เบื้องหน้า) ???
ekashking

@ekashking เพียงแค่ใส่คำสั่งทั้งหมดใน if-clause ตัวอย่างเช่น: if (ProcessLifecycleOwner.get (). getLifecycle (). getCurrentState (). isAtLeast (Lifecycle.State.STARTED)) => แอพอยู่ในเบื้องหน้า
Keivan Esbati

20

ตั้งแต่ Android API 16 มีวิธีง่าย ๆ ในการตรวจสอบว่าแอปอยู่เบื้องหน้าหรือไม่ มันอาจจะไม่สามารถจะเข้าใจผิดได้ แต่ไม่มีวิธีการใน Android จะเข้าใจผิดได้ วิธีนี้ดีพอที่จะใช้เมื่อบริการของคุณได้รับการอัปเดตจากเซิร์ฟเวอร์และต้องตัดสินใจว่าจะแสดงการแจ้งเตือนหรือไม่ (เพราะถ้า UI อยู่เบื้องหน้าผู้ใช้จะสังเกตเห็นการอัปเดตโดยไม่มีการแจ้งเตือน)

RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;

รหัสนี้ควรอยู่ในระดับบริการหรือคลาสอื่นเช่นคลาสแอปพลิเคชัน ขอบคุณมาก.
Woppi

.. ทุกที่ที่คุณต้องการใช้เป็นบรรทัดสุดท้ายเป็นเพียงบูลีนที่คุณตรวจสอบ
AO_

นี่เป็นวิธีการเดียวกันกับ AWS Android SDK สำหรับการแจ้งเตือนแบบพุช
spakmad

โปรดทราบว่า "คำจำกัดความของพื้นหลังเพื่อวัตถุประสงค์ในการ จำกัด การให้บริการนั้นแตกต่างจากคำจำกัดความที่ใช้โดยการจัดการหน่วยความจำแอปอาจอยู่ในพื้นหลังที่เกี่ยวข้องกับการจัดการหน่วยความจำ " developer.android.com/about/versions/oreo/background.html (
ARLabs

ขอบคุณมันใช้งานได้! ฉันสามารถใช้รหัสนี้ในการJobServiceตรวจสอบว่าบริการกำลังทำงานในพื้นหลัง
Michael Osofsky

17

คำตอบของไอดอลนั้นเกิดข้อผิดพลาดและมีความซับซ้อนมากขึ้นแม้ว่าจะยกเลิกการตรวจสอบแอปพลิเคชัน Android ในเบื้องหน้าหรือไม่? และที่นี่การกำหนดแอปพลิเคชันเบื้องหน้าปัจจุบันจากงานหรือบริการเบื้องหลัง

มีวิธีที่ง่ายกว่านี้มากขึ้น:

บนBaseActivity ที่กิจกรรมทั้งหมดขยาย:

protected static boolean isVisible = false;

 @Override
 public void onResume()
 {
     super.onResume();
     setVisible(true);
 }


 @Override
 public void onPause()
 {
     super.onPause();
     setVisible(false);
 }

เมื่อใดก็ตามที่คุณต้องตรวจสอบถ้ามีกิจกรรมแอพลิเคชันของคุณอยู่ในเบื้องหน้าเพียงแค่ตรวจสอบ isVisible() ;

เพื่อทำความเข้าใจวิธีการนี้ให้ตรวจสอบคำตอบของวงจรชีวิตของกิจกรรมแบบเคียงข้างกัน: วงจรชีวิตของกิจกรรมแบบเคียงข้างกัน


3
Idolon's answer is error prone- น่าเสียดายที่ฉันต้องเห็นด้วยกับคุณ จากความคิดเห็นของ Dianne Hackborn ใน Google Groups ฉันได้อัปเดตคำตอบของฉันแล้ว โปรดตรวจสอบรายละเอียด
Idolon

2
นี่ไม่ใช่วิธีแก้ปัญหาที่เข้าใจผิดได้เช่นกัน สถานการณ์หนึ่งคือหากผู้ใช้ดึงลงแผงการแจ้งเตือนแล้วไม่onPause, onStop, หรือonResumeเหตุการณ์ที่เรียกว่า แล้วคุณจะทำอย่างไรถ้าไม่มีเหตุการณ์เหล่านี้ถูกไล่ออก?!

นี่ทำให้ฉันมีคำถามนี้: stackoverflow.com/questions/33657102/…
Ruchir Baronia

น่าเศร้าที่รหัสนี้ใช้งานไม่ได้เมื่อเริ่มกิจกรรมเมื่อหน้าจอดับ ในกรณีนี้ onResume และ onPause เรียกว่า making isVisible = false
CoolMind

@CoolMind คุณช่วยอธิบายเกี่ยวกับกรณีการใช้ที่คุณจะเริ่มกิจกรรมในขณะที่อยู่เบื้องหลัง
neteinstein

11

ฉันลองใช้วิธีแก้ปัญหาที่แนะนำซึ่งใช้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 กรณีที่เป็นไปได้:

  1. stateCounter = 0 : จำนวนการหยุดเท่ากับจำนวนกิจกรรมที่เริ่มต้นซึ่งหมายความว่าแอปพลิเคชันทำงานบนพื้นหลัง
  2. stateCounter > 0 : จำนวนการเริ่มต้นมีขนาดใหญ่กว่าจำนวนการหยุดซึ่งหมายความว่าแอปพลิเคชันทำงานบนพื้นหน้า

ประกาศ: stateCounter < 0จะหมายถึงว่ามีกิจกรรมที่หยุดมากกว่าแทนที่จะเริ่มซึ่งเป็นไปไม่ได้ หากคุณพบกรณีนี้หมายความว่าคุณไม่ได้เพิ่ม / ลดจำนวนตัวนับเท่าที่ควร

คุณพร้อมที่จะไป คุณควรตรวจสอบว่าใบสมัครของคุณอยู่ในพื้นหลังด้านในonStop()หรือไม่


ผมจะย้ายไปif(Utilities.isApplicationOnBackground()) … Utilitiesเพราะมิฉะนั้นเฉพาะกิจกรรมที่เฉพาะเจาะจงจะตอบสนองต่อเหตุการณ์
ชื่อที่แสดง

10

ไม่มีทางที่คุณติดตามด้วยตัวคุณเองเพื่อกำหนดว่ากิจกรรมใด ๆ ของคุณสามารถมองเห็นได้หรือไม่ บางทีคุณควรพิจารณาถามคำถาม StackOverflow ใหม่โดยอธิบายว่าคุณพยายามทำอะไรจากประสบการณ์ของผู้ใช้ดังนั้นเราอาจให้แนวคิดการใช้งานทางเลือกแก่คุณ


2
ใน android เรามีการตั้งค่าที่เรียกว่า "ข้อมูลพื้นหลัง" การตั้งค่านี้เปลี่ยนการเชื่อมต่อข้อมูลพื้นหลังใด ๆ เมื่อแอปพลิเคชันทำงานในพื้นหลัง ฉันต้องการใช้การสลับ "ข้อมูลพื้นหลัง" สำหรับแอปพลิเคชันของฉันดังนั้นเมื่อผู้ใช้ไม่เห็นกิจกรรมของฉันฉันต้องการให้บริการของฉันหยุดทำการถ่ายโอนข้อมูลใด ๆ แต่เมื่อกิจกรรมของฉันดำเนินต่อ ถ่ายโอนข้อมูลต่อ
cppdev

1
@cppdev: หวังว่า "การถ่ายโอนข้อมูล" Serviceจะถูกดำเนินการโดย ถ้าเป็นเช่นนั้นให้กิจกรรมของคุณแจ้งบริการตามที่ปรากฏและหายไป หากServiceกำหนดว่าไม่มีกิจกรรมที่มองเห็นได้และจะยังคงมีวิธีนั้นอยู่เป็นระยะเวลาหนึ่งให้หยุดการถ่ายโอนข้อมูลที่จุดหยุดตรรกะถัดไป ใช่นี่จะต้องใช้รหัสสำหรับแต่ละกิจกรรมของคุณ แต่ตอนนี้นั่นเป็น AFAIK ที่หลีกเลี่ยงไม่ได้
CommonsWare

1
หากคุณต้องการที่จะหลีกเลี่ยงที่จะคัดลอกวางรหัสร่วมกันระหว่างกิจกรรมทั้งหมดของคุณคุณสามารถสร้างชั้นMyActivityClassสืบทอดจากและการใช้วิธีวงจรชีวิตและทำให้กิจกรรมทั้งหมดของคุณได้รับมรดกจากActivity MyActivityClassนี้จะไม่ทำงานPreferenceActivityหรือMapActivityแม้ว่า (ดูคำถามนี้ )
Guillaume Brunerie

@CommonsWare ฉันได้ลองกับ OnPause () OnResume () ว่ามันทำงานอยู่หรือไม่ แต่ถ้าแอพของฉันไม่ได้ดูในหน้าจอดูถ้ามันทำงานในพื้นหลังวิธีการตรวจสอบว่ามันใช้งานได้หรือไม่
Manoj

@CommonsWare ฉันได้ลองกับ OnPause () OnResume () ว่ามันทำงานอยู่หรือไม่ แต่ถ้าแอพของฉันไม่ได้ดูในหน้าจอดูถ้ามันทำงานในพื้นหลังวิธีการตรวจสอบว่ามันใช้งานได้หรือไม่
Manoj

5

คุณสามารถใช้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
     }
   }
}

1
ลองคำตอบของคุณแล้ว แต่ไม่น่าเชื่อถือ การเรียกกลับ onTrimMemory จะไม่ถูกเรียกเมื่อหน้าจอถูกล็อคหรือเมื่อกดปุ่ม "พลังงาน" เพื่อล็อคหน้าจอ และจะไม่ส่งคืน TRIM_MEMORY_UI_HIDDEN เสมอหากแอปของคุณปรากฏและคุณเปิดแอปอื่นผ่านการแจ้งเตือนแถบสถานะ ทางออกเดียวที่เชื่อถือได้คือการใช้ ActivityLifecycleCallbacks และปรับให้เข้ากับกรณีการใช้งาน
velval

4

การสร้างคำตอบบน @Cornstalks เพื่อรวมคุณสมบัติที่มีประโยชน์สองอย่าง

คุณสมบัติพิเศษ:

  • นำเสนอรูปแบบซิงเกิลเพื่อให้คุณสามารถทำสิ่งนี้ได้ทุกที่ในแอปพลิเคชัน: AppLifecycleHandler.isApplicationVisible () และ AppLifecycleHandler.isApplicationInForeground ()
  • เพิ่มการจัดการกิจกรรมที่ซ้ำกัน (ดูความคิดเห็น // ดำเนินการบางอย่างเกี่ยวกับการเปลี่ยนการมองเห็นและ // ดำเนินการบางอย่างเกี่ยวกับการเปลี่ยนแปลงในเบื้องหน้า)

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;
    }
}

3

ทางออกที่ดีที่สุดที่ฉันใช้กับตัวจับเวลา

คุณเริ่มจับเวลาใน onPause () และยกเลิกตัวจับเวลาเดียวกันใน onResume () มี 1 อินสแตนซ์ของตัวจับเวลา (โดยปกติจะกำหนดไว้ในคลาสแอปพลิเคชัน) ตัวจับเวลาถูกตั้งค่าให้เรียกใช้ Runnable หลังจาก 2 วินาที (หรือช่วงเวลาใดที่คุณคิดว่าเหมาะสม) เมื่อตัวจับเวลาเริ่มทำงานคุณตั้งค่าสถานะที่ทำเครื่องหมายแอปพลิเคชันว่าเป็นพื้นหลัง

ในเมธอด onResume () ก่อนที่คุณจะยกเลิกตัวจับเวลาคุณสามารถสอบถามการตั้งค่าพื้นหลังเพื่อดำเนินการเริ่มต้นใด ๆ (เช่นเริ่มการดาวน์โหลดหรือเปิดใช้งานบริการตำแหน่ง)

โซลูชันนี้ช่วยให้คุณมีกิจกรรมหลายอย่างใน back stack และไม่ต้องการการอนุญาตใด ๆ

โซลูชันนี้ทำงานได้ดีหากคุณใช้ Event Bus เช่นกันเนื่องจากตัวจับเวลาของคุณสามารถไล่เหตุการณ์และส่วนต่าง ๆ ของแอพของคุณสามารถตอบสนองได้


ฉันเริ่มคิดว่านี่เป็นทางออกที่ดีที่สุด (แต่โชคร้าย)
dhaag23

ใช่นี่เป็นทางออกที่ดีที่สุดที่ฉันจัดการด้วย ฉันต้องหยุดการสแกนบลูทู ธ เมื่อแอพไม่ได้ทำงานเบื้องหน้า แต่ไม่สามารถใช้เพียงแค่หยุดหรือหยุดหรือทำลายเพราะฉันไม่ต้องการหยุดและเริ่มต้นอย่างต่อเนื่องเมื่อผู้ใช้สำรวจไปรอบ ๆ แอป
CaptRespect

3

หากคุณเปิดใช้งานการตั้งค่าของนักพัฒนา "อย่าเก็บการกระทำ" - ตรวจสอบเฉพาะกิจกรรมที่สร้างไว้ไม่เพียงพอ คุณต้องตรวจสอบ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) { }        

}

3

ทางออกที่ถูกต้องเพียงข้อเดียว:

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        MyApp.mainActivity = this;
        super.onCreate(savedInstanceState);
        ...
    }

MyApp.java:

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) {
            ...
        }
    }

}

ฉันไม่เห็นว่าโซลูชันนี้สามารถให้คำตอบกับคำถามง่ายๆภายในคำสั่ง IF ในกิจกรรมของฉัน (หรือส่วน) ว่าแอปของฉันอยู่บนพื้นหลังหรือเบื้องหน้า คำสั่ง "IF" อยู่ที่ไหน ???
ekashking

2

หากต้องการ piggyback เกี่ยวกับสิ่งที่ CommonsWare และ Key ได้กล่าวไว้คุณอาจขยายคลาสแอพพลิเคชั่นและให้กิจกรรมทั้งหมดของคุณเรียกว่าในเมธอด onPause / onResume สิ่งนี้จะช่วยให้คุณทราบว่ากิจกรรมใด (IES) ที่มองเห็นได้ แต่สิ่งนี้อาจจัดการได้ดีกว่า

คุณอธิบายรายละเอียดเกี่ยวกับสิ่งที่คุณมีในใจได้ไหม? เมื่อคุณพูดว่าทำงานในพื้นหลังคุณหมายถึงเพียงแค่ให้แอปพลิเคชันของคุณยังคงอยู่ในหน่วยความจำแม้ว่าจะไม่ได้อยู่บนหน้าจอในปัจจุบัน? คุณเคยใช้บริการเป็นวิธีที่ถาวรกว่าในการจัดการแอพของคุณเมื่อไม่ได้โฟกัสหรือไม่?


ใน android เรามีการตั้งค่าที่เรียกว่า "ข้อมูลพื้นหลัง" การตั้งค่านี้เปลี่ยนการเชื่อมต่อข้อมูลพื้นหลังใด ๆ เมื่อแอปพลิเคชันทำงานในพื้นหลัง ฉันต้องการใช้การสลับ "ข้อมูลพื้นหลัง" สำหรับแอปพลิเคชันของฉันดังนั้นเมื่อผู้ใช้ไม่เห็นกิจกรรมของฉันฉันต้องการให้บริการของฉันหยุดทำการถ่ายโอนข้อมูลใด ๆ แต่เมื่อกิจกรรมของฉันดำเนินต่อ ถ่ายโอนข้อมูลต่อ
cppdev

1
Applicationไม่ได้หรือonPause() onResume()
CommonsWare

1
@CommonsWare คุณพูดถูกฉันอ้างถึงแต่ละกิจกรรมที่ติดต่อแอปพลิเคชันในการหยุดชั่วคราว / ดำเนินการต่อ นี่เป็นความคิดพื้นฐานที่คุณเพิ่งแบ่งปันความคิดเห็นกับคำตอบของคุณแม้ว่าคุณจะใช้บริการซึ่งฉันคิดว่าเป็นการเคลื่อนไหวที่ชาญฉลาดกว่า
ด่าน

2

ฉันใช้งาน 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


1

กิจกรรมจะหยุดชั่วคราวเมื่อไดอะล็อกมาเหนือดังนั้นโซลูชันที่แนะนำทั้งหมดจึงเป็นครึ่งโซลูชั่น คุณต้องสร้าง hooks สำหรับกล่องโต้ตอบด้วย



1

เอกสารทางการ:

ระบบแยกความแตกต่างระหว่างแอปพื้นหน้าและพื้นหลัง (คำจำกัดความของพื้นหลังเพื่อจุดประสงค์ในการ จำกัด บริการแตกต่างจากคำจำกัดความที่ใช้โดยการจัดการหน่วยความจำแอปอาจอยู่ในพื้นหลังซึ่งเกี่ยวข้องกับการจัดการหน่วยความจำแต่ในส่วนหน้า ถือว่าอยู่เบื้องหน้าหากสิ่งใดสิ่งหนึ่งต่อไปนี้เป็นจริง:

  1. มันมีกิจกรรมที่มองเห็นได้ไม่ว่าจะเป็นกิจกรรมที่เริ่มต้นหรือหยุดชั่วคราว
  2. มันมีบริการเบื้องหน้า
  3. แอปเบื้องหน้าอื่นเชื่อมต่อกับแอปไม่ว่าจะเชื่อมโยงกับบริการใดแอปหนึ่งหรือโดยใช้ผู้ให้บริการเนื้อหารายใดรายหนึ่ง ตัวอย่างเช่นแอปอยู่เบื้องหน้าหากแอปอื่นเชื่อมโยงกับแอป:
    • IME
    • บริการวอลเปเปอร์
    • ฟังการแจ้งเตือน
    • บริการเสียงหรือข้อความ

หากไม่มีเงื่อนไขเหล่านี้เป็นจริงแอปนั้นจะถือว่าอยู่ในพื้นหลัง


0

วิธีแก้ปัญหาอื่นสำหรับโพสต์เก่านี้ (สำหรับผู้ที่อาจช่วยได้):


<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();
    }

}

0

ดูความคิดเห็นในฟังก์ชั่น 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++;
    }
}

0

คุณควรใช้การตั้งค่าที่ใช้ร่วมกันเพื่อจัดเก็บทรัพย์สินและดำเนินการโดยใช้บริการที่มีผลผูกพันจากกิจกรรมของคุณ หากคุณใช้การผูกเท่านั้น (นั่นคือไม่เคยใช้ startService) บริการของคุณจะทำงานก็ต่อเมื่อคุณผูกไว้ (ผูก onResume และ unbind onPause) ที่จะทำให้มันทำงานในเบื้องหน้าเท่านั้นและหากคุณต้องการทำงานต่อ พื้นหลังคุณสามารถใช้บริการเริ่มหยุดปกติ


0

ฉันคิดว่าคำถามนี้ควรชัดเจนกว่านี้ เมื่อไหร่? ที่ไหน? สถานการณ์เฉพาะของคุณคืออะไรที่คุณต้องการรู้ไหมหากแอปของคุณอยู่ในพื้นหลัง

ฉันเพิ่งแนะนำวิธีแก้ปัญหาของฉันในแบบของฉัน
ฉันทำสิ่งนี้โดยใช้ฟิลด์ "สำคัญ" ของ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;
}

นี่ไม่ใช่วิธีการแก้ปัญหาที่แนะนำตามที่ระบุไว้ในคำตอบของ @ Idolon
CoolMind

0

ฉันขอแนะนำให้อ่านหน้านี้: http://developer.android.com/reference/android/app/Activity.html

กล่าวโดยย่อกิจกรรมของคุณจะไม่ปรากฏอีกต่อไปหลังจากonStop()ถูกเรียก


3
ฉันมีกิจกรรมประมาณ 10 กิจกรรมในใบสมัครของฉัน ดังนั้นฉันต้องการทราบว่าไม่มีผู้ใช้เหล่านี้หากมองเห็นได้ ในทุกฉันต้องการทราบว่าใบสมัครของฉันโดยรวมกำลังทำงานอยู่ในพื้นหลัง
cppdev

ดังนั้นคุณจึงติดตามทั้งหมด 10-ish หรือตามที่แนะนำไว้กับ CommonsWare ให้อธิบายว่าคุณกำลังพยายามทำอะไร
คีย์

3
สิ่งนี้ไม่ถูกต้อง กิจกรรมของคุณจะปรากฏจนกระทั่งonStop; ระหว่างonPauseและonStopก็มองเห็นแต่ไม่ได้อยู่เบื้องหน้า
nickgrim

@nickgrim: อะไรไม่ถูกต้อง? ฉันระบุว่ากิจกรรมจะไม่ปรากฏหลังจากonStop()ถูกเรียกอีกต่อไปซึ่งสอดคล้องกับสิ่งที่คุณเขียน
คีย์

@Key: ตอนแรกคุณพูดจนonPauseเรียกว่า: การแก้ไขล่าสุดได้แก้ไขคุณ
nickgrim


0

ในความคิดของฉันคำตอบมากมายแนะนำให้โหลดโค้ดจำนวนมากและทำให้เกิดความซับซ้อนและอ่านไม่ออก

เมื่อมีคนถามในดังนั้นวิธีการสื่อสารระหว่างServiceและActivityผมมักจะให้คำแนะนำการใช้LocalBroadcastManager


ทำไม?

ก็ด้วยการอ้างถึงเอกสาร:

  • คุณรู้ว่าข้อมูลที่คุณกำลังออกอากาศจะไม่ปล่อยให้แอปของคุณดังนั้นไม่จำเป็นต้องกังวลเกี่ยวกับการรั่วไหลของข้อมูลส่วนตัว

  • แอปพลิเคชันอื่นไม่สามารถส่งการออกอากาศเหล่านี้ไปยังแอปของคุณได้ดังนั้นคุณไม่จำเป็นต้องกังวลเกี่ยวกับช่องโหว่ด้านความปลอดภัยที่สามารถใช้ประโยชน์ได้

  • มันมีประสิทธิภาพมากกว่าการส่งการออกอากาศทั่วโลกผ่านระบบ

ไม่อยู่ในเอกสาร:

  • มันไม่ต้องการห้องสมุดภายนอก
  • รหัสน้อยที่สุด
  • รวดเร็วในการติดตั้งและทำความเข้าใจ
  • ไม่มีรูปแบบการเรียกกลับที่ดำเนินการด้วยตนเอง / รูปแบบ Ultra-Singleton / ภายในกระบวนการใด ๆ ...
  • ไม่มีการอ้างอิงที่แข็งแกร่งบน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);

สถานการณ์ที่ธรรมดามาก

ผู้พัฒนา: ฉันต้องการที่จะส่งข้อมูลจากฉันและปรับปรุงService Activityฉันจะตรวจสอบว่าActivityอยู่ในเบื้องหน้าได้อย่างไร

มักจะไม่จำเป็นต้องตรวจสอบว่าActivityอยู่ในเบื้องหน้าหรือไม่ เพียงแค่ส่งข้อมูลผ่านทางจากคุณLocalBroadcastManager ServiceหากเปิดActivityอยู่ระบบจะตอบกลับและดำเนินการ

สำหรับสถานการณ์ทั่วไปมากนี้Serviceจะกลายเป็นผู้ส่งและนำไปปฏิบัติActivityBroadcastReceiver

ดังนั้นสร้างในของคุณReceiver ActivityลงทะเบียนในและยกเลิกการลงทะเบียนในonResume() ไม่จำเป็นต้องใช้วิธีวงจรชีวิตอื่น ๆonPause()ไม่มีความจำเป็นต้องใช้วิธีการวงจรชีวิตอื่น

กำหนดReceiverพฤติกรรมในonReceive()(อัปเดต ListView ทำสิ่งนี้ทำเช่นนั้น ... )

วิธีนี้Activityจะฟังก็ต่อเมื่ออยู่ในเบื้องหน้าและจะไม่มีอะไรเกิดขึ้นหากอยู่ด้านหลังหรือถูกทำลาย

ในกรณีที่มีหลายตัวเลือกActivityใดActivityจะเปิดขึ้นจะตอบสนอง (ถ้าพวกเขายังใช้Receiver)

หากทุกคนอยู่ในพื้นหลังไม่มีใครตอบสนองและสัญญาณก็จะหายไป

ส่งข้อมูลจากServiceทางIntent(ดูรหัสด้านบน) โดยระบุรหัสสัญญาณ


  • ยกเว้นสำหรับMulti-สนับสนุน Window อาจเป็นเรื่องยาก (โปรดทดสอบถ้าจำเป็น) ...

0
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
}

0

ไม่มีคำตอบใดที่เหมาะสำหรับกรณีเฉพาะหากคุณทราบว่ากิจกรรม 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
    }
}

}


-1

ในกิจกรรมของฉันบนรีโมตและ 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)){...}

อาจจะไม่หรูหรา แต่ก็ใช้งานได้สำหรับฉัน ...


-1

มันอาจจะสายเกินไปที่จะตอบ แต่ถ้ามีใครบางคนมาเยี่ยมชมแล้วนี่คือคำตอบที่ฉันแนะนำเหตุผลที่แอปต้องการทราบว่าสถานะอยู่ในพื้นหลังหรือมาเบื้องหน้าอาจมีหลายคน เพื่อแสดงขนมปังปิ้งและการแจ้งเตือนเมื่อผู้ใช้อยู่ใน BG 2. เพื่อทำงานบางอย่างสำหรับผู้ใช้ครั้งแรกที่มาจาก BG เช่นแบบสำรวจความคิดเห็นวาดใหม่ ฯลฯ

การแก้ปัญหาโดย Idolon และอื่น ๆ จะดูแลส่วนแรก แต่ไม่ได้สำหรับส่วนที่สอง หากมีหลายกิจกรรมในแอปของคุณและผู้ใช้กำลังสลับระหว่างกิจกรรมเหล่านั้นตามเวลาที่คุณอยู่ในกิจกรรมที่สองการตั้งค่าสถานะที่มองเห็นได้จะเป็นเท็จ ดังนั้นจึงไม่สามารถใช้งานได้อย่างแน่นอน

ฉันทำสิ่งที่ CommonsWare แนะนำ "ถ้าบริการกำหนดว่าไม่มีกิจกรรมที่มองเห็นได้และยังคงเป็นเช่นนั้นตามระยะเวลาให้หยุดการถ่ายโอนข้อมูลที่จุดหยุดตรรกะถัดไป"

บรรทัดตัวหนามีความสำคัญและสามารถใช้เพื่อให้ได้ไอเท็มที่สอง ดังนั้นสิ่งที่ฉันทำคือเมื่อฉันได้รับ onActivityPaused () อย่าเปลี่ยนการมองเห็นเป็นเท็จโดยตรงแทนที่จะมีการจับเวลา 3 วินาที (นั่นคือสูงสุดที่กิจกรรมถัดไปควรจะเปิดตัว) และถ้าไม่มี onActivityResumed ( ) โทรใน 3 วินาทีถัดไปเปลี่ยนเป็นเท็จ ในทำนองเดียวกัน onActivityResumed () หากมีตัวจับเวลาฉันจะยกเลิกมัน ในการสรุปผลที่มองเห็นได้คือ isAppInBackground

ขออภัยไม่สามารถคัดลอกรหัส ...


-3

ฉันอยากจะแนะนำให้คุณใช้วิธีอื่นในการทำเช่นนี้

ฉันเดาว่าคุณต้องการที่จะแสดงหน้าจอเริ่มต้นขึ้นในขณะที่โปรแกรมกำลังเริ่มต้นถ้ามันทำงานอยู่ในแบ็กเอนด์แล้วอย่าแสดงมัน

แอปพลิเคชันของคุณสามารถเขียนเวลาปัจจุบันไปยังไฟล์ที่ต้องการได้อย่างต่อเนื่อง ขณะที่แอปพลิเคชันของคุณเริ่มต้นให้ตรวจสอบการประทับเวลาล่าสุดหาก current_time-last_time> ช่วงเวลาที่คุณระบุสำหรับการเขียนเวลาล่าสุดหมายความว่าแอปพลิเคชันของคุณหยุดทำงานไม่ว่าระบบหรือผู้ใช้จะถูกฆ่า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.