संपूर्ण इतिहास स्टैक को साफ़ करें और Android पर एक नई गतिविधि शुरू करें


332

क्या स्टैक पर एक गतिविधि शुरू करना संभव है, इससे पहले पूरे इतिहास को साफ़ करना?

स्थिति

मेरे पास एक गतिविधि स्टैक है जो या तो A-> B-> C या B-> C (स्क्रीन A उपयोगकर्ताओं के टोकन का चयन करता है, लेकिन कई उपयोगकर्ताओं के पास केवल एक टोकन होता है)।

स्क्रीन सी में उपयोगकर्ता एक्शन ले सकता है जो स्क्रीन बी को अमान्य बना देता है, इसलिए एप्लिकेशन उन्हें स्क्रीन ए में ले जाना चाहता है, चाहे वह पहले से ही स्टैक में हो। स्क्रीन ए तो मेरे आवेदन में स्टैक पर एकमात्र आइटम होना चाहिए।

टिप्पणियाँ

इसी तरह के कई अन्य प्रश्न हैं, लेकिन मुझे ऐसा कुछ भी नहीं मिला है जो इस सटीक प्रश्न का उत्तर देता हो। मैंने कॉल करने की कोशिश की getParent().finish()- यह हमेशा एक शून्य सूचक अपवाद के परिणामस्वरूप होता है। FLAG_ACTIVITY_CLEAR_TOPकेवल तभी काम करता है जब गतिविधि पहले से ही स्टैक पर हो।

जवाबों:


658

एपीआई स्तर 11 में इसके लिए एक नया आशय ध्वज जोड़ा गया: Intent.FLAG_ACTIVITY_CLEAR_TASK

बस स्पष्ट करने के लिए, इसका उपयोग करें:

जावा

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);


Kotlin

intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK


दुर्भाग्य से एपीआई lvl <= 10 के लिए, मुझे अभी तक इसका कोई साफ समाधान नहीं मिला है। "DontHackAndroidLikeThis" समाधान वास्तव में शुद्ध hackery है। यदि आप ऐसा नहीं करना चाहिए। :)

संपादित करें: एपीआई <= 10 के लिए @ बेन पियर्सन की टिप्पणी के अनुसार, अब उसी के लिए IntentCompat वर्ग का उपयोग किया जा सकता है । IntentCompat.FLAG_ACTIVITY_CLEAR_TASKकार्य को साफ़ करने के लिए कोई ध्वज का उपयोग कर सकता है । तो आप पूर्व एपीआई स्तर 11 का भी समर्थन कर सकते हैं।


