จะตรวจสอบได้อย่างไรว่ากิจกรรมอยู่เบื้องหน้าหรือในพื้นหลังที่มองเห็นได้?


104

ฉันมีหน้าจอเริ่มต้นในตัวจับเวลา ปัญหาของฉันคือว่าก่อนที่ฉันfinish()กิจกรรมของฉันฉันต้องตรวจสอบว่ากิจกรรมถัดไปได้เริ่มต้นเพราะกล่องระบบการสนทนาปรากฏขึ้นและฉันต้องการfinish(); เมื่อผู้ใช้เลือกตัวเลือกจากกล่องโต้ตอบแล้ว?

ฉันรู้ว่ามีคำถามมากมายเกี่ยวกับวิธีดูว่ากิจกรรมของคุณอยู่เบื้องหน้าหรือไม่ แต่ฉันไม่รู้ว่าสิ่งนี้อนุญาตให้มีกล่องโต้ตอบอยู่ด้านบนของกิจกรรมด้วยหรือไม่

นี่คือปัญหาสีแดงคือกิจกรรมของฉันซึ่งอยู่เบื้องหลังในขณะที่บทสนทนาอยู่เบื้องหน้า:

สีแดงคือกิจกรรมของฉันซึ่งอยู่เบื้องหลังในขณะที่บทสนทนาอยู่เบื้องหน้า

แก้ไข:ฉันได้ลองเพียงแค่ไม่ได้ใช้งานfinish()แต่กิจกรรมของฉันสามารถย้อนกลับไปในกลุ่มแอปพลิเคชันที่ฉันพยายามหลีกเลี่ยงได้


อาจจะเกี่ยวข้องกัน: stackoverflow.com/questions/4414171/…
jarmod

เพื่อความชัดเจนคุณต้องการเปิดตัวเลือกความตั้งใจและรอให้แอปของคุณเสร็จสิ้น () จนกว่าผู้ใช้จะแตะหนึ่งในตัวเลือก? ดูเหมือนว่าคุณต้องการ Intent.createChooser () และ startActivityForResult () ตามด้วยเสร็จสิ้น () เมื่อได้รับผลลัพธ์
alanv


ProcessLifecycleOwnerเป็นโซลูชันใหม่ล่าสุด
SR

คำตอบ:


189

นี่คือสิ่งที่แนะนำเป็นวิธีแก้ปัญหาที่เหมาะสม :

โซลูชันที่เหมาะสม (เครดิตไปที่ Dan, CommonsWare และ NeTeInStEiN) ติดตามการมองเห็นแอปพลิเคชันของคุณด้วยตัวเองโดยใช้เมธอด Activity.onPause, Activity.onResume จัดเก็บสถานะ "การเปิดเผย" ในคลาสอื่น ๆ ทางเลือกที่ดีคือการใช้งานแอปพลิเคชันหรือบริการของคุณเอง (นอกจากนี้ยังมีโซลูชันนี้อยู่ 2-3 รูปแบบหากคุณต้องการตรวจสอบการเปิดเผยกิจกรรมจากบริการ)

ตัวอย่าง ใช้คลาส 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 ให้กับทุกกิจกรรมในโครงการ (คุณสามารถสร้างบรรพบุรุษร่วมกันสำหรับกิจกรรมของคุณได้หากคุณต้องการ แต่ถ้ากิจกรรมของคุณขยายจาก MapActivity / ListActivity เป็นต้นคุณยังต้องเขียนสิ่งต่อไปนี้ด้วยมือ) :

@Override
protected void onResume() {
  super.onResume();
  MyApplication.activityResumed();
}

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

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

แหล่งข่าวยังกล่าวถึงวิธีแก้ปัญหาที่ผิดสองวิธี ... ดังนั้นหลีกเลี่ยงการทำเช่นนั้น

ที่มา: stackoverflow


มีช่วงเวลาเล็กน้อยระหว่างเสร็จสิ้นและเริ่มกิจกรรมและฉันต้องเพิ่มความล่าช้าและการตอบโต้
sagus_helgy

