จะรับบริบทกิจกรรมเบื้องหน้าปัจจุบันใน Android ได้อย่างไร


171

เมื่อใดก็ตามที่การออกอากาศของฉันถูกดำเนินการฉันต้องการที่จะแสดงการแจ้งเตือนให้ทำกิจกรรมเบื้องหน้า


คุณต้องการรับบริบทของกิจกรรมจากที่ใด นี่คือกิจกรรมแอปของคุณหรือแอปพลิเคชันอื่น ๆ
AAnkit

นี่คือกิจกรรมของแอพ ฉันได้ทำการเข้ารหัสข้อความเตือนบนฟังก์ชั่น broadcastreceiver onreceive ()
Deepali

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

ฉันต้องการที่จะแสดงการแจ้งเตือนเกี่ยวกับกิจกรรมเบื้องหน้าของฉันเป็นวิธีอื่นใดในการแสดงการแจ้งเตือนไปยังกิจกรรมเบื้องหน้าโดยไม่มีบริบท
Deepali

1
ใน onreceive only u รับ COntext เป็น param คุณสามารถพูด context.getApplicationContext ()
AAnkit

คำตอบ:


39

รู้ว่าActivityManagerจัดการกิจกรรมเพื่อให้เราสามารถได้รับข้อมูลจากActivityManager เราได้รับการทำงานเบื้องหน้าปัจจุบันโดย

ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;

อัปเดต 2018/10/03
getRunningTasks () ถูกยกเลิก ดูวิธีแก้ปัญหาด้านล่าง

วิธีการนี้เลิกใช้แล้วใน API ระดับ 21 ในฐานะของ Build.VERSION_CODES.LOLLIPOP วิธีนี้ไม่สามารถใช้ได้กับแอปพลิเคชันของบุคคลที่สามอีกต่อไป: การแนะนำของเอกสารล่าสุดเป็นศูนย์กลางหมายความว่ามันสามารถรั่วไหลของข้อมูลบุคคลไปยังผู้โทร สำหรับความเข้ากันได้แบบย้อนหลังมันจะยังส่งคืนชุดย่อยของข้อมูล: อย่างน้อยงานของผู้เรียกและอาจเป็นงานอื่น ๆ เช่นบ้านที่ไม่ทราบว่ามีความละเอียดอ่อน


16
อย่าคิดว่า Martin จะได้รับประโยชน์จาก SDK ของ getRunningTasks "หมายเหตุ: วิธีการนี้ใช้สำหรับการดีบักและนำเสนอส่วนต่อประสานผู้ใช้งานการจัดการสิ่งนี้ไม่ควรใช้สำหรับตรรกะหลักในแอปพลิเคชัน"
ruhalde

3
เห็นได้ชัดว่านี่รองรับการทำงานที่ จำกัด ใน Android 5 / Lollipop เท่านั้น
Sam

7
เอกสารสำหรับActivityManager.getRunningTasks ()บอกว่า "วิธีนี้เลิกใช้แล้วใน API ระดับ 21"
markshep

210

( หมายเหตุ:มีการเพิ่ม API อย่างเป็นทางการใน API 14: ดูคำตอบนี้https://stackoverflow.com/a/29786451/119733 )

อย่าใช้คำตอบก่อนหน้า (waqas716)

คุณจะมีปัญหาหน่วยความจำรั่วเนื่องจากการอ้างอิงแบบคงที่กับกิจกรรม สำหรับรายละเอียดเพิ่มเติมดูลิงค์ต่อไปนี้http://android-developers.blogspot.fr/2009/01/avoiding-memory-leaks.html

เพื่อหลีกเลี่ยงปัญหานี้คุณควรจัดการการอ้างอิงกิจกรรม เพิ่มชื่อแอปพลิเคชันในไฟล์รายการ:

<application
    android:name=".MyApp"
    ....
 </application>

คลาสแอปพลิเคชันของคุณ:

  public class MyApp extends Application {
        public void onCreate() {
              super.onCreate();
        }

        private Activity mCurrentActivity = null;
        public Activity getCurrentActivity(){
              return mCurrentActivity;
        }
        public void setCurrentActivity(Activity mCurrentActivity){
              this.mCurrentActivity = mCurrentActivity;
        }
  }

สร้างกิจกรรมใหม่:

public class MyBaseActivity extends Activity {
    protected MyApp mMyApp;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mMyApp = (MyApp)this.getApplicationContext();
    }
    protected void onResume() {
        super.onResume();
        mMyApp.setCurrentActivity(this);
    }
    protected void onPause() {
        clearReferences();
        super.onPause();
    }
    protected void onDestroy() {        
        clearReferences();
        super.onDestroy();
    }

    private void clearReferences(){
        Activity currActivity = mMyApp.getCurrentActivity();
        if (this.equals(currActivity))
            mMyApp.setCurrentActivity(null);
    }
}

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

Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();