23
बस स्पष्ट करने के लिए, इसका उपयोग करें: इरादे ।setFlags (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
user123321

2
Intent.FLAG_ACTIVITY_NEW_TASK के बिना ऐप कभी-कभी केवल एंड्रॉइड 4 पर ही बंद हो जाता है
अधिकतम

22
IntentCompat के पास अब कार्य को साफ़ करने के लिए एक ध्वज है, इसलिए आप पूर्व API स्तर 11 का समर्थन कर सकते हैं - डेवलपर.
बेन पियर्सन

10
IntentCompat.FLAG_ACTIVITY_CLEAR_TASK को API स्तर वाले उपकरणों पर अनदेखा किया जाता है <10. डेवलपर
डेविड

7
IntentCompat का झंडा केवल एक दुर्घटना से बचने के लिए है, लेकिन @David के अनुसार कुछ भी नहीं करता है।
स्टिल

49

केस 1: केवल दो गतिविधि A और B:

यहाँ गतिविधि का प्रवाह A-> B है। B से बैकबटन पर क्लिक करने पर हमें एप्लिकेशन को बंद करने की आवश्यकता होती है, जबकि ए से कॉल बी शुरू करने के दौरान एक्टिविटी शुरू होती है () इससे एक्टिविटी ए के लिए बैकस्टैक.गेजे में ए गतिविधि को स्टोर करने से एंड्रॉइड को रोक दिया जाता है। आवेदन की स्क्रीनिंग / स्प्लैश स्क्रीन।

Intent newIntent = new Intent(A.this, B.class);
startActivity(newIntent);
finish();

केस 2: दो से अधिक सक्रियताएं:

अगर गतिविधि डी से आते समय ए-> बी-> सी-> डी-> बी और एक्टिविटी बी में बैक बटन पर क्लिक करना है, तो उस स्थिति में हमें इसका उपयोग करना चाहिए।

Intent newIntent = new Intent(D.this,B.class);
newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(newIntent);

यहां गतिविधि B को एक नए उदाहरण के बजाय Intent.FLAG_ACTIVITY_CLEAR_TOP और Intent.FLAG_ACTIVITY_NEW_TASK की वजह से बैकस्टैक से शुरू किया जाएगा। स्टैक को साफ करता है और इसे शीर्ष एक बनाता है। जब हम बैक बटन दबाते हैं तो पूरा आवेदन समाप्त हो जाएगा।


2
इसने मेरे लिए काम किया। मैंने उन झंडों को सभी गतिविधियों में डाला। उन गतिविधियों में बैक बटन पूरी तरह से पिछली गतिविधि पर जा रहे हैं, और मुख्य गतिविधि में आशय इरादे के साथ = नया आशय (Intent.ACTION_MAIN); intent.addCategory (Intent.CATEGORY_HOME); intent.addFlags (Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK); startActivity (आशय); समाप्त(); पूरा ऐप बंद है, फिर भी मेमोरी में है, लेकिन कोई सक्रिय नहीं है, और यदि आप पुनः आरंभ करते हैं, तो ऐप स्प्लैश स्क्रीन पर चला जाता है :)
राको

यह सबसे अच्छा जवाब होना चाहिए। अगर किसी के पास मेरे साथ समान परिदृश्य है: A-> B-> C-> D-> E -> (B) E-> B से एक परिणाम होना चाहिए: A-> B
शेम एलेक्सिस शावेज

39

Android के नए संस्करण के साथ> = API 16 का उपयोग करें finishAffinity()

दृष्टिकोण> = एपीआई 16 के लिए उपयुक्त है।

Intent mIntent = new Intent(mContext,MainActivity.class);
finishAffinity();
startActivity(mIntent);
  • यह नई गतिविधि शुरू करने के समान है, और सभी स्टैक को साफ़ करें।
  • या MainActivity / FirstActivity के लिए पुनरारंभ करें।

1
यह चाल किया, झंडे मेरे लिए 4.xx पर काम कर रहे थे और यह पूरी तरह से काम किया! धन्यवाद
जोनाथन Aste

1
यह सही उत्तर प्रतीत होता है यदि आपका लक्ष्य वर्तमान गतिविधि सहित नीचे और सभी गतिविधियों को पूरा करना है और अपने स्वयं के कार्य में एक नई गतिविधि शुरू करना है।
टोबे

24

मैंने इस पर भी कुछ घंटे बिताए ... और सहमत हूं कि FLAG_ACTIVITY_CLEAR_TOP को लगता है कि आप क्या चाहते हैं: लॉन्च किए जा रहे गतिविधि को छोड़कर, पूरे स्टैक को साफ़ करें, इसलिए बैक बटन एप्लिकेशन से बाहर निकलता है। फिर भी जैसा कि माइक रिपास ने उल्लेख किया है, FLAG_ACTIVITY_CLEAR_TOP केवल तभी काम करता है जब आप जिस गतिविधि को शुरू कर रहे हैं वह पहले से ही स्टैक में है; जब गतिविधि नहीं होती है, तो ध्वज कुछ भी नहीं करता है।

क्या करें? स्टैक में लॉन्च की जा रही गतिविधि को FLAG_ACTIVITY_NEW_TASK के साथ रखें, जो उस गतिविधि को इतिहास स्टैक पर एक नए कार्य की शुरुआत बनाती है। फिर FLAG_ACTIVITY_CLEAR_TOP ध्वज जोड़ें।