28
สิ่งนี้ไม่ได้ผลอย่างน่าเชื่อถือ คุณอาจมีสถานการณ์ต่อไปนี้: Resume A Resume B Pause A ตอนนี้ activityVisible เป็นเท็จในขณะที่แอปพลิเคชันสามารถมองเห็นได้ บางทีคุณอาจใช้ตัวนับการมองเห็น: visibleCounter ++ ใน onResume และ visibleCounter - ใน onPause
Joris Weimar

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

1
ในความเป็นจริงไม่มีคำตอบอื่นใดที่ใช้ได้ผล 100% เช่นกัน

2
หากแอปมีมากกว่าหนึ่งกิจกรรมโครงการนี้จะใช้ไม่ได้ แทนที่ด้วยเคาน์เตอร์อย่างน้อย
ruX

70

หากกำหนดเป้าหมาย API ระดับ 14 ขึ้นไปสามารถใช้android.app.Application.ActivityLifecycleCallbacks

public class MyApplication extends Application implements ActivityLifecycleCallbacks {
    private static boolean isInterestingActivityVisible;

    @Override
    public void onCreate() {
        super.onCreate();

        // Register to be notified of activity state changes
        registerActivityLifecycleCallbacks(this);
        ....
    }

    public boolean isInterestingActivityVisible() {
        return isInterestingActivityVisible;
    }

    @Override
    public void onActivityResumed(Activity activity) {
        if (activity instanceof MyInterestingActivity) {
             isInterestingActivityVisible = true;
        }
    }

    @Override
    public void onActivityStopped(Activity activity) {
        if (activity instanceof MyInterestingActivity) {
             isInterestingActivityVisible = false;
        }
    }

    // Other state change callback stubs
    ....
}

18
คุณสามารถทำได้ในการเรียกกลับวงจรชีวิตของกิจกรรมปกติ (onResume (), onStop ()) เช่นกัน
Daniel Wilson

5
@DanielWilson ฉันคิดว่าประเด็นไม่ใช่การสร้างระบบเพื่อทำบางสิ่งที่มีอยู่แล้ว IMHO นี่ควรเป็นคำตอบที่ยอมรับได้
Jeffrey Blattman

29

UPD : Lifecycle.State.RESUMEDการปรับปรุงเพื่อให้รัฐ ขอบคุณ@htafoyaสำหรับสิ่งนั้น

ในปี 2019 ด้วยความช่วยเหลือของไลบรารีการสนับสนุนใหม่28+หรือ AndroidX คุณสามารถใช้:

val isActivityInForeground = activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)

คุณสามารถอ่านเพิ่มเติมในเอกสารเพื่อทำความเข้าใจว่าเกิดอะไรขึ้นภายใต้ฝากระโปรง


2
ไม่จริงอาจจะดีกว่าที่จะวางactivity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED) หรือเริ่มต้น INITIALIZEDไม่รับประกันว่าจะอยู่เบื้องหน้า
htafoya

11

กิจกรรม :: hasWindowFocus ()ส่งคืนบูลีนที่คุณต้องการ

public class ActivityForegroundChecker extends TimerTask
{
    private static final long FOREGROUND_CHECK_PERIOD = 5000;
    private static final long FIRST_DELAY             = 3000;

    private Activity m_activity;
    private Timer    m_timer;

    public ActivityForegroundChecker (Activity p_activity)
    {
        m_activity = p_activity;
    }

    @Override
    public void run()
    {
        if (m_activity.hasWindowFocus() == true) {
            // Activity is on foreground
            return;
        }
        // Activity is on background.
    }

    public void start ()
    {
        if (m_timer != null) {
            return;
        }
        m_timer = new Timer();
        m_timer.schedule(this, FIRST_DELAY, FOREGROUND_CHECK_PERIOD);
    }