9
คุณสามารถใช้ WeakReference และบรรลุผลลัพธ์เดียวกันโดยใช้โค้ดน้อยลง
Nacho Coloma

5
@Nacho ฉันจะไม่แนะนำให้ใช้WeakReferencesใน Android อีกเลย GC จะรวบรวมพวกเขาได้เร็วขึ้นจากนั้นคุณคิดว่า
rekire

4
@MaximKorobov ใช่มันเป็นไปได้ถ้าคุณโทรเสร็จ () จาก onCreate () ถ้าคุณใช้กิจกรรมของคุณเพียงเพื่อเปิดกิจกรรมอื่นและหยุดกิจกรรมนี้ ในสถานการณ์นี้มันข้าม onPause () และ onStoo () ดูหมายเหตุด้านล่างของ: developer.android.com/training/basics/activity-lifecycle/ …
Rodrigo Leitão

2
@rekire @NachoColoma WeakReferenceไม่แนะนำให้ใช้กับการแคชนี่ไม่ใช่การแคชนั่นคือความmCurrentActivityประสงค์จะมีการอ้างอิงถึงมันเมื่อมันยังมีชีวิตอยู่ดังนั้นWeakReferenceจะไม่มีการรวบรวมในขณะที่Activityอยู่ด้านบน อย่างไรก็ตามสิ่งที่ @NachoColoma แนะนำผิดเพราะWeakReferenceอาจยังคงอ้างอิงกิจกรรมที่ไม่ได้ดำเนินการต่อ (ไม่ใช่มีชีวิตอยู่ / ไม่อยู่ด้านบน) หากตัวแปรไม่ถูกล้าง!
TWiStErRob

14
เริ่มต้นจาก Android API ระดับ 14 มันควรจะเป็นไปได้ที่จะใช้Application .ActivityLifecycleCallbacksซึ่งจะเป็นศูนย์กลางมากขึ้นและคุณไม่จำเป็นต้องเพิ่มรหัสการจัดการใด ๆ ในทุกกิจกรรมของคุณ ดูได้ที่developer.android.com/reference/android/app/…
Filou

68

ฉันขยายคำตอบที่ด้านบนของ @ gezdy

ในทุกกิจกรรมแทนที่จะต้อง "ลงทะเบียน" ด้วยApplicationการเข้ารหัสด้วยตนเองเราสามารถใช้ API ต่อไปนี้ตั้งแต่ระดับ 14 เพื่อช่วยให้เราบรรลุวัตถุประสงค์ที่คล้ายกันโดยใช้การเข้ารหัสด้วยตนเองน้อยลง

public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)

http://developer.android.com/reference/android/app/Application.html#registerActivityLifecycleCallbacks%28android.app.Application.ActivityLifecycleCallbacks%29

ในApplication.ActivityLifecycleCallbacksคุณจะได้รับซึ่งActivityคือ "แนบ" หรือ "แฝด" Applicationนี้

อย่างไรก็ตามเทคนิคนี้ใช้ได้เฉพาะตั้งแต่ API ระดับ 14


1
ขึ้นอยู่กับคำตอบอื่น ๆ ทั้งหมด? เห็นได้ชัดว่านี่คือ API ที่ออกแบบมาสำหรับวัตถุประสงค์นี้ ขอบคุณ Cheok Yan Cheng
Michael Bushe

