बटन दबाने पर गतिविधि को दो बार लोड करने से कैसे रोकें


93

यदि मैं पहली बार क्लिक करने के तुरंत बाद दो बार बटन दबाता हूं तो गतिविधि को दो बार लोड करने से रोकने की कोशिश कर रहा हूं।

मेरे पास एक गतिविधि है जो एक बटन के क्लिक पर लोड होती है, कहते हैं

 myButton.setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) {
       //Load another activity
    }
});

अब क्योंकि लोड की जाने वाली गतिविधि में नेटवर्क कॉल हैं, लोड होने में थोड़ा समय लगता है (एमवीसी)। मैं इसके लिए एक लोडिंग दृश्य दिखाता हूं लेकिन अगर मैं इससे पहले दो बार बटन दबाता हूं, तो मैं गतिविधि को दो बार लोड होते हुए देख सकता हूं।

क्या किसी को पता है कि इसे कैसे रोका जाए?


आप गतिविधि को खोलने के बाद बटन को अक्षम कर सकते हैं ... और जब गतिविधि समाप्त हो जाती है, तो इसे फिर से सक्षम करें ... आप onActivityResult फ़ंक्शन
Maneesh

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

अक्षम करना आसान तरीके से काम नहीं करता है यदि बहुत ही अगला कथन किसी लंबी प्रक्रिया या गतिविधि के शुरू होने के लिए है ... बटन को अक्षम करने के लिए आपको एक अलग थ्रेड बनाना होगा ...
Awais तारिक

यदि एक ही एपीआई को दो बार यहां देखें तो देखें: techstricks.com/avoid-multiple-requests-when-use-volley
शिलेंद्र मद्दा

जवाबों:


69

बटन के ईवेंट श्रोता में, बटन को अक्षम करें और दूसरी गतिविधि दिखाएं।

    Button b = (Button) view;
    b.setEnabled(false);

    Intent i = new Intent(this, AnotherActitivty.class);
    startActivity(i);

onResume()बटन को फिर से सक्षम करने के लिए ओवरराइड करें।

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

        Button button1 = (Button) findViewById(R.id.button1);
        button1.setEnabled(true);
    }

1
यह सही तरीका है। यहां तक ​​कि यह आपके लिए बटन चयनित राज्यों (यदि आप उन्हें प्रदान करते हैं) और सभी सामग्री डिजाइन "उपहार" को संभालेंगे, तो आप एक साधारण मानक विजेट से उम्मीद करेंगे। मैं विश्वास नहीं कर सकता कि लोग इसके लिए टाइमर का उपयोग करते हैं। तब आप इन चीजों को संभालने के लिए अजीब पुस्तकालयों को देखना शुरू करते हैं ...
मार्टिन मारकोसिनी

157

इसे अपनी Activityपरिभाषा में जोड़ें AndroidManifest.xml...

android:launchMode = "singleTop"

उदाहरण के लिए:

<activity
            android:name=".MainActivity"
            android:theme="@style/AppTheme.NoActionBar"
            android:launchMode = "singleTop"/>

ठीक है, मुझे लगता है कि आप नई गतिविधि शुरू करने के बाद कुछ लंबी प्रक्रिया कर रहे हैं .. इसीलिए स्क्रीन काली हो जाती है। अब यदि आप उस काली स्क्रीन से बचना चाहते हैं, तो आपको गतिविधि के प्रारंभ में एक प्रगति संवाद दिखाना चाहिए और एक अलग थ्रेड (यानी यूआई थ्रेड या बस एस्क् यूंट क्लास का उपयोग करें) में लंबी प्रोसेसिंग करनी चाहिए। एक बार आपकी प्रोसेसिंग हो जाने के बाद उस डायलॉग को छिपा दें। यह मेरी जानकारी में सबसे अच्छा समाधान है और मैंने इसे कई बार इस्तेमाल किया है ... :)
आवा तारिक

मेरे पास दिखाने के लिए संवाद है। लेकिन हाँ, मैं onCreate में वेब को इंगित करने वाला एक तरीका है। लेकिन क्या यह एकमात्र उपाय है? क्योंकि इस बिंदु पर, मैं धागे और सभी को बदलने के बिना संभालना चाहता हूं। तो क्या आप अन्य संभावित तरीके जानते हैं। और मैं अपनी सूची एडाप्टर में बटन कर रहा हूं और मैंने इसके लिए xml में विधि की घोषणा की है, न कि प्रोग्रामिक रूप से
तेजस