    public void stop ()
    {
        if (m_timer == null) {
            return;
        }
        m_timer.cancel();
        m_timer.purge();
        m_timer = null;
    }
}

นี่คือคลาสตัวอย่างเพื่อตรวจสอบการมองเห็นกิจกรรมของคุณจากทุกที่

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


1
ขอบคุณสำหรับการแก้ไขคำตอบ @Burak Day มันเป็นคำตอบตอนนี้
Nick

วิธีนี้ไม่ได้ผลฉันอยากจะใช้คุณสมบัติบูลีนในคลาสตั้งค่าเป็นจริงใน OnResume และตั้งค่าเป็นเท็จใน OnPause ();
Chandler

@Chandler ปัญหาที่แน่นอนที่คุณมีกับรหัสนี้คืออะไร? นอกจากนี้รุ่นใด
Burak Day

@ ผู้จัดการยังจะเกิดอะไรขึ้นถ้าคุณไม่สามารถเข้าถึงวิธีวงจรชีวิตของกิจกรรมได้ พิจารณาว่าคุณกำลังตรวจสอบการเปิดเผยกิจกรรมจากห้องสมุด
Burak Day

ปัญหาที่แท้จริงของคำตอบนี้คือมันไม่ทำงาน activity.hasWindowFocus เป็นจริงไม่สามารถรับประกันได้ว่ากิจกรรมอยู่ระหว่างสถานะ onResume และ onPause ฉันอยากจะแนะนำให้เพิ่มคุณสมบัติ isResumed บูลในกิจกรรมนั้นตั้งค่าด้วยตนเองและเพิ่มเมธอด get
Chandler

10

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

ถ้าฉันเข้าใจคุณถูกต้องสิ่งที่คุณต้องทำคือเรียกร้องfinish()จากกิจกรรมของคุณonStopเพื่อยุติกิจกรรมนั้น ดูภาพที่แนบมาของกิจกรรมระยะเวลาการสาธิต App นี่คือลักษณะที่ปรากฏเมื่อเปิดกิจกรรม B จากกิจกรรม A ลำดับของเหตุการณ์คือจากล่างขึ้นบนดังนั้นคุณจะเห็นว่ากิจกรรม A onStopถูกเรียกหลังจากที่เรียกกิจกรรม B onResumeแล้ว

การสาธิตวงจรชีวิตของกิจกรรม

ในกรณีที่กล่องโต้ตอบปรากฏขึ้นกิจกรรมของคุณจะเป็นสีจางในพื้นหลังและonPauseเรียกเท่านั้น


7

สองวิธีที่เป็นไปได้:

1) การเรียกกลับของวงจรชีวิตของกิจกรรม

ใช้แอปพลิเคชันที่ใช้ActivityLifecycleCallbacksและใช้เพื่อติดตามเหตุการณ์วงจรชีวิตของกิจกรรมในแอปพลิเคชันของคุณ โปรดทราบว่า ActivityLifecycleCallbacks ใช้สำหรับ Android api> = 14 สำหรับ Android api ก่อนหน้านี้คุณจะต้องติดตั้งด้วยตัวเองในกิจกรรมทั้งหมดของคุณ ;-)

ใช้แอปพลิเคชันเมื่อคุณต้องการแบ่งปัน / จัดเก็บสถานะในกิจกรรมต่างๆ

2) ตรวจสอบข้อมูลกระบวนการทำงาน

คุณสามารถตรวจสอบสถานะของกระบวนการที่กำลังทำงานอยู่ด้วยคลาสนี้ RunningAppProcessInfo

ดึงรายการกระบวนการทำงานด้วยActivityManager.getRunningAppProcesses () และกรองรายการผลลัพธ์เพื่อตรวจสอบ RunningAppProcessInfo ที่ต้องการและตรวจสอบ "ความสำคัญ"



3

ใช้ช่องว่างของเวลาระหว่างหยุดชั่วคราวและเล่นต่อจากพื้นหลังเพื่อตรวจสอบว่าตื่นจากพื้นหลังหรือไม่

