เจตนาที่ชัดเจน


111

แอป Android ของฉันถูกเรียกโดยเจตนาที่ส่งผ่านข้อมูล (อยู่ระหว่างการพิจารณาในแถบสถานะ)

เมื่อฉันกดปุ่มโฮมและเปิดแอปอีกครั้งโดยกดปุ่มโฮมค้างไว้มันจะเรียกเจตนาอีกครั้งและยังคงมีความพิเศษเหมือนเดิม

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
      super.onSaveInstanceState(savedInstanceState);
    }
    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
      super.onRestoreInstanceState(savedInstanceState);
    }

นี่คือรหัสที่ไม่ทำงานอย่างที่ควรจะเป็น

    String imgUrl;
    Bundle extras = this.getIntent().getExtras();


    if(extras != null){
        imgUrl = extras.getString("imgUrl");
        if( !imgUrl.equals(textView01.getText().toString()) ){

            imageView.setImageDrawable( getImageFromUrl( imgUrl ) );
            layout1.setVisibility(0);
            textView01.setText(imgUrl);//textview to hold the url

        }

    }

และเจตนาของฉัน:

public void showNotification(String ticker, String title, String message, 
    String imgUrl){
    String ns = Context.NOTIFICATION_SERVICE;
    NotificationManager mNotificationManager = 
        (NotificationManager) getSystemService(ns);
    int icon = R.drawable.icon;        // icon from resources
    long when = System.currentTimeMillis();         // notification time
    CharSequence tickerText = ticker;              // ticker-text

    //make intent
    Intent notificationIntent = new Intent(this, activity.class);
    notificationIntent.putExtra("imgUrl", imgUrl);
    notificationIntent.setFlags(
        PendingIntent.FLAG_UPDATE_CURRENT | 
        PendingIntent.FLAG_ONE_SHOT);
    PendingIntent contentIntent = 
        PendingIntent.getActivity(this, 0, 
        notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT | 
        PendingIntent.FLAG_ONE_SHOT);

    //make notification
    Notification notification = new Notification(icon, tickerText, when);
    notification.setLatestEventInfo(this, title, message, contentIntent);
    //flags
    notification.flags = Notification.FLAG_SHOW_LIGHTS | 
        Notification.FLAG_ONGOING_EVENT | 
        Notification.FLAG_ONLY_ALERT_ONCE | 
        Notification.FLAG_AUTO_CANCEL;
    //sounds
    notification.defaults |= Notification.DEFAULT_SOUND;
    //notify
    mNotificationManager.notify(1, notification);
}

มีวิธีใดที่จะล้างเจตนาหรือตรวจสอบว่าเคยใช้มาก่อนหรือไม่?


คุณสามารถโพสต์รหัสของคุณได้หรือไม่?
xandy

ฉันเพิ่มรหัสในคำถามของฉัน
อังคาร

แทนที่จะล้าง Intent คุณสามารถกำหนดประเภทการเปิดตัวและจัดการโฟลว์ของแอพให้สอดคล้องกัน รับความพิเศษเฉพาะในกรณีที่มีการเปิดใช้งานสำหรับการแจ้งเตือนไม่ใช่จากพื้นหลัง stackoverflow.com/questions/4116110/clearing-intent/…
BB

คำตอบ:


168

อัพเดท:

ฉันไม่รู้ว่าคำตอบนี้จะถูกอ้างถึงมากขนาดนี้เมื่อฉันเขียนมันครั้งแรกเมื่อ 5 ปีที่แล้ว!

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

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


ฉันมีปัญหาเดียวกัน

คำตอบข้างต้นทำให้ฉันมาถูกทางและฉันพบวิธีแก้ปัญหาที่ง่ายกว่าให้ใช้:

getIntent().removeExtra("key"); 

วิธีการเรียกร้องให้ "ล้าง" เจตนา

มันตอบช้าไปหน่อยเนื่องจากมีคนถามเมื่อปีที่แล้ว แต่หวังว่านี่จะช่วยคนอื่นได้ในอนาคต


4
เมธอด removeExtra () ไม่ใช้พารามิเตอร์ String หรือไม่? เช่นนี้ getIntent (). removeExtra ("String");
tony9099