2
और क्या संभव है ??? एक तरह से या किसी अन्य को आपको एक चिकनी दिखने वाली ऐप प्राप्त करने के लिए थ्रेडिंग को लागू करना होगा ... इसे आज़माएं ..;) बस सभी मौजूदा कोड को एक विधि में रखें और उस विधि को एक अलग थ्रेड से उसी स्थान पर कॉल करें जहां आपने लिखा है। यह पहले ... यह कोड की पाँच से छह पंक्तियाँ बढ़ाता है ..
Awais तारिक

19
यह गतिविधि के दो उदाहरणों को मौजूदा से रोकता है, लेकिन यह कोड को दो बार गलत तरीके से चलने से नहीं रोकता है। वोटों के कम होने के बावजूद स्वीकृत उत्तर बेहतर है।
lilbyrdie

18
यह गलत है, यह गतिविधि को दो बार मौजूद नहीं करता है, यहां तक ​​कि विभिन्न कार्यों में भी। सही तरीका यह होगा android:launchMode = "singleTop", जो एंड्रॉइड मल्टीटास्किंग को तोड़ने के बिना प्रभाव को प्राप्त करता है। प्रलेखन में कहा गया है कि अधिकांश ऐप्स को singleInstanceविकल्प का उपयोग नहीं करना चाहिए ।
नोहस

37

आप इस तरह के इरादों के झंडे का उपयोग कर सकते हैं।

Intent intent = new Intent(Class.class);    
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
activity.startActivity(intent);

यह इतिहास स्टैक के शीर्ष पर केवल एक गतिविधि को खुलेगा।


4
यह उत्तर, सबसे उत्कट उत्तर के साथ संयुक्त रूप से सबसे अच्छा काम करता है। गतिविधि के प्रकटन में इस ध्वज का उपयोग करें: android:launchMode = "singleTop"इस तरह यह हर इरादे में झंडा जोड़ने के बिना हल किया गया है।
नोहस

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

4
यह startActivityForResult
raj

27

चूंकि एसओ मुझे अन्य उत्तरों पर टिप्पणी करने की अनुमति नहीं देता है, इसलिए मुझे इस धागे को एक नए उत्तर के साथ प्रदूषित करना होगा।

"गतिविधि दो बार" समस्या के लिए सामान्य उत्तर और इन समाधानों के साथ मेरे अनुभव (एंड्रॉइड 7.1.1):

  1. गतिविधि शुरू करने वाला बटन अक्षम करें: काम करता है लेकिन थोड़ा अनाड़ी लगता है। यदि आपके पास अपने ऐप में गतिविधि शुरू करने के कई तरीके हैं (जैसे एक्शन बार में एक बटन और सूची दृश्य में किसी आइटम पर क्लिक करके), तो आपको कई GUI तत्वों के सक्षम / अक्षम स्थिति का ट्रैक रखना होगा। उदाहरण के लिए, सूची में क्लिक की गई वस्तुओं को अक्षम करना बहुत सुविधाजनक नहीं है। इसलिए, बहुत सार्वभौमिक दृष्टिकोण नहीं है।
  2. launchMode = "singleInstance": startActivityForResult () के साथ काम नहीं कर रहा है, startActivity () के साथ वापस नेविगेशन को तोड़ता है, जो एंड्रॉइड मैनिफ़ेस्ट डॉक्यूमेंटेशन द्वारा नियमित अनुप्रयोगों के लिए अनुशंसित नहीं है।
  3. लॉन्चमोड = "सिंगलटैस्क": स्टार्ट एक्टिविटीफॉरएन्स्कुल्ट () के साथ काम नहीं कर रहा है, नियमित रूप से प्रदर्शित दस्तावेज़ द्वारा नियमित अनुप्रयोगों के लिए अनुशंसित नहीं है।
  4. FLAG_ACTIVITY_REORDER_TO_FRONT: वापस बटन तोड़ता है।
  5. FLAG_ACTIVITY_SINGLE_TOP: काम नहीं कर रहा है, गतिविधि अभी भी दो बार खोली गई है।
  6. FLAG_ACTIVITY_CLEAR_TOP: यह केवल मेरे लिए काम कर रहा है।

