एंड्रॉइड में थ्रेड या स्लीप थ्रेड या प्रक्रिया कैसे करें?


294

मैं कोड की दो पंक्तियों के बीच एक विराम बनाना चाहता हूं, मुझे थोड़ा समझाएं:

-> उपयोगकर्ता एक बटन (वास्तव में एक कार्ड) पर क्लिक करता है और मैं इस बटन की पृष्ठभूमि को बदलकर दिखाता हूं:

thisbutton.setBackgroundResource(R.drawable.icon);

-> 1 सेकंड कहने के बाद, मुझे अपनी पृष्ठभूमि को वापस बदलकर बटन की पिछली स्थिति में वापस जाना होगा:

thisbutton.setBackgroundResource(R.drawable.defaultcard);

-> मैंने कोड की इन दो पंक्तियों के बीच धागे को थामने की कोशिश की है:

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

हालांकि, यह काम नहीं करता है। शायद यह प्रक्रिया है और थ्रेड नहीं है जिसे मुझे रोकने की आवश्यकता है?

मैंने भी कोशिश की है (लेकिन यह काम नहीं करता है):

new Reminder(5);

इसके साथ:

public class Reminder {

Timer timer;

        public Reminder(int seconds) {
            timer = new Timer();
            timer.schedule(new RemindTask(), seconds*1000);
        }

        class RemindTask extends TimerTask {
            public void run() {
                System.out.format("Time's up!%n");
                timer.cancel(); //Terminate the timer thread
            }
        }  
    }

मैं थ्रेड या प्रक्रिया को कैसे रोक / सो सकता हूं?


4
ओह, बस क्लासिक थ्रेड पॉज ब्लॉक का उपयोग करें: जबकि (सच) {}
क्रिस्टोफर

6
@ KristoferA-Huagati.com मुझे यकीन नहीं है कि अगर आप व्यंग्यात्मक हैं या वास्तव में कुछ Dalvik / Android जादू है ताकि यह एंड्रॉइड पर स्वीकार्य हो। क्या आप स्पष्ट कर सकते हैं? संदेह करने के लिए क्षमा करें, लेकिन मैं पूछता हूं क्योंकि (!conditionCheck()) {}आमतौर पर हतोत्साहित किया जाता है।
दुखी चर

"हालांकि, यह काम नहीं करता है।" "मैंने भी कोशिश की है (लेकिन यह काम नहीं करता है)" यह कहने का एक उत्कृष्ट उदाहरण है कि लक्षण दिए बिना कोई समस्या है। किस तरह से ये प्रयास आपकी आवश्यकताओं को पूरा करने में विफल रहे? क्या धागा थमा नहीं था? क्या आपको एक त्रुटि संदेश मिला है?
लार्स

जवाबों:


454

इस समस्या का एक हल है हैंडलर.पोस्टडेलिड () विधि का उपयोग करना । कुछ Google प्रशिक्षण सामग्री एक ही समाधान सुझाती हैं।

@Override
public void onClick(View v) {
    my_button.setBackgroundResource(R.drawable.icon);

    Handler handler = new Handler(); 
    handler.postDelayed(new Runnable() {
         @Override 
         public void run() { 
              my_button.setBackgroundResource(R.drawable.defaultcard); 
         } 
    }, 2000); 
}

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

एक और अधिक जटिल समाधान जो मेमोरी लीक से बचा जाता है Handlerऔर Runnableगतिविधि के अंदर स्थिर आंतरिक कक्षाओं के साथ उप- वर्ग करता है क्योंकि स्थिर आंतरिक कक्षाएं उनके बाहरी वर्ग के लिए एक अंतर्निहित संदर्भ नहीं रखती हैं:

private static class MyHandler extends Handler {}
private final MyHandler mHandler = new MyHandler();

public static class MyRunnable implements Runnable {
    private final WeakReference<Activity> mActivity;

    public MyRunnable(Activity activity) {
        mActivity = new WeakReference<>(activity);
    }

    @Override
    public void run() {
        Activity activity = mActivity.get();
        if (activity != null) {
            Button btn = (Button) activity.findViewById(R.id.button);
            btn.setBackgroundResource(R.drawable.defaultcard);
        }
    }
}

private MyRunnable mRunnable = new MyRunnable(this);

public void onClick(View view) {
    my_button.setBackgroundResource(R.drawable.icon);

    // Execute the Runnable in 2 seconds
    mHandler.postDelayed(mRunnable, 2000);
}