25
@Maks ฉันอาจจะผิด แต่ฉันคิดว่าสิ่งนี้จะใช้ไม่ได้ในสถานการณ์ต่อไปนี้: 1) เปิดกิจกรรมผ่านการแจ้งเตือน 2) จบกิจกรรมโดยกดปุ่มย้อนกลับ 3) เปิดกิจกรรมอีกครั้งผ่านประวัติ (แอพล่าสุด) อีกกรณีหนึ่งคือเมื่อระบบฆ่าแอปเนื่องจากขาดทรัพยากร (เปิดใช้งาน "อย่าเก็บกิจกรรม" ภายใต้ตัวเลือกของนักพัฒนาและหลังจากนั้นเพียงกดที่บ้านจากนั้นเปิดกิจกรรมอีกครั้งจากประวัติ) ฉันโพสต์วิธีแก้ปัญหาที่ฉันใช้ด้านล่าง หากคุณสามารถแสดงความคิดเห็นได้ก็จะดี
tato.rodrigo

2
น่าเสียดายที่มันไม่ได้ผลสำหรับเรา เราพบว่าการเริ่มต้นกิจกรรมใหม่ซึ่งจะเป็นการเริ่มต้นกิจกรรมทำให้ OnNewIntent เริ่มทำงานอีกครั้งด้วยเจตนาเดียวกัน
Le-roy Staines

2
แทนที่จะล้าง Intent คุณสามารถกำหนดประเภทการเปิดตัวและจัดการโฟลว์ของแอพให้สอดคล้องกัน รับความพิเศษเฉพาะในกรณีที่มีการเปิดใช้งานสำหรับการแจ้งเตือนไม่ใช่จากพื้นหลัง stackoverflow.com/questions/4116110/clearing-intent/…
BB

2
ไม่ได้ผลสำหรับฉัน ฉันประสบปัญหาเดียวกับที่ @ tato.rodrigo พูดถึงโดยที่เจตนาไม่ได้รับการเคลียร์หากกิจกรรมถูกเปิดผ่านการแจ้งเตือนหรือจากประวัติหรือเหตุผลอื่น ๆ ที่เขาพูดถึงดังนั้นสิ่งที่ฉันทำหลังจากใช้ข้อมูลเจตนาคือการรีเซ็ตเจตนาเช่น สิ่งนี้setIntent(new Intent())และมันทำงานได้ดีในขณะนี้
Shubhral

43

แก้ไข:ฉันกำลังแก้ไขเพื่อโพสต์โซลูชันทั้งหมดที่ฉันใช้

การแก้ปัญหานี้จะทำงานถ้าปัญหาคือ"ไม่รันโค้ดบางอย่างเมื่อกิจกรรมเริ่มจากประวัติศาสตร์ (แอปล่าสุด)"

ก่อนอื่นให้ระบุbooleanในของคุณActivityเพื่อระบุว่าIntentบริโภคไปแล้วหรือไม่:

    private boolean consumedIntent;

จากนั้นจัดเก็บและเรียกคืนค่านี้อย่างปลอดภัยโดยใช้onSaveInstanceStateและonCreateวิธีการจัดการกับการเปลี่ยนแปลงการกำหนดค่าและกรณีที่ระบบอาจฆ่าคุณActivityเมื่อไปที่พื้นหลัง

    private final String SAVED_INSTANCE_STATE_CONSUMED_INTENT = "SAVED_INSTANCE_STATE_CONSUMED_INTENT";

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean(SAVED_INSTANCE_STATE_CONSUMED_INTENT, consumedIntent);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //set content view ...

        if( savedInstanceState != null ) {
            consumedIntent = savedInstanceState.getBoolean(SAVED_INSTANCE_STATE_CONSUMED_INTENT);
        }

        //other initializations
    }

ตอนนี้ตรวจสอบว่าคุณสามารถเรียกใช้รหัสของคุณภายใต้onResumeวิธีการ

    @Override
    protected void onResume() {
        super.onResume();

        //check if this intent should run your code
        //for example, check the Intent action
        boolean shouldThisIntentTriggerMyCode = [...];
        Intent intent = getIntent();
        boolean launchedFromHistory = intent != null ? (intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0 : false;
        if( !launchedFromHistory && shouldThisIntentTriggerMyCode && !consumedIntent ) {
            consumedIntent = true;
            //execute the code that should be executed if the activity was not launched from history
        }
    }

นอกจากนี้หากคุณActivityกำหนดค่าไว้singleTopคุณควรรีเซ็ตค่าสถานะของคุณเมื่อมีการIntentส่งมอบใหม่

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        consumedIntent = false;
    }