ในแอปพลิเคชันที่กำหนดเอง

private static boolean isInBackground;
private static boolean isAwakeFromBackground;
private static final int backgroundAllowance = 10000;

public static void activityPaused() {
    isInBackground = true;
    final Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            if (isInBackground) {
                isAwakeFromBackground = true;
            }
        }
    }, backgroundAllowance);
    Log.v("activity status", "activityPaused");
}

public static void activityResumed() {
    isInBackground = false;
    if(isAwakeFromBackground){
        // do something when awake from background
        Log.v("activity status", "isAwakeFromBackground");
    }
    isAwakeFromBackground = false;
    Log.v("activity status", "activityResumed");
}

ในคลาส BaseActivity

@Override
protected void onResume() {
  super.onResume();
  MyApplication.activityResumed();
}

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

3

ฉันคิดว่าฉันมีทางออกที่ดีกว่า เพราะคุณสามารถสร้างใน MyApplication.activityResumed (); เพื่อขยายทุกกิจกรรม

ประการแรกคุณต้องสร้าง (เช่น CyberneticTwerkGuruOrc)

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

ถัดไปคุณต้องเพิ่มคลาส Application ลงใน AndroidManifest.xml

<application
    android:name="your.app.package.MyApplication"
    android:icon="@drawable/icon"
    android:label="@string/app_name" >

จากนั้นสร้างคลาส ActivityBase

public class ActivityBase extends Activity {

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

    @Override
    protected void onResume() {
        super.onResume();
        MyApplication.activityResumed();
    }
}

ในที่สุดเมื่อคุณสร้างกิจกรรมใหม่คุณสามารถขยายได้โดยใช้ ActivityBase แทนกิจกรรม

public class Main extends ActivityBase {
    @Override
    protected void onResume() {
        super.onResume();
    }

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

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

หากคุณต้องการตรวจสอบการเปิดเผยแอปของคุณคุณสามารถโทร

MyApplication.isActivityVisible()

จะเกิดอะไรขึ้นหากฉันต้องการกิจกรรมเพื่อขยาย AppCombatActivity
winklerrr

2

สิ่งนี้สามารถบรรลุสิ่งนี้ได้อย่างมีประสิทธิภาพโดยใช้Application.ActivityLifecycleCallbacks

ตัวอย่างเช่นให้ใช้ชื่อคลาสกิจกรรมเป็นProfileActivityช่วยให้ค้นหาได้ว่าอยู่เบื้องหน้าหรือเบื้องหลัง

ก่อนอื่นเราต้องสร้างคลาสแอปพลิเคชันของเราโดยการขยายคลาสแอปพลิเคชัน

ซึ่งดำเนินการ

Application.ActivityLifecycleCallbacks

ให้เป็นคลาส Application ของฉันดังนี้

คลาสแอปพลิเคชัน

public class AppController extends Application implements Application.ActivityLifecycleCallbacks {


private boolean activityInForeground;

@Override
public void onCreate() {
    super.onCreate();

//register ActivityLifecycleCallbacks  

    registerActivityLifecycleCallbacks(this);

}



public static boolean isActivityVisible() {
    return activityVisible;
}

public static void activityResumed() {
    activityVisible = true;
}

public static void activityPaused() {
    activityVisible = false;
}

private static boolean activityVisible;

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {

}

@Override
public void onActivityStarted(Activity activity) {

}

@Override
public void onActivityResumed(Activity activity) {
    //Here you can add all Activity class you need to check whether its on screen or not

    activityInForeground = activity instanceof ProfileActivity;
}

@Override
public void onActivityPaused(Activity activity) {

}

@Override
public void onActivityStopped(Activity activity) {

}

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

}

@Override
public void onActivityDestroyed(Activity activity) {

}

public boolean isActivityInForeground() {
    return activityInForeground;
}
}

ในคลาสข้างต้นจะมีการแทนที่ methord onActivityResumedของActivityLifecycleCallbacks

 @Override