ध्यान दें कि गतिविधि के लिए Runnableएक कमजोर संदर्भ का उपयोग करता है , जो एक स्थिर वर्ग में आवश्यक है जो UI तक पहुंच की आवश्यकता है।


3
यह काम करता है, लेकिन यह पूरे कोड में देरी का परिचय देने के लिए एक बहुत असुविधाजनक तरीका है, है ना?
एहतेश चौधरी

4
मुझे यकीन नहीं है कि आप "असुविधाजनक" से क्या मतलब है। हैंडलर का पोस्टडेलिड तरीका एंड्रॉइड को यह बताने के लिए डिज़ाइन किया गया है कि आप एक निश्चित समय बीतने के बाद कोड को निष्पादित करना चाहते हैं।
ट्रॉनमैन

27
2 साल बाद और इस कोड ने मेरी मदद की! साभार @tronman !! :)
मेल्विन लाई

2
आप बस इसे दूसरे (अंतिम) चर की तरह कॉपी कर सकते हैं final Button mynewbutton = mybutton;और mynewbuttonहैंडलर और रननेबल में उपयोग कर सकते हैं।
दिहुंयेट

2
@MelvinLai 5 साल बाद और इस कोड ने मेरी मदद की! :)
गैब्रिएलोलिवेरा

191

आप इसे छोटा कर सकते हैं

SystemClock.sleep(7000);

चेतावनी : कभी भी, कभी भी, एक UI थ्रेड पर ऐसा करें।

सोने के लिए इसका उपयोग करें। पृष्ठभूमि धागा।


आपकी समस्या का पूर्ण समाधान होगा: यह उपलब्ध है एपीआई 1

findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View button) {
                button.setBackgroundResource(R.drawable.avatar_dead);
                final long changeTime = 1000L;
                button.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        button.setBackgroundResource(R.drawable.avatar_small);
                    }
                }, changeTime);
            }
        });

Tmp हैंडलर बनाए बिना। इसके अलावा यह समाधान @tronman से बेहतर है क्योंकि हम हैंडलर द्वारा दृश्य को बनाए नहीं रखते हैं। इसके अलावा हमें खराब थ्रेड पर बनाए गए हैंडलर की समस्या नहीं है;)

प्रलेखन

सार्वजनिक स्थैतिक शून्य नींद (लंबी एमएस)

एपीआई स्तर 1 में जोड़ा गया

लौटने से पहले मिलीसेकंड (अपटाइममिल्स) की दी गई संख्या का इंतजार करता है। सोने के समान (लंबा), लेकिन इंटरप्टेड एक्ससेप्शन को नहीं फेंकता ; अगले रुकावट ऑपरेशन तक व्यवधान () घटनाओं को टाल दिया जाता है। है वापस नहीं जब तक कम से कम मिलीसेकंड की निर्दिष्ट संख्या बीत जाने पर।

पैरामीटर

एमएस , लौटने से पहले सोने के लिए, ऊपर के मिलीसेकेंड में।

देखें वर्ग से पोस्टडायलेड के लिए कोड :

/**
 * <p>Causes the Runnable to be added to the message queue, to be run
 * after the specified amount of time elapses.
 * The runnable will be run on the user interface thread.</p>
 *
 * @param action The Runnable that will be executed.
 * @param delayMillis The delay (in milliseconds) until the Runnable
 *        will be executed.
 *
 * @return true if the Runnable was successfully placed in to the
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the Runnable will be processed --
 *         if the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 *
 * @see #post
 * @see #removeCallbacks
 */
public boolean postDelayed(Runnable action, long delayMillis) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.postDelayed(action, delayMillis);
    }
    // Assume that post will succeed later
    ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
    return true;
}

22
और एंड्रॉइड यूआई को फ्रीज करें? यह मत करो।
शक्शिनडर

3
Ctrl + Shift + O (ग्रहण ऑटो आयात)
Dawid Drozd

13
गेल्डुर, आप @ रिचीह की टिप्पणी के बिंदु को याद कर रहे हैं। पोस्ट किए जाने से 3 साल पहले स्वीकार किए गए उत्तर की तुलना में , आप जो सुझाव देते हैं, वह ओपी को उसकी समस्या को हल करने में मदद नहीं करता है। कारण: कोड, जो ओपी द्वारा दिखाया गया है, और जैसा कि स्वीकृत उत्तर में दिखाया गया है, यूआई हैंडलर के अंदर चल रहा है । कहना OMG of course do this in background threadअप्रासंगिक है, जब तक कि आप इसे पृष्ठभूमि के धागे में डालने के लिए कैसे नहीं दिखाते हैं। किस समय, आपको पता चलेगा कि आपके पास पहले से स्वीकृत उत्तर की तुलना में अधिक जटिल उत्तर है। क्या मैंने उल्लेख किया है कि तीन साल पहले एक बेहतर समाधान स्वीकार किया गया था? : पी
टूलमेकरसेव