अब, जब FLAG_ACTIVITY_CLEAR_TOP स्टैक में नई गतिविधि को खोजने के लिए जाता है, तो यह वहाँ हो जाएगा और बाकी सब साफ़ होने से पहले इसे खींच लिया जाएगा।

यहाँ मेरा लॉगआउट फ़ंक्शन है; व्यू पैरामीटर वह बटन है जिससे फ़ंक्शन जुड़ा हुआ है।

public void onLogoutClick(final View view) {
    Intent i = new Intent(this, Splash.class);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    startActivity(i);
    finish();
}

1
क्या आपको CLEAR_TOP के बजाय CLEAR_TASK से मतलब है?
एंडी

14

आपको स्टैक नहीं बदलना चाहिए। Android बैक बटन वेब ब्राउजर की तरह काम करना चाहिए।

मैं इसे करने का एक तरीका सोच सकता हूं, लेकिन यह काफी हैक है।

  • singleTaskइसे AndroidManifest उदाहरण में जोड़कर अपनी गतिविधियाँ करें :

    <activity android:name=".activities.A"
              android:label="@string/A_title"
              android:launchMode="singleTask"/>
    
    <activity android:name=".activities.B"
              android:label="@string/B_title"
              android:launchMode="singleTask"/>
  • बढ़ाएँ Applicationजो तर्क है कि कहाँ जाना है का आयोजन करेगा।

उदाहरण:

public class DontHackAndroidLikeThis extends Application {

  private Stack<Activity> classes = new Stack<Activity>();

  public Activity getBackActivity() {
    return classes.pop();
  }

  public void addBackActivity(Activity activity) {
    classes.push(activity);
  }
}

अ से ब तक:

DontHackAndroidLikeThis app = (DontHackAndroidLikeThis) getApplication();
app.addBackActivity(A.class); 
startActivity(this, B.class);

B से C:

DontHackAndroidLikeThis app = (DontHackAndroidLikeThis) getApplication();
app.addBackActivity(B.class); 
startActivity(this, C.class);

सी में:

If ( shouldNotGoBackToB() ) {
  DontHackAndroidLikeThis app = (DontHackAndroidLikeThis) getApplication();
  app.pop();
}

और pop()स्टैक से बैक बटन को संभालें ।

एक बार फिर, आपको ऐसा नहीं करना चाहिए :)


अंत में मैं स्टैक को छोड़ने का फैसला करता हूं और केवल उपयोगकर्ता को बताता हूं कि उनकी वर्तमान स्क्रीन अमान्य थी
केसबश

1
बहुत निराशा होती है कि Android हमें इस तरह से पहले से ही गतिविधि स्टैक का प्रबंधन नहीं करने देता है। मुझे अपने भविष्य के एंड्रॉइड ऐप्स में इस समाधान का उपयोग करने के लिए लुभाया जाएगा।
सेफ्रॉन

4
बस स्पष्ट होना चाहिए कि इसका उपयोग क्यों नहीं किया जाना चाहिए: यह मेमोरी लीक बनाने का एक अच्छा तरीका है। कुछ बिंदु पर ओएस पृष्ठभूमि गतिविधियों को मारने का निर्णय Applicationले सकता है, लेकिन चूंकि उनके उदाहरण हैं कि ओएस नष्ट हो गई गतिविधियों से उस रैम को मुक्त नहीं कर पाएगा।
विट ख़ुदेंको

@ क्या अन्य मुद्दे हैं? स्मृति रिसाव को केवल कमजोर संदर्भों को ध्यान में रखते हुए पैच किया जा सकता है।
नवीन

1
@Navin हाँ, लीक को कमजोर रिफ से बचा जा सकता है, लेकिन अगर GC के बाद एक लाइव एक्टिविटी रेफ नहीं होगा तो पूरा दृष्टिकोण बेकार है। एक बार फिर - ऐसा मत करो, यह Android के लिए एक गलत दृष्टिकोण है।
विट खूदेंको

12