12
ขอบคุณมาก! ฉันได้ช่วยรหัส(intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)นี้แล้วตอนนี้ฉันสามารถรู้ได้ว่าเวลาเริ่มกิจกรรมนั้นมาจากประวัติและฉันสามารถเพิกเฉยต่อความพิเศษของฉันได้
Roman Nazarevych

1
@Lemberg ฉันมีปัญหาเดียวกันและฉันได้แก้ไขเช่นเดียวกับคุณหากคุณใช้สิ่งพิเศษบางอย่างที่มาจากการแจ้งเตือนแบบพุชมีความเสี่ยงที่จะเริ่มกิจกรรมของคุณจากประวัติและไม่อยู่ใช้บริการพิเศษของคุณและเปลี่ยนเส้นทางไปยังการกระทำเดียวกันกับของคุณ ผลักดันการแจ้งเตือน ธงเปิดตัว
FromHistory

จะใช้งานได้หรือไม่แม้ว่ากิจกรรมจะถูกทำลายและเราเปิดอีกครั้งจากกองประวัติ
25

เยี่ยมมาก! ดูเหมือนว่าจะใช้งานได้แม้ว่าแอปจะถูกทำลาย ... แต่โปรด @ tato.rodrigo ลบออกboolean shouldThisIntentTriggerMyCode = [...];จากคำตอบ (ใช้เพื่ออะไร)
user25

ในกรณีของฉันที่มีการแจ้งเตือนหลายรายการสำหรับผู้ใช้บางรายผู้ใช้จะดีกว่าconsumedIntentเนื่องจากStringมี Uid การแจ้งเตือน สามารถเพิ่ม Uid นี้ในการแจ้งเตือนที่แบ็กเอนด์เป็นการประทับเวลาปัจจุบัน นอกจากนี้คุณควรบันทึก Uid นี้onSaveInstanceStateเฉพาะในกรณีที่ Intent กำลังมาในรูปแบบonCreateเท่านั้น ซึ่งหมายความว่าคุณไม่ควรบันทึก Uid onNewIntentจาก
Konstantin Konopko

22

คำตอบ Maks ใช้สำหรับการล้างข้อมูลเพิ่มเติม:

    getIntent().removeExtra("key"); 

คำสั่งที่มีประโยชน์อีกอย่างคือ:

    getIntent().setAction("");

คุณยังสามารถติดแท็กความตั้งใจได้โดยโทร:

    getIntent().putExtra("used", true);

จากนั้นตรวจสอบค่า


21

เมื่อเราเปิดแอพ Android จากประวัติ (แอพล่าสุด) แอพสามารถเปิดตัวได้โดยใช้ค่าสถานะเจตนาที่แตกต่างกันสามแบบ

  1. FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
    นี่คือเวลาที่มีการเปิดกิจกรรมจากประวัติของแอพที่ย่อขนาดให้เล็กสุด (กดปุ่มโฮมแบบยาว)
    ค่าคงที่: 1048576 (0x00100000)
  2. FLAG_ACTIVITY_NEW_TASK
    นี่คือเวลาที่เริ่มกิจกรรมผ่าน "คลิกไอคอนแอปพลิเคชัน" หรือผ่าน " ตัวกรองเจตนา " กิจกรรมนี้จะกลายเป็นจุดเริ่มต้นของงานใหม่ในกองประวัตินี้
    ค่าคงที่: 268435456 (0x10000000)
  3. FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY | FLAG_ACTIVITY_NEW_TASK
    นี่คือตอนที่แอพถูกปิดโดยกดปุ่มย้อนกลับจากนั้นกลับมาจากประวัติ (แอพล่าสุด)
    ค่าคงที่: 269484032 (0x10100000)

ค่าคงที่สามารถเรียกดูได้ทาง getIntent().getFlags()

ในกรณีที่สาม Android จะโหลดค่า Intent สุดท้ายซ้ำจากหน่วยความจำ ดังนั้นความตั้งใจของแอปของคุณ ( getIntent) จะมีค่าจากจุดประสงค์สุดท้ายที่เปิดตัวแอป

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

 <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER"/>
 </intent-filter>