2
... यह उल्लेख करना भूल गया कि इस सुझाव से विशेष रूप से सवाल का उद्देश्य क्या होता है, यह है कि ओपी स्पष्ट रूप से देरी के बाद यूआई कार्रवाई करना चाहता है। तो, आपके पास एक समाधान होगा जिसमें आपने एक पृष्ठभूमि थ्रेड बनाया है (समस्या को हल करने के लिए पहले से अधिक भारी-वजन की आवश्यकता है), सोए थे, और फिर आपको (किसी तरह) UI थ्रेड पर वापस जाना होगा। Handler + postRunnableएक ही चरण में, यह सब पूरा करता है। एक दूसरा धागा बनाने के सिस्टम ओवरहेड के बिना।
ToolmakerSteve

2
@ टूलमेकर अब खुश हैं: डी? मुख्य प्रश्न है: "एंड्रॉइड में थ्रेड या स्लीप थ्रेड या प्रक्रिया कैसे करें?" तो मेरा जवाब आसान था :)। यदि कोई व्यक्ति "थ्रेड स्लीप थ्रेड" के लिए यह प्रश्न दिखाएगा। वह / वह शायद मेरे जवाब की तलाश में है: पी। लेकिन ठीक है, मैंने पूर्ण प्रतिक्रिया जोड़ी;)
दाविद ड्रोज़ड

28

मैं इसका उपयोग करता हूं:

Thread closeActivity = new Thread(new Runnable() {
  @Override
  public void run() {
    try {
      Thread.sleep(3000);
      // Do some stuff
    } catch (Exception e) {
      e.getLocalizedMessage();
    }
  }
});

4
क्या e.getLocalizedMessage()करना है?
फिलिप रीचर्ट

मैं e.getLocalizedMessage () का उपयोग करता हूं जब मुझे एक सरल, सामान्य और त्वरित अपवाद संदेश की आवश्यकता होती है
Byt3

1
लेकिन मुझे यकीन है कि आप ऐसा नहीं करते हैं, ओपी एक यूआई क्लिक विधि के बारे में पूछते हैं, जो यूआई के लिए और अपडेट करने जा रहा है। स्वीकृत Handler/postDelayedसमाधान के दो फायदे हैं: (1) 2 थ्रेड के सिस्टम ओवरहेड से बचा जाता है, (1) UI थ्रेड पर चलता है, इसलिए बिना किसी अपवाद के UI परिवर्तन कर सकता है।
टूलमेकरसेव

1
सीधे सवाल के मुख्य लक्ष्य से संबंधित नहीं है लेकिन आपको अपवाद को नहीं पकड़ना चाहिए। बल्कि इंटरप्टेड एक्ससेप्शन को पकड़ें। अपवाद को पकड़ने से, आप वह सब कुछ पकड़ लेंगे जो गलत हो सकता है, इस प्रकार उन समस्याओं को छिपा सकता है जिन्हें आप अन्यथा पकड़ लेंगे।
हेरव थू

16

आप शायद इसे इस तरह से नहीं करना चाहते हैं। sleep()अपने बटन-क्लिक किए गए ईवेंट हैंडलर में एक स्पष्ट डालकर , आप वास्तव में एक सेकंड के लिए पूरे यूआई को लॉक करेंगे। एक विकल्प यह है कि किसी प्रकार के एकल-शॉट टाइमर का उपयोग किया जाए । बैकग्राउंड कलर को डिफॉल्ट कलर में बदलने के लिए TimerTask बनाएं और इसे टाइमर पर शेड्यूल करें।

एक अन्य संभावना एक हैंडलर का उपयोग करना है । नहीं है एक ट्यूटोरियल है जो एक हैंडलर का उपयोग कर के लिए एक टाइमर में स्विच किसी के बारे में।

संयोग से, आप एक प्रक्रिया को रोक नहीं सकते। एक जावा (या एंड्रॉइड) प्रक्रिया में कम से कम 1 थ्रेड होता है, और आप केवल थ्रेड्स सो सकते हैं।


14

मैं काउंटडाउनटाइम का उपयोग करता हूं

new CountDownTimer(5000, 1000) {

    @Override
    public void onTick(long millisUntilFinished) {
        // do something after 1s
    }

    @Override
    public void onFinish() {
        // do something end times 5s
    }

}.start(); 