2
@MichaelBushe - ในปี 2012 เมื่อคำตอบอื่น ๆ ถูกเขียนขึ้นอยู่กับระดับ API 14 ไม่ใช่สิ่งที่ต้องพึ่งพาในทุกอุปกรณ์เนื่องจาก API เพิ่งเปิดตัวเมื่อไม่นานมานี้ (ตุลาคม 2554)
ToolmakerSteve

4
พบคำตอบที่แสดงให้เห็นถึงวิธีการที่จะใช้วิธีการนี้: stackoverflow.com/a/11082332/199364 ประโยชน์คืออะไรจำเป็นต้องทำกิจกรรมที่ตัวเอง ; รหัสมีอยู่ในคลาสการเรียกกลับที่กำหนดเองของคุณ คุณเพียงแค่สร้างคลาสนั้นimplements Application.ActivityLifecycleCallbacksและเพิ่มวิธีการที่จะใช้ จากนั้นในตัวสร้างคลาส '(หรือ onCreate หรือ init หรือวิธีอื่นที่รันเมื่ออินสแตนซ์กำลังทำงานอยู่ / พร้อมใช้งาน) ให้ใส่getApplication().registerActivityLifecycleCallbacks(this);เป็นบรรทัดสุดท้าย
ToolmakerSteve

ผมคิดว่าคำตอบของคุณที่ดีที่สุดคือ
burulangtu

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

56

อัปเดต 2 : มีการเพิ่ม API อย่างเป็นทางการสำหรับเรื่องนี้โปรดใช้ActivityLifecycleCallbacksแทน

UPDATE:

ตามที่ @gezdy ชี้และฉันรู้สึกขอบคุณสำหรับสิ่งนั้น ตั้งค่าการอ้างอิงเป็น nullสำหรับกิจกรรมปัจจุบันแทนที่จะอัปเดตในทุก ๆ onResume ตั้งค่าเป็นโมฆะในทุกกิจกรรมของ onDestroy เพื่อหลีกเลี่ยงปัญหาการรั่วไหลของหน่วยความจำ

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

@Override
protected void onResume() {
    super.onResume();
    appConstantsObj.setCurrentActivity(this);

}

@Override
protected void onPause() {
   clearReferences();
   super.onPause();
}

@Override
protected void onDestroy() {        
   clearReferences();
   super.onDestroy();
}

private void clearReferences(){
          Activity currActivity = appConstantsObj.getCurrentActivity();
          if (this.equals(currActivity))
                appConstantsObj.setCurrentActivity(null);
}

ตอนนี้ในคลาสออกอากาศของคุณคุณสามารถเข้าถึงกิจกรรมปัจจุบันเพื่อแสดงการแจ้งเตือน


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

มันเกี่ยวกับการอ้างอิงแบบคงที่ของวัตถุกิจกรรมของคุณ คุณสามารถสร้างมันได้ทุกที่ที่คุณต้องการ :) มันไม่สำคัญ
Waqas

นี่คือ btw เทียบเท่ากับคำตอบก่อนหน้าของคุณ Applicationถูกสร้างเพียงครั้งเดียวและไม่เคยเก็บขยะเหมือนตัวแปรสแตติก
zapl

1
จะมีปัญหากับกิจกรรมลำดับชั้น เมื่อคุณกลับจากกิจกรรมเด็กไปยังผู้ปกครองคนหนึ่ง: (1) ถูกเรียกว่า onPause ของเด็ก (2) onResume ของผู้ปกครอง; (3) onDestroy ของเด็ก ==> กิจกรรมปัจจุบันจะเป็นโมฆะ คุณควรทำเครื่องหมายถูกเช่น @gezdy ในตัวอย่างของเขาในเมธอด clearReferences
ศิลปะ

4
@ waqas716 ผมขอแนะนำให้ลดความซับซ้อนของสภาพในการclearReferences() (this.equals(currActivity))
naXa

51

@lockwobrขอบคุณสำหรับการอัปเดต