public void onActivityResumed(Activity activity) {
    //Here you can add all Activity class you need to check whether its on screen or not

    activityInForeground = activity instanceof ProfileActivity;
}

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

ลงทะเบียนคลาส Application ของคุณใน manifest.xml

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

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

AppController applicationControl = (AppController) getApplicationContext();
    if(applicationControl.isActivityInForeground()){
     Log.d("TAG","Activity is in foreground")
    }
    else
    {
      Log.d("TAG","Activity is in background")
    }

1

หากคุณต้องการทราบว่ามีกิจกรรมใดในแอปของคุณให้เห็นบนหน้าจอหรือไม่คุณสามารถทำสิ่งต่อไปนี้:

public class MyAppActivityCallbacks implements Application.ActivityLifecycleCallbacks {
private Set<Class<Activity>> visibleActivities = new HashSet<>();

@Override
public void onActivityResumed(Activity activity) {
    visibleActivities.add((Class<Activity>) activity.getClass());
}

@Override
public void onActivityStopped(Activity activity) {
     visibleActivities.remove(activity.getClass());
}

public boolean isAnyActivityVisible() {
    return !visibleActivities.isEmpty();
}

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}

@Override
public void onActivityStarted(Activity activity) {}

@Override
public void onActivityPaused(Activity activity) {}

@Override
public void onActivityDestroyed(Activity activity) {}

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

เพียงสร้างซิงเกิลตันของคลาสนี้และตั้งค่าในอินสแตนซ์แอปพลิเคชันของคุณดังนี้

class App extends Application{
     @Override
     public void onCreate() {
         registerActivityLifecycleCallbacks(myAppActivityCallbacks);
     }
}

จากนั้นคุณสามารถใช้เมธอด isAnyActivityVisible () ของอินสแตนซ์ MyAppActivityCallbacks ได้ทุกที่!


0

คุณพยายามโทรไม่เสร็จและใส่ "android: noHistory =" true "ในรายการหรือไม่สิ่งนี้จะป้องกันไม่ให้กิจกรรมไปที่สแต็ก


0

ฉันต้องบอกว่าขั้นตอนการทำงานของคุณไม่ได้เป็นไปตามมาตรฐานของ Android ใน Android คุณไม่จำเป็นต้องfinish()ทำกิจกรรมของคุณหากคุณต้องการเปิดกิจกรรมอื่นจาก Intent เพื่อความสะดวกของผู้ใช้ Android อนุญาตให้ผู้ใช้ใช้ปุ่ม "ย้อนกลับ" เพื่อย้อนกลับจากกิจกรรมที่คุณเปิดไปยังแอปของคุณ

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


3
"buu นี่ไม่ใช่ Android" คำตอบที่น่าเบื่อหน่ายและไม่ตอบคำถามที่วางไว้ตั้งแต่แรก นอกจากนี้ยังมีเหตุผลที่ถูกต้องในการเสร็จสิ้น (); - ตัวอย่างเช่นเป็นไปได้ที่จะกลับไปอีกครั้งเมื่อการดำเนินการถูกระงับโดยไม่มีจุดประสงค์ใด ๆ กล่าวอีกนัยหนึ่งคุณคิดว่าพวกเขาใส่ Finish () ไว้ในนั้นเพื่อความสนุกหรือไม่? การอยู่ในกองซ้อนเป็นสิ่งที่ผู้ถามต้องการหลีกเลี่ยง
Lassi Kinnunen

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

0

บันทึกค่าสถานะหากคุณหยุดชั่วคราวหรือกลับมาทำงานต่อ หากคุณกลับมาทำงานต่อนั่นหมายความว่าคุณอยู่เบื้องหน้า

boolean  isResumed = false;

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

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

private void finishIfForeground() {
  if (isResumed) {
    finish();
  }
}

0

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