यह उपयोगी है।
उज़ायसन

9

यह वही है जो मैंने दिन के अंत में किया था - अब ठीक काम करता है:

@Override
    public void onClick(View v) {
        my_button.setBackgroundResource(R.drawable.icon);
        // SLEEP 2 SECONDS HERE ...
        final Handler handler = new Handler(); 
        Timer t = new Timer(); 
        t.schedule(new TimerTask() { 
                public void run() { 
                        handler.post(new Runnable() { 
                                public void run() { 
                                 my_button.setBackgroundResource(R.drawable.defaultcard); 
                                } 
                        }); 
                } 
        }, 2000); 
    }

2
पोस्टडायलैड क्यों नहीं? टाइमर की आवश्यकता नहीं है।
रिचीह

8

श्री यांकोव्स्की के जवाबों के अलावा, आप भी इस्तेमाल कर सकते हैं postDelayed()। यह किसी भी View(जैसे, आपका कार्ड) पर उपलब्ध है Runnableऔर देरी की अवधि लेता है । यह Runnableउस देरी के बाद निष्पादित करता है ।


5

यह मेरा उदाहरण है

एक जावा यूटिल्स बनाएं

    import android.app.ProgressDialog;
    import android.content.Context;
    import android.content.Intent;

    public class Utils {

        public static void showDummyWaitingDialog(final Context context, final Intent startingIntent) {
            // ...
            final ProgressDialog progressDialog = ProgressDialog.show(context, "Please wait...", "Loading data ...", true);

            new Thread() {
                public void run() {
                    try{
                        // Do some work here
                        sleep(5000);
                    } catch (Exception e) {
                    }
                    // start next intent
                    new Thread() {
                        public void run() {
                        // Dismiss the Dialog 
                        progressDialog.dismiss();
                        // start selected activity
                        if ( startingIntent != null) context.startActivity(startingIntent);
                        }
                    }.start();
                }
            }.start();  

        }

    }    

3
प्रश्न के पहले से ही हल किए गए वर्षों के बाद एक और उत्तर जोड़ा गया, जो प्रश्न के लिए प्रासंगिक नहीं है, क्योंकि यह यूआई कार्य करने में सक्षम होने की कथित इच्छा से निपटता नहीं है। आप यहां UI कार्य नहीं कर सकते, क्योंकि आप एक नए थ्रेड पर चल रहे हैं। UI थ्रेड पर नहीं।
टूलमेकरसिटेव

1
UX चीजों पर, डेटा लोड करने के लिए उपयोगकर्ता को एक अवरुद्ध संवाद दिखाना ... अच्छा नहीं है।
2Dee

4

या आप उपयोग कर सकते हैं:

android.os.SystemClock.sleep(checkEvery)

जिसमें लपेटने की आवश्यकता नहीं होने का लाभ है try ... catch


0

आप Kotlin और उपयोग करते हैं coroutines , तो आप बस कर सकते हैं

GlobalScope.launch {
   delay(3000) // In ms
   //Code after sleep
}

और अगर आपको यूआई अपडेट करने की आवश्यकता है

GlobalScope.launch {
  delay(3000)
  GlobalScope.launch(Dispatchers.Main) {
    //Action on UI thread
  }
}

0

मुझे पता है कि यह एक पुराना धागा है, लेकिन Android प्रलेखन में मुझे एक ऐसा समाधान मिला, जो मेरे लिए बहुत अच्छा काम करता है ...

new CountDownTimer(30000, 1000) {

    public void onTick(long millisUntilFinished) {
        mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
    }

    public void onFinish() {
        mTextField.setText("done!");
    }
}.start();

https://developer.android.com/reference/android/os/CountDownTimer.html

आशा है कि यह किसी की मदद करता है ...


0
  class MyActivity{
    private final Handler handler = new Handler();
    private Runnable yourRunnable;
    protected void onCreate(@Nullable Bundle savedInstanceState) {
       // ....
       this.yourRunnable = new Runnable() {
               @Override
               public void run() {
                   //code
               }
            };

        this.handler.postDelayed(this.yourRunnable, 2000);
       }


     @Override
  protected void onDestroy() {
      // to avoid memory leaks
      this.handler.removeCallbacks(this.yourRunnable);
      }
    }

और यह सुनिश्चित करने के लिए कि आपको ट्रॉनमैन उत्तर में वर्णित "स्थिर वर्ग" विधि के साथ जोड़ा जा सकता है

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