EDIT: यह स्टार्ट-एक्टिविटी () के साथ गतिविधियाँ शुरू करने के लिए था। StartActivityForResult () का उपयोग करते समय मुझे FLAG_ACTIVITY_SINGLE_TOP और FLAG_ACTIVITY_CLEAR_TOP दोनों सेट करने की आवश्यकता है।


FLAG_ACTIVITY_CLEAR_TOP: यह एंड्रॉइड 7.1.1 पर मेरे लिए काम करने वाला एकमात्र है
मिंगजियांग शि

1
मैं "FLAG_ACTIVITY_REORDER_TO_FRONT" का उपयोग कर रहा हूं और यह ठीक काम कर रहा है और बैक बटन भी सामान्य कार्य करता है। "ब्रेक्स बैक बटन" से वास्तव में आपका क्या अभिप्राय था? क्या आप उस पर स्पष्टीकरण दे सकते हैं?
मिरुहसिन सोडिकोव

मैंने पाया है कि "को पुन: व्यवस्थित" झंडा एक बग था ... और यह नहीं कर रहा था पुन: क्रम किटकैट में। हालाँकि, मैंने लॉलीपॉप और पाई में इसकी जाँच की, यह ठीक काम कर रहा है।
मिरुहसिन सोदिकोव

7

यह केवल मेरे लिए काम कर रहा था startActivity(intent)

intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);

1
@राज क्या आपने android:launchMode = "singleInstance"अपनी गतिविधि टैग के मेनिफेस्ट फ़ाइल में इसे जोड़कर देखा है ?
शीलेंद्र मद्दा


4

मान लीजिए कि @wannik सही है, लेकिन अगर हमारे पास 1 से अधिक बटन हैं जो एक ही एक्शन श्रोता को बुलाते हैं और मैं अगली गतिविधि शुरू करने से पहले लगभग एक बार दो बटन क्लिक करता हूं ...

तो यह अच्छा है अगर आपके पास मैदान है private boolean mIsClicked = false;और श्रोता में:

if(!mIsClicked)
{
    mIsClicked = true;
    Intent i = new Intent(this, AnotherActitivty.class);
    startActivity(i);
}

और onResume()हमें राज्य वापस करने की आवश्यकता है:

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

    mIsClicked = false;
}

मेरे और @ वणिक के उत्तर के बीच क्या उदासीनता है?

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

मेरे उत्तर और अन्य के बीच क्या अंतर है?

वे सही तरीके से सोच रहे हैं लेकिन वे कॉलिंग गतिविधि के एक ही उदाहरण के लिए भविष्य की वापसी के लिए नहीं सोच रहे हैं :)


servoper, आपके शोध के लिए धन्यवाद। यह प्रश्न पहले ही हल हो चुका है, कभी आपका उत्तर भी आपके द्वारा बताई गई स्थिति के लिए आशाजनक लगता है। मुझे कोशिश करने दो और परिणाम के साथ आओ :)
तेजस

1
मेरे एक खेल में यह मुद्दा है। मेरे पास "सिलेक्ट लेवल" वाले बैलून हैं जिनमें समान श्रोता हैं और टैग्स से विचार भिन्न हैं। इसलिए अगर मैं तेजी से दो गुब्बारे चुनता हूं तो यह दो गतिविधियां शुरू करता है। मुझे पता है कि क्योंकि नई गतिविधि ध्वनि शुरू होती है .. और इस मामले में ध्वनि दो बार बजाई जाती है ... लेकिन आप इसे वापस क्लिक करके देख सकते हैं जो आपको पिछली गतिविधि पर ले जाएगी
सर NIkolay Cesar The First

1
यह पर्याप्त नहीं है। आपको synchronized(mIsClicked) {...}100% सुरक्षित होने के साथ-साथ उपयोग करने की आवश्यकता है ।
मॉन्स्टिएर

@Monstieur आपको एक सिंक्रोनाइज़्ड ब्लॉक की आवश्यकता नहीं है क्योंकि यह सभी मेन थ्रेड है ...
मार्टिन मार्कोसिनी