นี่ใช้งานไม่ได้ 100% ใน api เวอร์ชั่น 16 ถ้าคุณอ่านโค้ดบน gitHub ฟังก์ชั่น "currentActivityThread" นั้นถูกเปลี่ยนใน Kitkat ดังนั้นฉันอยากจะบอกว่ารุ่น 19ish ยากที่จะจับคู่ api version ออกมาใน github .

มีการเข้าถึงปัจจุบันActivityมีประโยชน์มาก จะดีไหมถ้ามีgetActivityวิธีสแตติกคืนกิจกรรมปัจจุบันโดยไม่มีคำถามที่ไม่จำเป็น?

Activityระดับเป็นประโยชน์อย่างมาก มันช่วยให้สามารถเข้าถึงเธรด UI ของแอปพลิเคชันมุมมองทรัพยากรและอื่น ๆ อีกมากมาย วิธีการมากมายต้องใช้Contextแต่วิธีรับตัวชี้? นี่คือวิธีการบางอย่าง:

  • การติดตามสถานะของแอปพลิเคชันโดยใช้วิธีการวงจรชีวิตที่ถูกแทนที่ คุณต้องจัดเก็บกิจกรรมปัจจุบันในตัวแปรแบบคงที่และคุณต้องเข้าถึงรหัสของกิจกรรมทั้งหมด
  • ติดตามสถานะของแอปพลิเคชันโดยใช้การประพันธ์ดนตรี ประกาศเครื่องมือวัดในรายการใช้งานและใช้วิธีการในการติดตามการเปลี่ยนแปลงกิจกรรม การส่งตัวชี้กิจกรรมไปยังเมธอดและคลาสที่ใช้ในกิจกรรมของคุณ การฉีดพอยเตอร์โดยใช้หนึ่งในไลบรารี่ของการฉีดโค้ด ทั้งหมดของวิธีการเหล่านี้จะค่อนข้างไม่สะดวก ; โชคดีที่มีวิธีที่ง่ายกว่ามากในการรับกิจกรรมปัจจุบัน
  • ดูเหมือนว่าระบบต้องการการเข้าถึงกิจกรรมทั้งหมดโดยไม่มีปัญหาที่กล่าวถึงข้างต้น ดังนั้นส่วนใหญ่มีวิธีรับกิจกรรมโดยใช้สายคงที่เท่านั้น ฉันใช้เวลาขุดผ่านแหล่งข้อมูล Android บน grepcode.com และพบสิ่งที่ต้องการ ActivityThreadมีระดับที่เรียกว่าเป็น ActivityThreadชั้นนี้มีการเข้าถึงกิจกรรมและสิ่งที่ดียิ่งขึ้นมีวิธีแบบคงที่สำหรับการได้รับในปัจจุบัน มีปัญหาเพียงเล็กน้อยเดียวเท่านั้น - รายการกิจกรรมมีการเข้าถึงแพ็คเกจ

ง่ายต่อการแก้ไขโดยใช้การสะท้อน:

public static Activity getActivity() {
    Class activityThreadClass = Class.forName("android.app.ActivityThread");
    Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null);
    Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
    activitiesField.setAccessible(true);

    Map<Object, Object> activities = (Map<Object, Object>) activitiesField.get(activityThread);
    if (activities == null)
        return null;

    for (Object activityRecord : activities.values()) {
        Class activityRecordClass = activityRecord.getClass();
        Field pausedField = activityRecordClass.getDeclaredField("paused");
        pausedField.setAccessible(true);
        if (!pausedField.getBoolean(activityRecord)) {
            Field activityField = activityRecordClass.getDeclaredField("activity");
            activityField.setAccessible(true);
            Activity activity = (Activity) activityField.get(activityRecord);
            return activity;
        }
    }

    return null;
}

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

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

โพสต์บล็อก


2
ใน Kitkat และมากกว่า mActivities ไม่ใช่ HashMap แต่ ArrayMap ดังนั้นคุณต้องเปลี่ยนบรรทัดนี้: HashMap activities = (HashMap) activitiesField.get (activityThread); เพื่อมีลักษณะดังนี้: ArrayMap activities = (ArrayMap) activitiesField.get (activityThread);
Palejandro