ตัวอย่างเช่นหากกล่องโต้ตอบของระบบถูกกระตุ้นโดยการคลิกปุ่มบางปุ่มผู้ฟัง onclick อาจเป็นเช่นนั้น

private OnClickListener btnClickListener = new OnClickListener() {

    @Override
    public void onClick(View v) {           
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_SEND);
        intent.setType("text/plain");
        CheckActivity.this.startActivity(Intent.createChooser(intent, "Complete action using"));
        checkFlag = true;  //flag used to check

    }
};

และในช่วงหยุดกิจกรรม:

@Override
protected void onStop() {
    if(checkFlag){
        finish();
    }
    super.onStop();
}

0

ทำไมไม่ใช้การออกอากาศสำหรับสิ่งนี้? กิจกรรมที่สอง (กิจกรรมที่ต้องมีขึ้น) สามารถส่งการออกอากาศในพื้นที่ได้ดังนี้:

//put this in onCreate(..) or any other lifecycle method that suits you best
//notice the string sent to the intent, it will be used to register a receiver!
Intent result = new Intent("broadcast identifier");
result.putString("some message");//this is optional
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(result);

จากนั้นเขียนตัวรับสัญญาณอย่างง่ายภายในกิจกรรม splash:

//this goes on the class level (like a class/instance variable, not in a method) of your splash activity:
private BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        //kill activity here!!!
        //mission accomplished!
    }
};

และลงทะเบียนเครื่องรับใหม่ของคุณกับ LocalBroadcastManager เพื่อฟังการออกอากาศจากกิจกรรมที่สองของคุณ:

//notice the string sent to the intent filter, this is where you tell the BroadcastManager which broadcasts you want to listen to!
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(receiver, new IntentFilter("broadcast identifier"));

โปรดทราบว่าคุณสามารถใช้ทรัพยากรคงที่หรือสตริงสำหรับสตริง "ตัวระบุการออกอากาศ"


เพื่อประสิทธิภาพโฆษณาด้านความปลอดภัยที่ดีขึ้นให้ใช้LocalBroadcastManagerที่นี่
Alexander Farber

0

หากคุณใช้finish()เพียงเพื่อหลีกเลี่ยงไม่ให้แอปใหม่เริ่มต้นในสแต็ก (งาน) ของแอปของคุณคุณสามารถใช้Intent.FLAG_ACTIVITY_NEW_TASKแฟล็กเมื่อเริ่มแอปพลิเคชันใหม่และไม่ต้องโทรfinish()เลย ตามเอกสารนี้เป็นแฟล็กที่จะใช้เพื่อปรับใช้ลักษณะการทำงานสไตล์ "ตัวเรียกใช้งาน"

// just add this line before you start an activity
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

0

ใช้วิธีการเหล่านี้ภายในActivityไฟล์.

isDestroyed()

เพิ่มใน Api 17
ส่งคืนจริงหากมีการเรียก onDestroy () สุดท้ายในกิจกรรมดังนั้นอินสแตนซ์นี้จึงตาย

isFinishing()

เพิ่มใน Api 1
ตรวจสอบเพื่อดูว่ากิจกรรมนี้อยู่ระหว่างการดำเนินการเสร็จสิ้นหรือไม่เนื่องจากคุณเรียกว่าเสร็จสิ้น () หรือมีผู้อื่นร้องขอให้เสร็จสิ้น สิ่งนี้มักใช้ใน onPause () เพื่อพิจารณาว่ากิจกรรมนั้นหยุดชั่วคราวหรือเสร็จสิ้นอย่างสมบูรณ์


จากเอกสาร Memory Leaks

ข้อผิดพลาดทั่วไปAsyncTaskคือการจับข้อมูลอ้างอิงที่ชัดเจนถึงโฮสต์Activity(หรือFragment):

class MyActivity extends Activity {
  private AsyncTask<Void, Void, Void> myTask = new AsyncTask<Void, Void, Void>() {
    // Don't do this! Inner classes implicitly keep a pointer to their
    // parent, which in this case is the Activity!
  }
}

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

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