แต่ในกรณีที่สาม (แอปที่เลิกใช้แล้วเปิดตัวจากประวัติแอปล่าสุด) ระบบปฏิบัติการ Android จะใช้ความตั้งใจสุดท้ายที่เปิดตัวแอปก่อนที่แอปจะออก (โดยกดปุ่มย้อนกลับ) ดังนั้นคุณจึงมีค่าความตั้งใจเก่าและการไหลของแอปไม่เหมาะสม

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

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

ดังนั้นใน LaunchActivity คุณ (หนึ่งซึ่งมีตัวกรองความตั้งใจที่กำหนดไว้ในที่ประจักษ์), คุณสามารถใช้รหัสต่อไปนี้ในonCreate(), onStart()หรือonResume()วิธีการ

if(getIntent().getFlags() == (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)) {
    //app is launched from recent apps after it was closed
        normalLaunch();
    } else {
        String intentAction = getIntent().getAction();
        String scheme = getIntent().getScheme();
        //app is launched via other means
        // URL intent scheme, Intent action etc
        if("https".equalsIgnoreCase(scheme)) {
            // URL intent for browser
        } else if("com.example.bb".equalsIgnoreCase(intentAction)) {
            // App launched via package name
        } else {
            // App was launched via Click on App Icon, or other means
            normalLaunch();
        }
    }

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


1
ฮีโร่ทุกคนไม่สวมหมวก!
Sdghasemi

ฉันไม่รู้ แต่มันจะคืนค่าจริงเสมอgetIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORYไม่สำคัญว่าฉันจะเริ่มกิจกรรมจากกิจกรรมอื่น (วิธี startActivity) หรือเปิดใหม่จากกองประวัติ (แอพล่าสุด)
25

คุณจะต้องใช้ร่วมกับแฟล็กอื่นอาจจะเป็น FLAG_ACTIVITY_NEW_TASK
BB

1
วิธีนี้ใช้ไม่ได้เมื่อกิจกรรมถูกฆ่าในพื้นหลังเนื่องจากการตั้งค่า Dev "อย่าเก็บกิจกรรม" ในกรณีนี้ getIntent () getFlags () จะเหมือนกับเมื่อกิจกรรมเริ่มต้นเป็นครั้งแรก
Malachiasz

ขอบคุณคำอธิบาย แต่ไม่เป็นไปตามที่ตั้งใจไว้
Azlan Jamal

18

การล้างวัตถุเจตนา:

intent.replaceExtras(new Bundle());
intent.setAction("");
intent.setData(null);
intent.setFlags(0);

2
นี่ควรเป็นคำตอบที่ได้รับการยอมรับ ใช้งานได้จริง!
Martin Erlic

2
ไม่ทำงานเมื่อมีการตรวจสอบ "ไม่เก็บกิจกรรม" ในตัวเลือกของนักพัฒนา
Jemshit Iskenderov

8

คำตอบสั้น ๆ คือไม่มีทาง

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

setAction("")

แต่ไม่ได้ผลเนื่องจากเจตนาถูกบันทึกไว้แล้วจนถึงช่วงเวลาที่คุณได้รับภายในเมธอด onNewIntent () หรือ onStart ()

ฉันแก้ปัญหาโดยหลีกเลี่ยงการใช้เจตนา ปัญหาของฉันคล้ายกับปัญหาที่ผู้เขียนโพสต์ ฉันพยายามใช้ Global Exit จากแอปพลิเคชันผ่านการควบคุมในพื้นที่แจ้งเตือน ควรหยุดบริการพื้นฐานและปิดกิจกรรมทั้งหมดของแอป คุณสามารถพบพฤติกรรมเดียวกันในแอปพลิเคชัน Waze