7
@Palejandro ที่ให้การสนับสนุนทั้งในระดับ API (เหนือ 18 และด้านล่าง) ก็ควรใช้Mapอินเตอร์เฟซแทนหรือHashMap ArrayMapฉันแก้ไข @AZ_ คำตอบแล้ว
Yuriy Kolbasinskiy

2
สิ่งนี้ไม่ทำงาน 100% ของเวลาใน api รุ่น 16หากคุณอ่านโค้ดบน gitHub ฟังก์ชั่น "currentActivityThread" ถูกเปลี่ยนใน Kitkat ดังนั้นฉันอยากจะบอกว่ารุ่น19ishยากที่จะจับคู่ api version ออกมาใน github .
lockwobr

@lockwobr ขอบคุณวิธีแก้ปัญหาอัปเดตเมื่อคุณแสดงความคิดเห็น
:)

2
ไม่รองรับการเข้าถึง API ภายในผ่านการสะท้อนกลับและอาจไม่สามารถใช้งานได้กับอุปกรณ์ทั้งหมดหรือในอนาคต
เป่ย

9

ฉันทำตามใน Kotlin

  1. สร้างคลาสแอปพลิเคชัน
  2. แก้ไขคลาสแอปพลิเคชันดังต่อไปนี้

    class FTApplication: MultiDexApplication() {
    override fun attachBaseContext(base: Context?) {
        super.attachBaseContext(base)
        MultiDex.install(this)
    }
    
    init {
        instance = this
    }
    
    val mFTActivityLifecycleCallbacks = FTActivityLifecycleCallbacks()
    
    override fun onCreate() {
        super.onCreate()
    
        registerActivityLifecycleCallbacks(mFTActivityLifecycleCallbacks)
    }
    
    companion object {
        private var instance: FTApplication? = null
    
        fun currentActivity(): Activity? {
    
            return instance!!.mFTActivityLifecycleCallbacks.currentActivity
        }
    }
    
     }
  3. สร้างคลาส ActivityLifecycleCallbacks

    class FTActivityLifecycleCallbacks: Application.ActivityLifecycleCallbacks {
    
    var currentActivity: Activity? = null
    
    override fun onActivityPaused(activity: Activity?) {
        currentActivity = activity
    }
    
    override fun onActivityResumed(activity: Activity?) {
        currentActivity = activity
    }
    
    override fun onActivityStarted(activity: Activity?) {
        currentActivity = activity
    }
    
    override fun onActivityDestroyed(activity: Activity?) {
    }
    
    override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {
    }
    
    override fun onActivityStopped(activity: Activity?) {
    }
    
    override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {
        currentActivity = activity
    }
    
    }
  4. ตอนนี้คุณสามารถใช้มันในคลาสใดก็ได้โดยการเรียกสิ่งต่อไปนี้ FTApplication.currentActivity()


5

getCurrentActivity () ยังอยู่ใน ReactContextBaseJavaModule
(ตั้งแต่คำถามนี้ถูกถามครั้งแรกแอพ Android จำนวนมากก็มีส่วนประกอบ ReactNative - แอพไฮบริด)

class ReactContext ใน ReactNative มีชุดตรรกะทั้งหมดเพื่อรักษา mCurrentActivity ซึ่งส่งคืนใน getCurrentActivity ()

หมายเหตุ: ฉันต้องการ getCurrentActivity () นำไปใช้ในคลาสแอปพลิเคชัน Android


ในบางกรณีบริบทนี้จาก ReactContextBaseJavaModule เป็นโมฆะคุณรู้ไหมว่าทำไม
Moxor

4

ฉันไม่สามารถหาวิธีแก้ปัญหาที่ทีมของเราจะมีความสุขด้วยดังนั้นเราจึงรีดของเราเอง เราใช้ActivityLifecycleCallbacksเพื่อติดตามกิจกรรมปัจจุบันแล้วเปิดเผยผ่านบริการ รายละเอียดเพิ่มเติมได้ที่นี่: https://stackoverflow.com/a/38650587/10793