class MyActivity extends Activity {
  static class MyTask extends AsyncTask<Void, Void, Void> {
    // Weak references will still allow the Activity to be garbage-collected
    private final WeakReference<MyActivity> weakActivity;

    MyTask(MyActivity myActivity) {
      this.weakActivity = new WeakReference<>(myActivity);
    }

    @Override
    public Void doInBackground(Void... params) {
      // do async stuff here
    }

    @Override
    public void onPostExecute(Void result) {
      // Re-acquire a strong reference to the activity, and verify
      // that it still exists and is active.
      MyActivity activity = weakActivity.get();
      if (activity == null
          || activity.isFinishing()
          || activity.isDestroyed()) {
        // activity is no longer valid, don't do anything!
        return;
      }

      // The activity is still valid, do main-thread stuff here
    }
  }
}

0

นี่คือวิธีแก้ปัญหาโดยใช้Applicationคลาส

public class AppSingleton extends Application implements Application.ActivityLifecycleCallbacks {

private WeakReference<Context> foregroundActivity;


@Override
public void onActivityResumed(Activity activity) {
    foregroundActivity=new WeakReference<Context>(activity);
}

@Override
public void onActivityPaused(Activity activity) {
    String class_name_activity=activity.getClass().getCanonicalName();
    if (foregroundActivity != null && 
            foregroundActivity.get().getClass().getCanonicalName().equals(class_name_activity)) {
        foregroundActivity = null;
    }
}

//............................

public boolean isOnForeground(@NonNull Context activity_cntxt) {
    return isOnForeground(activity_cntxt.getClass().getCanonicalName());
}

public boolean isOnForeground(@NonNull String activity_canonical_name) {
    if (foregroundActivity != null && foregroundActivity.get() != null) {
        return foregroundActivity.get().getClass().getCanonicalName().equals(activity_canonical_name);
    }
    return false;
}
}

คุณสามารถใช้งานได้ดังนี้

((AppSingleton)context.getApplicationContext()).isOnForeground(context_activity);

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


0

ฉันไม่รู้ว่าทำไมไม่มีใครพูดถึง sharedPreferences สำหรับกิจกรรม A การตั้งค่า SharedPreference เช่นนั้น (ตัวอย่างเช่นใน onPause ()):

SharedPreferences pref = context.getSharedPreferences(SHARED_PREF, 0);
SharedPreferences.Editor editor = pref.edit();
editor.putBoolean("is_activity_paused_a", true);
editor.commit();

ฉันคิดว่านี่เป็นวิธีที่เชื่อถือได้ในการติดตามการแสดงผลกิจกรรม


0

จะActivity.onWindowFocusChanged(boolean hasFocus)มีประโยชน์ที่นี่? ที่บวกธงชั้นระดับบางอย่างเช่นisFocusedว่าonWindowFocusChangedชุดจะเป็นวิธีที่ง่ายที่จะบอกที่จุดใด ๆ ในกิจกรรมของคุณถ้ามันจะเน้นหรือไม่ จากการอ่านเอกสารดูเหมือนว่าจะตั้งค่า "เท็จ" อย่างถูกต้องในทุกสถานการณ์ที่กิจกรรมไม่ได้อยู่ใน "เบื้องหน้า" ทางกายภาพโดยตรงเช่นหากมีการแสดงกล่องโต้ตอบหรือถาดการแจ้งเตือนถูกดึงลง

ตัวอย่าง:

boolean isFocused;
@Override
void onWindowFocusChanged (boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    isFocused = hasFocus;
}

void someMethod() {
    if (isFocused) {
        // The activity is the foremost object on the screen
    } else {
        // The activity is obscured or otherwise not visible
    }
}

0

หากคุณใช้EventBusเป็นวิธีการที่เรียกว่าhasSubscriberForEventสามารถใช้เพื่อตรวจสอบว่าActivityโฟกัสอยู่หรือไม่


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