อัลกอริทึม:

  1. สร้าง PendingIntent สำหรับการควบคุมการแจ้งเตือนซึ่งส่งผ่านการดำเนินการ "ออก" ไปยังกิจกรรม แต่สำหรับกิจกรรมพิเศษซึ่งเป็นพร็อกซีธรรมดา
  2. โค้ดกิจกรรมพร็อกซี onStart () จะแยกวิเคราะห์เจตนาตรวจสอบการดำเนินการและตั้งค่าสถานะของโมเดลบางส่วนเป็น "Exited"
  3. กิจกรรมพร็อกซี onStart () โค้ดจะล้างเจตนาดั้งเดิมโดยใช้ setIntent ("") จากนั้นส่งต่อไปยังปลายทางกิจกรรม "รูท" โดยเรียก startActivity (ความตั้งใจ)
  4. กิจกรรมพร็อกซี onStart () รหัสเรียกเสร็จสิ้น ()
  5. ภายใน onStart () และ onNewIntent () ของสถานะโมเดลการตรวจสอบกิจกรรมปลายทางและการสิ้นสุดการโทร () หากเป็น "Exited" (และเรียก stopService () ในกรณีของฉันด้วย)

ฉันหวังว่านี่จะช่วยใครบางคนได้เพราะฉันไม่พบคำตอบในอินเทอร์เน็ต


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

5

ตรวจสอบให้แน่ใจว่าคุณกำลังใช้PendingIntent.FLAG_UPDATE_CURRENTธงPendingIntent

PendingIntent pendingIntent = PendingIntent.getActivity(this, 100, mPutIntent, PendingIntent.FLAG_UPDATE_CURRENT);

ไหนเป็นของคุณmPutIntentIntent

หวังว่านี่จะช่วยคุณได้


1
ช่วยชีวิตฉันไว้!!
eren130

1
ฉันไม่เข้าใจว่านี่ไม่ใช่คำตอบที่ยอมรับได้อย่างไร ความเสียใจเพียงอย่างเดียวของฉันมีอยู่อย่างเดียวคือการโหวตเพิ่มคะแนนเพียงครั้งเดียว ไชโย
Andy

2

เมื่อเร็ว ๆ นี้ฉันมีปัญหานี้และฉันแก้ไขได้โดยการเพิ่มการประทับเวลาเป็นพารามิเตอร์พิเศษให้กับจุดประสงค์:

private void launchActivity(Context context) {
    Intent intent = new Intent(context, MainActivity.class);
    intent.putExtra("KEY_EXTRA_TIMESTAMP", System.currentTimeMillis());
    context.startActivity(intent);
}

หลังจากนั้นบันทึกการประทับเวลาในการตั้งค่าที่ใช้ร่วมกัน:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    long time = getIntent().getLongExtra("KEY_EXTRA_TIMESTAMP", -1);
    long previousTime = getPreferences(MODE_PRIVATE).getLong("timestamp", -1);

    //ignore if the timestamp is the same as the previous one  
    if (time != previousTime) {
        handleIntent(getIntent());
        if (time != -1) {
            //save the timestamp
            getPreferences(MODE_PRIVATE).edit().putLong("timestamp", time).apply();
        }
    }
}

1

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


3
สิ่งนี้อาจไม่ได้ผลเนื่องจากค่าบูลีนจะถูกสร้างขึ้นใหม่ (หากประกาศทั่วโลกในการเปิดใช้งาน) เมื่อกิจกรรมถูกหยุดและเริ่มต้นใหม่ (คลิกปุ่มโฮมเป็นต้น)
tony9099

1

เมื่อคุณประมวลผล Intent เสร็จแล้วให้ทำสิ่งนี้:

setIntent(null);

คุณจะไม่เห็น Intent ที่ประมวลผลนั้นอีกและคุณจะไม่ปิดบังปัญหาด้วยการแก้ไขเนื้อหาของ Intent ที่ประมวลผล


1

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

ในการแก้ปัญหาฉันเก็บค่าบูลีนไว้ในSharedPreferencesหลังจากที่ Intent Extras ถูกประมวลผล เมื่อ Intent เดียวกันถูกส่งไปยัง Activity อีกครั้งฉันจะตรวจสอบค่า SharedPreference และตัดสินใจที่จะประมวลผล Intent Extra ในกรณีที่คุณส่ง Intent Extra ใหม่ไปยังกิจกรรมเดียวกันคุณทำให้ค่า SharedPreference เป็นเท็จและ Activity จะประมวลผล ตัวอย่าง :

// Start Activity with Intent Extras
Intent intent = new Intent(context, MyActivity.class);
intent.putExtra("someData", "my Data");
// Set data as not processed
context.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE).edit().putBoolean("myActivityExtraProccessed", false).commit();
context.startActivity(intent);

...

public class MyActivity{