2

สำหรับความเข้ากันได้ย้อนหลัง:

ComponentName cn;
ActivityManager am = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
    cn = am.getAppTasks().get(0).getTaskInfo().topActivity;
} else {
    //noinspection deprecation
    cn = am.getRunningTasks(1).get(0).topActivity;
}

4
หากไม่มีวิธีรับจาก ComponentName ไปยังอินสแตนซ์ปัจจุบันของกิจกรรมสิ่งนี้จะไม่ตอบคำถาม IMO
nasch

@nasch หนึ่งสามารถเก็บและรับWeakReferenceหมายเลขอ้างอิงจากApplicationคลาส - ในขณะที่ComponentNameจำเป็นต้องมีการตรวจสอบถ้าต้องการActivityอยู่ด้านบนของรายการงานที่กำลังทำงานอยู่ และถ้าสิ่งนี้ไม่ตอบคำถามทั้งหมดคำตอบที่ยอมรับก็ไม่ได้เช่นกัน
Martin Zeitler

ฉันเห็นด้วยคำตอบที่ยอมรับไม่ได้ตอบคำถามอย่างเต็มที่เช่นกัน
nasch

1
topActivityสามารถใช้ได้เฉพาะจาก Android Q
Eugen Martynov

1

โดยส่วนตัวฉันทำตาม "Cheok Yan Cheng" แต่ฉันใช้ "List" เพื่อมี "Backstack" ของกิจกรรมทั้งหมดของฉัน

ถ้าคุณต้องการตรวจสอบว่ากิจกรรมใดเป็นกิจกรรมปัจจุบันคุณเพียงแค่ต้องรับคลาสกิจกรรมล่าสุดในรายการ

สร้างแอปพลิเคชันที่ขยาย "แอปพลิเคชัน" และทำสิ่งนี้:

public class MyApplication extends Application implements Application.ActivityLifecycleCallbacks,
EndSyncReceiver.IEndSyncCallback {

private List<Class> mActivitiesBackStack;
private EndSyncReceiver mReceiver;
    private Merlin mMerlin;
    private boolean isMerlinBound;
    private boolean isReceiverRegistered;

@Override
    public void onCreate() {
        super.onCreate();
        [....]
RealmHelper.initInstance();
        initMyMerlin();
        bindMerlin();
        initEndSyncReceiver();
        mActivitiesBackStack = new ArrayList<>();
    }

/* START Override ActivityLifecycleCallbacks Methods */
    @Override
    public void onActivityCreated(Activity activity, Bundle bundle) {
        mActivitiesBackStack.add(activity.getClass());
    }

    @Override
    public void onActivityStarted(Activity activity) {
        if(!isMerlinBound){
            bindMerlin();
        }
        if(!isReceiverRegistered){
            registerEndSyncReceiver();
        }
    }

    @Override
    public void onActivityResumed(Activity activity) {

    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {
        if(!AppUtils.isAppOnForeground(this)){
            if(isMerlinBound) {
                unbindMerlin();
            }
            if(isReceiverRegistered){
                unregisterReceiver(mReceiver);
            }
            if(RealmHelper.getInstance() != null){
                RealmHelper.getInstance().close();
                RealmHelper.getInstance().logRealmInstanceCount("AppInBackground");
                RealmHelper.setMyInstance(null);
            }
        }
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {

    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        if(mActivitiesBackStack.contains(activity.getClass())){
            mActivitiesBackStack.remove(activity.getClass());
        }
    }
    /* END Override ActivityLifecycleCallbacks Methods */

/* START Override IEndSyncCallback Methods */
    @Override
    public void onEndSync(Intent intent) {
        Constants.SyncType syncType = null;
        if(intent.hasExtra(Constants.INTENT_DATA_SYNC_TYPE)){
            syncType = (Constants.SyncType) intent.getSerializableExtra(Constants.INTENT_DATA_SYNC_TYPE);
        }
        if(syncType != null){
            checkSyncType(syncType);
        }
    }
    /* END IEndSyncCallback Methods */

private void checkSyncType(Constants.SyncType){
    [...]
    if( mActivitiesBackStack.contains(ActivityClass.class) ){
         doOperation()     }
}

}

ในกรณีของฉันฉันใช้ "Application.ActivityLifecycleCallbacks" เพื่อ:

  • Bind / Unbind Merlin Instance (ใช้เพื่อรับเหตุการณ์เมื่อแอปขาดหรือรับการเชื่อมต่อตัวอย่างเช่นเมื่อคุณปิดข้อมูลมือถือหรือเมื่อคุณเปิด) มันจะมีประโยชน์หลังจากการกระทำที่ตั้งใจ "OnConnectivityChanged" ถูกปิดใช้งาน สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ MERLIN โปรดดู: MERLIN INFO LINK

  • ปิด Realm Instance สุดท้ายของฉันเมื่อปิดแอปพลิเคชัน ฉันจะเริ่มต้นมันภายใน BaseActivity ซึ่งขยายจากกิจกรรมอื่น ๆ ทั้งหมดและมีอินสแตนซ์ของ RealmHelper ส่วนตัว สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ REALM โปรดดู: REALM INFO LINK ตัวอย่างเช่นฉันมีอินสแตนซ์ "RealmHelper" แบบคงที่ในคลาส "RealmHelper" ของฉันซึ่งมีอินสแตนซ์ภายในแอปพลิเคชันของฉัน "onCreate" ฉันมีบริการการซิงโครไนซ์ที่ฉันสร้างฉันใหม่ "RealmHelper" เนื่องจากอาณาจักรนั้นเป็น "การเชื่อมโยงเธรด" และอินสแตนซ์ของอาณาจักรไม่สามารถทำงานภายในเธรดอื่นได้ ดังนั้นในการติดตามเอกสารของ Realm "คุณต้องปิดอินสแตนซ์ของอาณาจักรที่เปิดทั้งหมดเพื่อหลีกเลี่ยงการรั่วไหลของทรัพยากรระบบ" เพื่อบรรลุสิ่งนี้ฉันใช้ "Application.ActivityLifecycleCallbacks" ตามที่คุณเห็น

  • ในที่สุดฉันก็มีผู้รับที่ถูกทริกเกอร์เมื่อฉันเสร็จสิ้นการประสานใบสมัครของฉันแล้วเมื่อสิ้นสุดการซิงค์มันจะเรียกวิธีการ "IEndSyncCallback" "onEndSync" ซึ่งฉันดูว่าฉันมีคลาสกิจกรรมเฉพาะภายในรายการกิจกรรมของฉัน เพื่ออัปเดตข้อมูลในมุมมองหากการซิงค์อัปเดตและฉันอาจต้องดำเนินการอื่นหลังจากการซิงค์แอป

หวังว่าสิ่งนี้จะเป็นประโยชน์ เจอกัน :)


-1

คำตอบโดยwaqas716นั้นดี ฉันสร้างวิธีแก้ปัญหาสำหรับกรณีเฉพาะที่ต้องการรหัสและการบำรุงรักษาน้อยลง

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

ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity; 

ฉันจะตรวจสอบว่ามุมมองนั้นไม่ว่างและรับบริบทผ่าน getContext ()

View v = SuspectedActivity.get_view();

if(v != null)
{
    // an example for using this context for something not 
    // permissible in global application context. 
    v.getContext().startActivity(new Intent("rubberduck.com.activities.SomeOtherActivity"));
}

ฉันกำลังมองหาปัญหาที่คล้ายกันที่นี่ stackoverflow.com/questions/22788289/… เราจะได้รับ "SuspectedActivity" ได้อย่างไร API เนทีฟนี้หรือไม่
สเตลล่า

2
แต่จากเอกสารสำหรับgetRunningTasks: "Note: this method is only intended for debugging and presenting task management user interfaces. This should never be used for core logic in an application, ..." ในdeveloper.android.com/reference/android/app/…
ToolmakerSteve

3
ตอนนี้เอกสารสำหรับActivityManager.getRunningTasks ()บอกว่า "วิธีนี้เลิกใช้แล้วใน API ระดับ 21"
markshep

-2

ฉันไม่ชอบคำตอบอื่น ๆ ActivityManager ไม่ได้มีไว้เพื่อใช้ในการรับกิจกรรมปัจจุบัน การจัดระดับสุดยอดและขึ้นอยู่กับ Devroy นั้นเปราะบางและไม่ใช่การออกแบบที่ดีที่สุด

ความจริงแล้วสิ่งที่ดีที่สุดที่ฉันเคยได้รับคือการรักษา enum ในแอปพลิเคชันของฉันซึ่งได้รับการตั้งค่าเมื่อมีการสร้างกิจกรรม

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


1
Enum หรือไม่? วิธีนั้นช่วยค้นหาอินสแตนซ์ของกิจกรรมเบื้องหน้าปัจจุบันได้อย่างไร
ToolmakerSteve

"การจัดกลุ่มซุปเปอร์และขึ้นอยู่กับเดสทรอยก็เปราะบาง" มันเปราะบางอย่างไร
ToolmakerSteve

-3

วิธีแก้ปัญหาที่ค่อนข้างง่ายคือการสร้างคลาสผู้จัดการแบบซิงเกิลซึ่งคุณสามารถจัดเก็บการอ้างอิงไปยังกิจกรรมหนึ่งรายการหรือมากกว่าหรือสิ่งอื่นที่คุณต้องการเข้าถึงได้ทั่วทั้งแอพ

โทรUberManager.getInstance().setMainActivity( activity );ในกิจกรรมหลักของ onCreate

โทรไปUberManager.getInstance().getMainActivity();ที่ใดก็ได้ในแอปของคุณเพื่อรับข้อมูล (ฉันใช้สิ่งนี้เพื่อให้สามารถใช้ Toast จากเธรด UI ที่ไม่ใช่)

ตรวจสอบให้แน่ใจว่าคุณเพิ่มการโทรUberManager.getInstance().cleanup();เมื่อแอพของคุณถูกทำลาย

import android.app.Activity;

public class UberManager
{
    private static UberManager instance = new UberManager();

    private Activity mainActivity = null;

    private UberManager()
    {

    }

    public static UberManager getInstance()
    {
        return instance;
    }

    public void setMainActivity( Activity mainActivity )
    {
        this.mainActivity = mainActivity;
    }

    public Activity getMainActivity()
    {
        return mainActivity;
    }

    public void cleanup()
    {
        mainActivity = null;
    }
}

สิ่งนี้รบกวนและต้องการการเปลี่ยนแปลงในกิจกรรมทั้งหมด คำตอบโดย AZ_จะดีกว่ามากที่มันเป็นภาษาท้องถิ่นโดยสิ้นเชิงและแบบสแตนด์อโลนโดยไม่ต้องมีการเปลี่ยนแปลงอื่น ๆ ใน codebase
markshep

-7

ฉันเหมือนสาย 3 ปี แต่ฉันจะตอบมันต่อไปในกรณีที่มีคนพบสิ่งนี้เช่นฉัน

ฉันแก้ไขมันโดยใช้สิ่งนี้:

    if (getIntent().toString().contains("MainActivity")) {
        // Do stuff if the current activity is MainActivity
    }

โปรดทราบว่า "getIntent (). toString ()" รวมถึงข้อความอื่น ๆ อีกมากมายเช่นชื่อแพ็คเกจของคุณและตัวกรองเจตนาสำหรับกิจกรรมของคุณ ในทางเทคนิคเรากำลังตรวจสอบเจตนาปัจจุบันไม่ใช่กิจกรรม แต่ผลลัพธ์จะเหมือนกัน เพียงใช้เช่น Log.d ("test", getIntent (). toString ()); ถ้าคุณต้องการที่จะเห็นข้อความทั้งหมด วิธีนี้ค่อนข้างแฮ็ค แต่มันก็ดีกว่าในโค้ดของคุณและฟังก์ชั่นก็เหมือนกัน

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