एक नई गतिविधि शुरू करने के तुरंत बाद, का उपयोग करके startActivity, सुनिश्चित करें कि आप कॉल करते हैं finish()ताकि वर्तमान गतिविधि नए के पीछे खड़ी न हो।


इतिहास स्टैक पर मधुमक्खी पालन से एक निश्चित स्थिति में ठीक एक गतिविधि को रोकने के लिए +1 अच्छा समाधान।
मार्सबियर

27
यदि आप एक से अधिक गतिविधि स्टैक में खत्म पिछली गतिविधि स्पष्ट लेकिन दूसरों को नहीं होगा .... है काम नहीं करता है
Necronet

5

इसे इस्तेमाल करे:

Intent logout_intent = new Intent(DashboardActivity.this, LoginActivity.class);
logout_intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
logout_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
logout_intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(logout_intent);
finish();

4

उन्नत पुन: प्रयोज्य कोटलिन:

आप सेटर विधि का उपयोग करके सीधे ध्वज सेट कर सकते हैं। Kotlin में orहै प्रतिस्थापन जावा बिटवाइज़ या के लिए |

intent.flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK

यदि आप इसे नियमित रूप से उपयोग करने की योजना बनाते हैं, तो एक इंटेंट एक्सटेंशन फ़ंक्शन बनाएं

fun Intent.clearStack() {
    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}

फिर आप इरादे शुरू करने से पहले सीधे इस फ़ंक्शन को कॉल कर सकते हैं

intent.clearStack()

यदि आपको अन्य स्थितियों में अतिरिक्त झंडे जोड़ने के विकल्प की आवश्यकता है, तो एक्सटेंशन फ़ंक्शन में एक वैकल्पिक परम जोड़ें।

fun Intent.clearStack(additionalFlags: Int = 0) {
    flags = additionalFlags or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}


2

कोड के नीचे आज़माएं,

Intent intent = new Intent(ManageProfileActivity.this, LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|
                Intent.FLAG_ACTIVITY_CLEAR_TASK| 
                Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

अगर इस तरह की गतिविधि का उपयोग कर रहा हूं तो एक बार फिर से अपी को कॉल करें, लेकिन पहले से मौजूद सभी स्टैच्यू को साफ कर दिया गया है
हर्षा

2

मेरे लिए कोई भी उपरोक्त विधियों में से काम नहीं।

बस पिछली सभी गतिविधि को साफ़ करने के लिए ऐसा करें :

finishAffinity() // if you are in fragment use activity.finishAffinity()
Intent intent = new Intent(this, DestActivity.class); // with all flags you want
startActivity(intent)

-1

कभी-कभी आपका एंड्रॉइड एमुलेटर ग्रहण डीडीएमएस टूल को कनेक्ट करने और एडीबी को मैन्युअल रूप से शुरू करने के लिए कहने में विफल हो सकता है। उस स्थिति में आप कमांड प्रॉम्प्ट का उपयोग करके adb को शुरू या बंद कर सकते हैं।


1
कभी-कभी आपका एंड्रॉइड एमुलेटर ग्रहण डीडीएमएस टूल को कनेक्ट करने में असमर्थ हो सकता है और एडीबी को मैन्युअल रूप से शुरू करने के लिए कह सकता है। उस स्थिति में आप कमांड प्रॉम्प्ट का उपयोग करके adb को शुरू या बंद कर सकते हैं। आशय i = नया आशय (OldActivity.this, NewActivity.class); // नया कार्य और स्पष्ट झंडे सेट करें i.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) startActivity (i);
राजेशकुमार जी

-2

मैंने पाया कि बहुत ही सरल हैक इस प्रकार नए तत्व जोड़ते हैं AndroidManifest: -

<activity android:name=".activityName"
          android:label="@string/app_name"
          android:noHistory="true"/>

android:noHistoryस्टैक से अपनी अवांछित गतिविधि को साफ कर देगा।


2
यदि आप इस गतिविधि में अनुमति मांगते हैं, तो यह aproachment Android 6.0+ पर समस्याएँ पैदा कर सकता है।
विटाली ए
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.