    ...
    public void someMethod(){
        boolean isExtrasProcessed = context.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE).getBoolean("myActivityExtraProccessed", false);  
         if (!isExtrasProcessed) {
              // Use Extras

              //Set data as processed
              context.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE).edit().putBoolean("myActivityExtraProccessed", true).commit();
         }
    }

}

การตั้งค่าไม่สมเหตุสมผลเพราะคุณไม่รู้ว่าคุณเริ่มกิจกรรมโดยใช้ startActivity หรือเปิดใหม่จาก History Stack ...
user25

@ user25 ฉันคิดว่ามีวิธีตรวจสอบว่าเปิดตัวจากแอพล่าสุดหรือไม่ แต่มันสำคัญหรือไม่เจตนาที่เพิ่มขึ้นจะถูกใช้หรือไม่ถ้ามันถูกใช้คุณรู้ว่ามันมาจากการแชร์ pref ฉันใช้สิ่งนี้เพื่อบริโภคการแจ้งเตือนแบบพุชพิเศษและไม่สำคัญว่ากิจกรรมจะเปิดอย่างไรสำหรับกรณีของฉัน
Jemshit Iskenderov

0

แม้ว่าจะล้างเจตนาและเจตนาพิเศษด้วยตนเองหลังจากแยกวิเคราะห์แล้วก็ตามดูเหมือนว่า Activity.getIntent () จะส่งคืน Intent ดั้งเดิมที่เริ่มต้นกิจกรรมเสมอ

เพื่อหลีกเลี่ยงปัญหานี้ฉันขอแนะนำสิ่งนี้:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // The Intent provided by getIntent() (and its extras) will persist through a restore
    // via savedInstance.  Because of this, restoring this activity from a
    // an instance that was originally started with extras (deep-link or 
    // pre-defined destination) may cause un-desired behavior
    // (ie...infinite loop of sending the user directly to somewhere else because of a
    // pre-defined alternate destination in the Intent's extras).
    //
    // To get around this, if restoring from savedInstanceState, we explicitly
    // set a new Intent *** to override the original Intent that started the activity.***
    // Note...it is still possible to re-use the original Intent values...simply
    // set them in the savedInstanceState Bundle in onSavedInstanceState.
    if (savedInstanceState != null) {
        // Place savedInstanceState Bundle as the Intent "extras"
        setIntent(new Intent().putExtras(savedInstanceState));
    }

    processIntent(getIntent())
}

private void processIntent(Intent intent) {
    if (getIntent().getExtras() == null) {
        // Protection condition
        return;
    }

    doSomething(intent.getExtras.getString("SOMETHING_I_REALLY_NEED_TO_PERSIST"));

    final String somethingIDontWantToPersist = 
        intent.getExtras.getString("SOMETHING_I_DONT_WANT_TO_PERSIST");

    if(somethingIDontWantToPersist != null) {
        doSomething(somethingIDontWantToPersist);
    }
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save selective extras from original Intent...
    savedInstanceState.putString("SOMETHING_I_REALLY_NEED_TO_PERSIST", "persistedValued");
    super.onSaveInstanceState(savedInstanceState);
}

ด้วยวิธีนี้มีกลไกในการถ่ายโอนข้อมูลเจตจำนงดั้งเดิมในขณะที่ยังคงรักษาความสามารถในการเก็บรักษาบางส่วนของเจตนา / เจตจำนงพิเศษเดิมไว้อย่างชัดเจน

โปรดทราบว่าฉันยังไม่ได้ทดสอบโหมดเรียกใช้กิจกรรมทั้งหมด


0

วิธีตรงไปตรงมาคือหลีกเลี่ยงการเรียก getIntent () จากวิธีอื่นที่ไม่ใช่ onCreate () แต่จะทำให้เกิดปัญหาในระหว่างการเปิดตัวครั้งต่อไปหากผู้ใช้ออกจากกิจกรรมของเราโดยการแตะปุ่มโฮม ฉันคิดว่าปัญหานี้ไม่มีวิธีแก้ปัญหาที่ใช้งานได้อย่างสมบูรณ์


0

ฉันประสบปัญหาเดียวกันและพยายามใช้วิธีการข้างต้น แต่ไม่ได้ผล

ฉันคิดว่ามันอาจเป็นสาเหตุของโหมดเปิดตัวของ acitvity ซึ่งฉันใช้โหมด singleTop