@MartinMarconcini सिर्फ इसलिए कि एंड्रॉइड गतिविधि में सुरक्षित होने के कारण यह अच्छा कोड नहीं बनाता है। यदि यह एक स्वसंपूर्ण वर्ग होता तो इसे दस्तावेज के रूप में संरक्षित करना होता, न कि थ्रेड सेफ।
मॉन्स्टिएर

4

इस स्थिति के लिए, मैं दो में से एक के लिए जाऊँगा, singleTask Manifest.xml या एक ध्वज में गतिविधि के दशक में onResume()औरonDestroy() मेथड्स में क्रमशः ।

के लिए पहले समाधान: मैं का उपयोग करना पसंद singleTaskके बजाय प्रकट में गतिविधि के लिए singleInstance, का उपयोग कर के अनुसार singleInstanceमैं पता लगा है कि कुछ अवसरों में गतिविधि में ही के लिए एक नया अलग उदाहरण है, जिसमें चल रहे एप्लिकेशन में एक दो अलग-अलग आवेदन पत्र खिड़की के लिए परिणाम बनाने bcakground में और अतिरिक्त मेमोरी एलोकेशन के अलावा, जो उपयोगकर्ता को एप्लिकेशन को फिर से शुरू करने के लिए कुछ ऐप चुनने के लिए एप्लिकेशन को खोलने पर एक बहुत बुरा उपयोगकर्ता अनुभव देगा। तो, बेहतर तरीका यह है कि गतिविधि को निम्नलिखित की तरह मैनिफ़ेस्ट.xml पर परिभाषित किया जाए:

<activity
    android:name=".MainActivity"
    android:launchMode="singleTask"</activity>

आप यहां गतिविधि लॉन्च मोड की जांच कर सकते हैं


के लिए दूसरा समाधान, तो आप सिर्फ एक स्थिर चर या एक प्राथमिकता चर, उदाहरण के लिए परिभाषित करने के लिए है:

public class MainActivity extends Activity{
    public static boolean isRunning = false;

    @Override
    public void onResume() {
        super.onResume();
        // now the activity is running
        isRunning = true;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // now the activity will be available again
        isRunning = false;
    }

}

और दूसरी तरफ से जब आप इस गतिविधि को लॉन्च करना चाहते हैं, तो बस जांचें:

private void launchMainActivity(){
    if(MainActivity.isRunning)
        return;
    Intent intent = new Intent(ThisActivity.this, MainActivity.class);
    startActivity(intent);
}

3

मुझे लगता है कि आप समस्या को गलत तरीके से हल करने जा रहे हैं। आम तौर पर यह एक गतिविधि अपने स्टार्टअप जीवन चक्र के तरीकों (में से किसी में लंबे समय से चल वेब अनुरोध करने जा करने के लिए के लिए एक बुरा विचार है onCreate(), onResume(), आदि)। वास्तव में इन विधियों का उपयोग केवल उन वस्तुओं को त्वरित और प्रारंभिक करने के लिए किया जाना चाहिए जो आपकी गतिविधि का उपयोग करेगी और इसलिए अपेक्षाकृत जल्दी होनी चाहिए।

यदि आपको एक वेब अनुरोध करने की आवश्यकता है, तो अपनी नई लॉन्च की गई गतिविधि से पृष्ठभूमि थ्रेड में करें (और नई गतिविधि में लोडिंग संवाद दिखाएं)। एक बार बैकग्राउंड रिक्वेस्ट थ्रेड पूरा होने पर यह एक्टिविटी को अपडेट कर सकता है और डायलॉग को छिपा सकता है।

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


3

उम्मीद है की यह मदद करेगा:

 protected static final int DELAY_TIME = 100;

// to prevent double click issue, disable button after click and enable it after 100ms
protected Handler mClickHandler = new Handler() {

    public void handleMessage(Message msg) {

        findViewById(msg.what).setClickable(true);
        super.handleMessage(msg);
    }
};

