অ্যান্ড্রয়েডে কীভাবে থ্রেড / স্লিপ থ্রেড বা প্রক্রিয়া করবেন?


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
@ ক্রিস্টোফারএ-হুয়াগাটি ডট কম আমি নিশ্চিত নই যে আপনি ব্যঙ্গাত্মক হয়ে উঠছেন বা সত্যই কোনও ডালভিক / অ্যান্ড্রয়েড যাদু আছে যাতে এটি অ্যান্ড্রয়েডে গ্রহণযোগ্য। আপনি দয়া করে পরিষ্কার করতে পারেন? সন্দেহের জন্য দুঃখিত তবে আমি জিজ্ঞাসা করি কারণ (!conditionCheck()) {}সাধারণত যখন নিরুৎসাহিত হন।
দুর্বল পরিবর্তনশীল

"তবে এটি কার্যকর হয় না।" "আমি চেষ্টাও করেছি (তবে এটি কাজ করে না)" লক্ষণগুলি না দিয়ে সমস্যা আছে বলার এটি একটি সর্বোত্তম উদাহরণ is এই প্রচেষ্টাগুলি কীভাবে আপনার প্রয়োজনীয়তাগুলি পূরণ করতে ব্যর্থ হয়েছিল? থ্রেড কি থেমে নেই? আপনি একটি ত্রুটি বার্তা পেয়েছেন?
লার্শ

উত্তর:


454

এই সমস্যার একটি সমাধান হ্যান্ডলারের পোস্টপ্লেডিয়েড () পদ্ধতি ব্যবহার করা। কিছু গুগল প্রশিক্ষণ উপকরণ একই সমাধানের পরামর্শ দেয়।

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

যাইহোক, কেউ কেউ উল্লেখ করেছেন যে উপরের সমাধানটির ফলে মেমরি ফাঁস হয় কারণ এটি অ স্থিতিশীল অভ্যন্তরীণ এবং বেনাম শ্রেণীর ব্যবহার করে যা স্পষ্টভাবে তার বাহ্যিক শ্রেণি, ক্রিয়াকলাপের জন্য একটি রেফারেন্স ধারণ করে। কার্যকলাপের প্রসঙ্গটি আবর্জনা সংগ্রহ করা হলে এটি একটি সমস্যা problem

স্থিতিশীল অভ্যন্তর শ্রেণিগুলি তাদের বাহ্যিক শ্রেণীর নিখরচায় রেফারেন্স রাখে না এমন আরও জটিল সমাধান যা মেমরি ফাঁস সাবক্লাসগুলি 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);
}

নোট করুন যে ব্যবহারগুলিতে ক্রিয়াকলাপের প্রতি WeakReferencesRunnable ব্যবহার করা হয়, এটি স্ট্যাটিক শ্রেণিতে প্রয়োজনীয় যা ইউআইতে অ্যাক্সেস প্রয়োজন।


3
এটি কাজ করে, তবে পুরো কোড জুড়ে বিলম্বের পরিচয় দেওয়ার জন্য এটি বেশ অসুবিধাগ্রস্ত উপায়, তাই না?
এহতেশ চৌধুরী

4
আপনি "অসুবিধা" বলতে কী বোঝায় তা আমি নিশ্চিত নই। হ্যান্ডলারের পোস্টডলেড পদ্ধতিটি অ্যান্ড্রয়েডকে জানানোর জন্য ডিজাইন করা হয়েছে যে আপনি একটি নির্দিষ্ট পরিমাণ সময় অতিবাহিত হওয়ার পরে কিছুটা কোড কার্যকর করতে চান।
ট্রোনম্যান

27
2 বছর পরে এবং এই কোডটি আমাকে কেবল সহায়তা করেছে! ধন্যবাদ @ ট্রোনম্যান !! :)
মেলভিন লাই

2
আপনি কেবল এটির মতো অন্য কোনও (চূড়ান্ত) ভেরিয়েবলের অনুলিপি করতে পারেন final Button mynewbutton = mybutton;এবং mynewbuttonসেখান থেকে হ্যান্ডলার এবং রান্নেবল ব্যবহার করতে পারেন ।
ডিজনেয়েট

2
@ মেলভিনলাই 5 বছর পরে এবং এই কোডটি আমাকে কেবল সহায়তা করেছে! :)
গ্যাব্রিয়েলিভিরা

191