เมื่อฉันใช้แอปพื้นหลังและใช้ RamEater เพื่อจำลองปัญหาที่เจตนามักจะมีความพิเศษอยู่เสมอแม้ว่าฉันจะตั้งค่าว่างหรือลบคีย์

ปัญหานี้หมดไปโดยใช้พื้นที่จัดเก็บค่ากำหนดบน Android เพื่อตรวจสอบว่าผ่านแล้ว


0

ไม่ใช่แนวทางปฏิบัติที่ดีที่จะเพิ่มพิเศษอื่น ๆ เพียงเพื่อให้ทราบว่าของแถมถูกใช้ไปหรือไม่ทำไมไม่ทำสิ่งนี้:

if (intent.hasExtra(EXTRA_NAME) && intent.getBooleanExtra(EXTRA_NAME, false)) {
    // consume extra here after that set it to false
    putExtra(EXTRA_NAME, false)
}   

-1

แล้วเรื่องนี้ล่ะ? ตั้งค่า newIntent เป็นเจตนา

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);
}

1
ฉันไม่คิดว่าจะได้ผล เมื่อกิจกรรมถูกสร้างขึ้นใหม่จากประวัติศาสตร์เจตนาจะไม่ได้รับผลกระทบ
mdelolmo

-1

แล้วคุณจะล้างเจตนาเมื่อใด - แทนที่ด้วยเจตนาที่ว่างเปล่า?

เช่น.

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);
}

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

    Intent theIntent = getIntent();
    if ("myaction".equals(theIntent.getAction()) {
         handleIntent();
         onNewIntent(new Intent());  // <--- "clear" the intent by setting empty one
    }
}

-1

หวังว่าจะช่วยทุกคนได้ ก่อนอื่นเราจะได้รับเจตนา

//globally
Intent myIntent;

วางไว้ที่ใดที่หนึ่ง onCreate

myIntent = getIntent();
String data = myIntent.getStringExtra("yourdata");
//Your process here

ตอนนี้ให้ตั้งค่านี้ทุกครั้งที่แอปของเราถูกทำลายหรือออกเราจะลบข้อมูลออก

@Override
protected void onDestroy() {
    //TODO: Clear intents
    super.onDestroy();
    myIntent.removeExtra("data");
}
@Override
protected void onBackPressed() {
    //TODO: Clear intents
    super.onBackPressed();
    myIntent.removeExtra("data");
}

คุณจะเข้าใจถ้าสิ่งนี้ยังไม่เพียงพอเพียงแค่ค้นหาการโทรกลับ 'on' เพิ่มเติม


ความตั้งใจจะถูกล้างเมื่อคุณออกจากแอปเท่านั้นเช่น การปัดล่าสุด
Pixeldroid Modding

-2

ในขณะที่Intent.removeExtra("key")จะลบคีย์เฉพาะหนึ่งรายการออกจากส่วนเสริม แต่ยังมีเมธอดIntent.replaceExtras (Bundle)ซึ่งสามารถใช้เพื่อลบส่วนเสริมทั้งหมดจาก Intent หากnullถูกส่งผ่านเป็นพารามิเตอร์

จากเอกสาร:

แทนที่ส่วนเสริมใน Intent โดยสิ้นเชิงด้วย Bundle of extras ที่กำหนด

Parameters
extrasชุดพิเศษใหม่ใน Intent หรือ null เพื่อลบข้อมูลเพิ่มเติมทั้งหมด

เนื่องจากเมธอด putXXX () เริ่มต้นส่วนเสริมด้วย Bundle ใหม่หากเป็นโมฆะจึงไม่มีปัญหา


-3
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
intent.addCategory(Intent.CATEGORY_HOME);  
startActivity(intent);

2
คุณควรพิจารณารายละเอียดเกี่ยวกับคำตอบของคุณโดยให้รายละเอียดเกี่ยวกับสิ่งที่คุณกำลังทำและวิธีที่คำตอบนั้นตอบคำถามของ OP
forsvarir

1
@Ramkumar นี้จะพาผู้ใช้ไปที่บ้าน ซึ่งเห็นได้ชัดว่าเป็นเพียงกรณีเดียวจาก 10,000 กรณีที่อาจทำให้เกิดการเรียก onPause, onStop หรือ onDestroy
tony9099

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