@Override
public void onClick(View v) {
    int id = v.getId();
    v.setClickable(false);
    mClickHandler.sendEmptyMessageDelayed(id, DELAY_TIME);
    // startActivity()
}`

2

यदि आप कोई उपयोग नहीं करना चाहते हैं तो अन्य बहुत ही सरल समाधान onActivityResult()2 सेकंड (या आप चाहते हैं) के लिए बटन अक्षम है, आदर्श नहीं है, लेकिन आंशिक रूप से समस्या को हल कर सकते हैं कुछ मामलों और कोड सरल है:

   final Button btn = ...
   btn.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            //start activity here...
            btn.setEnabled(false);   //disable button

            //post a message to run in UI Thread after a delay in milliseconds
            btn.postDelayed(new Runnable() {
                public void run() {
                    btn.setEnabled(true);    //enable button again
                }
            },1000);    //1 second in this case...
        }
    });

2

// चर घटना समय ट्रैक करने के लिए

private long mLastClickTime = 0;

2. ऑनक्लिक में देखें कि यदि वर्तमान समय और अंतिम क्लिक समय का अंतर i सेकंड से कम है, तो कुछ भी न करें (वापसी) घटना के लिए और कुछ न करें

 @Override
public void onClick(View v) {
    // Preventing multiple clicks, using threshold of 1 second
    if (SystemClock.elapsedRealtime() - mLastClickTime < 1000) {
        return;
          }
    mLastClickTime = SystemClock.elapsedRealtime();
            // Handle button clicks
            if (v == R.id.imageView2) {
        // Do ur stuff.
         }
            else if (v == R.id.imageView2) {
        // Do ur stuff.
         }
      }
 }

1

बस बटन पर एक झंडा बनाए रखें जिस पर क्लिक करें विधि:

सार्वजनिक बूलियन oneTimeLoadActivity = false;

    myButton.setOnClickListener(new View.OnClickListener() {
          public void onClick(View view) {
               if(!oneTimeLoadActivity){
                    //start your new activity.
                   oneTimeLoadActivity = true;
                    }
        }
    });

0

यदि आप onActivityResult का उपयोग कर रहे हैं, तो आप राज्य को बचाने के लिए एक चर का उपयोग कर सकते हैं।

private Boolean activityOpenInProgress = false;

myButton.setOnClickListener(new View.OnClickListener() {
  public void onClick(View view) {
    if( activityOpenInProgress )
      return;

    activityOpenInProgress = true;
   //Load another activity with startActivityForResult with required request code
  }
});

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  if( requestCode == thatYouSentToOpenActivity ){
    activityOpenInProgress = false;
  }
}

बैक बटन पर काम करता है भी क्योंकि अनुरोध कोड घटना पर वापस आ गया है।


0

क्लिक करने पर गतिविधि खोलने से बचने के लिए लॉन्च मोड को एकल कार्य के रूप में जोड़ें

<activity
        android:name=".MainActivity"
        android:label="@string/activity"
        android:launchMode = "singleTask" />

-1
myButton.setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) {
      myButton.setOnClickListener(null);
    }
});

शायद यह काम नहीं करेगा क्योंकि आपको इसे अंतिम घोषित करना होगा।
राजा

-1

एक flagचर सेट का उपयोग करें to true, जांचें कि क्या यह सही हैreturn और गतिविधि कॉल करें।

आप एक्टिविटी कॉल को निष्पादित करने वाले सेटक्लिकक्लिकेबल (गलत) का भी उपयोग कर सकते हैं

flg=false
 public void onClick(View view) { 
       if(flg==true)
         return;
       else
       { flg=true;
        // perform click}
    } 

perform click; wait; flg = false;जब हम वापस आते हैं
Xeno लुपस

-1

आप बस startActivityForResult को ओवरराइड कर सकते हैं और उदाहरण चर का उपयोग कर सकते हैं:

boolean couldStartActivity = false;

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

    couldStartActivity = true;
}

@Override
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
    if (couldStartActivity) {
        couldStartActivity = false;
        intent.putExtra(RequestCodeKey, requestCode);
        super.startActivityForResult(intent, requestCode, options);
    }
}

-4

आप यह भी कोशिश कर सकते हैं

Button game = (Button) findViewById(R.id.games);
        game.setOnClickListener(new View.OnClickListener() 
        {
            public void onClick(View view) 
            {
                Intent myIntent = new Intent(view.getContext(), Games.class);
                startActivityForResult(myIntent, 0);
            }

        });
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.