আপনি এটি চেষ্টা করতে পারেন এটি সংক্ষিপ্ত

SystemClock.sleep(7000);

সতর্কতা : কখনও কখনও, এটি কোনও ইউআই থ্রেডে করবেন না।

যেমন ঘুমাতে এটি ব্যবহার করুন। পটভূমি থ্রেড


আপনার সমস্যার পুরো সমাধানটি হ'ল এটি উপলব্ধ এপিআই 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 হ্যান্ডলার তৈরি না করে। এছাড়াও এই সমাধানটি @ ট্রোনম্যানের চেয়ে ভাল কারণ আমরা হ্যান্ডলারের দ্বারা দৃষ্টিভঙ্গি ধরে রাখি না। এছাড়াও হ্যান্ডলারের খারাপ থ্রেডে তৈরি করা নিয়ে আমাদের সমস্যা নেই;)

নথিপত্র

পাবলিক স্ট্যাটিক অকার্যকর ঘুম (দীর্ঘ এমএস)

এপিআই স্তর 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
এবং অ্যান্ড্রয়েড ইউআই জমাতে দিন? এটি করবেন না।
shkschneider

3
সিআরটিএল + শিফট + ও (গ্রহন স্বয়ংক্রিয় আমদানি)
দাউদ ড্রজড

13
জেলডুর, আপনি @ রিচিএইচএইচ মন্তব্যটির বিন্দুটি মিস করছেন। আপনার পোস্টের 3 বছর পূর্বে যে উত্তরটি গৃহীত হয়েছিল তার সাথে তুলনা করে , আপনার পরামর্শটি ওপিকে তার সমস্যা সমাধানে সহায়তা করে না। কারণ: ওপি দ্বারা দেখানো এবং গ্রহণযোগ্য উত্তরে দেখানো কোড উভয়ই একটি ইউআই হ্যান্ডলারের ভিতরে চলছে । বলা OMG of course do this in background threadঅপ্রাসঙ্গিক, যদি না আপনি পটভূমির থ্রেডে রাখার জন্য প্রদর্শন করেন। কোন সময়ে, আপনি আবিষ্কার করবেন যে ইতিমধ্যে স্বীকৃত উত্তরের চেয়ে আপনার একটি উত্তর আরও জটিল। আমি কি উল্লেখ করেছি যে তিন বছর আগে আরও ভাল সমাধান গৃহীত হয়েছিল? : পি
টুলমেকারস্টেভ

2
... এটি উল্লেখ করতে ভুলে গেছেন যে এই পরামর্শটি বিশেষত প্রশ্নটির বাইরে-উদ্দেশ্য করে তোলে, এটি ওপি স্পষ্টতই বিলম্বের পরে ইউআই ক্রিয়াটি করতে চায়। সুতরাং, আপনার একটি সমাধান থাকবে যাতে আপনি একটি পটভূমি থ্রেড তৈরি করেছেন (ইস্যুটি সমাধান করার জন্য ইতিমধ্যে আরও বেশি ভারী ওজন) ঘুমিয়েছে এবং তারপরে আপনাকে (কোনওভাবে) ইউআই থ্রেডে ফিরে যেতে হবে। Handler + postRunnableএকক পদক্ষেপে, এই সমস্ত সম্পাদন করে। সিস্টেম ছাড়াই একটি দ্বিতীয় থ্রেড তৈরি করার জন্য।
টুলমেকারস্টেভ

2
@ টুলমেকারস্টেভ এখন খুশি: ডি? মূল প্রশ্নটি: "অ্যান্ড্রয়েডে থ্রেড বা ঘুমের থ্রেড বা প্রক্রিয়া কীভাবে?" সুতরাং আমার উত্তর ছিল সহজ :)। যদি কেউ গুগল করে "কীভাবে থ্রেড ঘুমাবেন" এই প্রশ্নটি দেখায়। তিনি / তিনি সম্ভবত আমার উত্তর খুঁজছেন: পি। তবে ঠিক আছে আমি পূর্ণ প্রতিক্রিয়া যোগ করেছি;)
দাউদ ড্রোজ 25'16

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 () ব্যবহার করি যখন আমার একটি সাধারণ, সাধারণ এবং দ্রুত ব্যতিক্রম বার্তা প্রয়োজন
বাইট 3

1
তবে আমি বাজি দিয়েছি যে ইউপি যে পদ্ধতিতে ইউআই-তে ক্লিক করবে, ইউআই-তে আরও নতুন আপডেট করতে চলেছে, সেই পরিস্থিতিতে ওপি আপনাকে যে পরিস্থিতিতে বলবে না তেমনটি করবেন না do গৃহীত Handler/postDelayedসমাধানটির দুটি সুবিধা রয়েছে: (1) 2 য় থ্রেডের ওভারহেড সিস্টেম এড়ানো, (1) ইউআই থ্রেডে চালিত হয়, সুতরাং ব্যতিক্রম না করেই ইউআই পরিবর্তন করতে পারে make
টুলমেকারস্টেভ

1
প্রশ্নের মূল লক্ষ্যটির সাথে সরাসরি সম্পর্কিত নয় তবে আপনাকে ব্যতিক্রম ধরা উচিত নয়। বরং ইন্টারপডএক্সসেপশন ধরুন। ব্যতিক্রম ধরা পরে, আপনি ভুল হতে পারে এমন সমস্ত কিছুই ধরবেন, এভাবে আপনি অন্যথায় যে সমস্যাগুলি দেখবেন সেগুলি লুকিয়ে রাখবে।
হার্ভে থু

16

আপনি সম্ভবত এটি সেভাবে করতে চান না। sleep()আপনার বোতামে ক্লিক করা ইভেন্ট হ্যান্ডলারটিতে একটি স্পষ্টতা রেখে , আপনি সত্যই পুরো ইউআইটিকে এক সেকেন্ডের জন্য লক করে রাখবেন। একটি বিকল্প হ'ল এক ধরণের একক শট টাইমার ব্যবহার করা । ব্যাকগ্রাউন্ডের রঙটিকে ডিফল্ট রঙে ফিরিয়ে আনতে একটি টাইমার টাস্ক তৈরি করুন এবং এটি টাইমারে শিডিউল করুন।

আর একটি সম্ভাবনা হ্যান্ডলার ব্যবহার করা । এমন একজন সম্পর্কে একটি টিউটোরিয়াল রয়েছে যিনি একজন টাইমার ব্যবহার থেকে হ্যান্ডলারের সাহায্যে ব্যবহার শুরু করেছিলেন।

ঘটনাচক্রে, আপনি কোনও প্রক্রিয়া থামাতে পারবেন না। একটি জাভা (বা অ্যান্ড্রয়েড) প্রক্রিয়াটিতে কমপক্ষে 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একটি বিলম্ব সময় নেয় takes এটি 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
প্রশ্নটি ইতিমধ্যে ভাল সমাধান হওয়ার কয়েক বছর পরে আরও একটি উত্তর যুক্ত হয়েছে, এটি প্রশ্নের সাথে প্রাসঙ্গিক নয়, কারণ এটি ইউআই কাজ সম্পাদন করতে সক্ষম হওয়ার বর্ণিত আকাঙ্ক্ষার সাথে কাজ করে না। আপনি এখানে ইউআই কাজ করতে পারবেন না, কারণ আপনি একটি নতুন থ্রেডে চলছে। ইউআই থ্রেডে নেই।
টুলমেকারস্টেভ

1
UX- এর দিক দিয়ে, ব্যবহারকারীকে ডেটা লোড করার জন্য একটি ব্লক করা ডায়ালগ দেখানো ভাল ... ভাল নয়।
2

4

অথবা আপনি ব্যবহার করতে পারেন:

android.os.SystemClock.sleep(checkEvery)

যা একটি মোড়ানো প্রয়োজন না করার সুবিধা আছে try ... catch


0

আপনি যদি কোটলিন এবং কর্টিন ব্যবহার করেন তবে আপনি কেবল এটি করতে পারেন

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

এবং আপনার যদি ইউআই আপডেট করতে হয়

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

0

আমি জানি এটি একটি পুরানো থ্রেড, তবে অ্যান্ড্রয়েড ডকুমেন্টে আমি এমন একটি সমাধান পেয়েছি যা আমার পক্ষে খুব ভালভাবে কাজ করেছে ...

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

এবং দ্বিগুণ নিশ্চিত হওয়ার জন্য আপনি ট্রোনম্যান উত্তরে বর্ণিত হিসাবে এটি "স্ট্যাটিক ক্লাস" পদ্ধতির সাথে একত্রিত করা যেতে পারে

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.