안드로이드에서 스레드 또는 프로세스를 일시 중지 / 수면하는 방법은 무엇입니까?


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
아, 클래식 스레드 일시 정지 블록을 사용하십시오 : while (true) {}
KristoferA

6
@ KristoferA-Huagati.com 당신이 냉소적이거나 ​​실제로 Dalvik / Android 마법이있어 Android에서 받아 들일 수 있는지 확실하지 않습니다. 당신은 명확히 할 수 있습니까? 의문의 여지가 있지만 죄송합니다 (!conditionCheck()) {}.
Miserable Variable

"그러나 이것은 작동하지 않습니다." "나는 또한 시도했지만 작동하지 않습니다"이것은 증상을 나타내지 않고 문제가 있다고 말하는 전형적인 예입니다. 이러한 시도는 어떤 방식으로 요구 사항을 충족시키지 못했습니까? 스레드가 일시 중지되지 않았습니까? 오류 메시지가 나타 났습니까?
LarsH

답변:


454

이 문제에 대한 한 가지 해결책은 Handler.postDelayed () 메소드 를 사용하는 입니다. 일부 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); 
}

그러나 일부는 위의 솔루션 이 외부 클래스 인 활동에 대한 참조를 내재적으로 보유하는 비 정적 내부 및 익명 클래스를 사용하기 때문에 메모리 누수가 발생 한다고 지적했습니다 . 활동 컨텍스트가 가비지 수집 될 때 문제가됩니다.

메모리 누설을 방지보다 복잡한 용액, 서브 클래스 HandlerRunnable그 밖의 클래스 암시 참조지지 않은 정적 내부 클래스 보낸 활동 내부 정적 내부 클래스로 :

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사용하는 WeakReference를 사용자 인터페이스에 대한 액세스를 필요로하는 정적 클래스에 필요한 활동에.


3
작동하지만 코드 전체에 지연을 발생시키는 것은 매우 불편한 방법입니다.
Ehtesh Choudhury

4
"불편"이라는 것이 무슨 의미인지 잘 모르겠습니다. Handler의 postDelayed 메소드는 일정 시간이 지난 후에 약간의 코드가 실행되도록 Android에 알리도록 설계되었습니다.
tronman

27
2 년 후에이 코드가 도움이되었습니다! @tronman에게 감사합니다 !! :)
Melvin Lai 2016 년

2
당신과 같이 다른 (최종) 변수에 복사 간단하게 할 수 있습니다 final Button mynewbutton = mybutton;사용 mynewbutton핸들러 및 실행 가능한에서에서 거기에.
Dzhuneyt

2
5 년 후 @MelvinLai 및이 코드는 저에게 도움이되었습니다! :)
gabrieloliveira

191

당신은 그것이이 일을 시도 할 수 있습니다 짧은

SystemClock.sleep(7000);

경고 : 절대로 UI 스레드에서 수행하지 마십시오.

이것을 사용하여 잠자십시오. 배경 실.


문제에 대한 전체 솔루션은 다음과 같습니다. 이것은 사용 가능한 API입니다 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보다 낫습니다. 처리기별로보기를 유지하지 않기 때문입니다. 또한 불량 스레드에서 작성된 Handler에는 문제가 없습니다.)

선적 서류 비치

공공 정적 무효 수면 (긴 ms)

API 레벨 1에 추가됨

돌아 오기 전에 주어진 밀리 초 (uptimeMillis) 동안 기다립니다. sleep (long)과 유사 하지만 InterruptedException을 발생시키지 않습니다 . 다음 인터럽트 가능 조작까지 인터럽트 () 이벤트가 지연됩니다. 않습니다 반환하지 적어도 지정된 밀리 초를 경과 할 때까지.

매개 변수

밀리 초의 가동 시간으로 돌아 오기 전에 ms 가 절전 모드로 전환됩니다.

View 클래스에서 postDelayed 코드 :

/**
 * <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
그리고 안드로이드 UI가 멈추게 하시겠습니까? 이러지 마
shkschneider

3
Ctrl + Shift + O (이클립스 자동 가져 오기)
DAWID 할 Drozd

13
Gelldur, @RichieHH의 의견이 빠졌습니다. 게시하기 3 년 전에 수락 된 답변과 비교하여 OP가 문제를 해결하는 데 도움이되지 않는 것이 좋습니다. 이유 : OP로 표시되고 승인 된 응답으로 표시되는 코드 가 UI 핸들러 내에서 실행 중 입니다. OMG of course do this in background thread백그라운드 스레드에 넣는 방법을 보여주지 않으면 말 은 중요하지 않습니다. 이때 이미 승인 된 답변보다 더 복잡한 답변이 있음을 알게됩니다. 3 년 전에 더 나은 솔루션이 채택되었다고 언급 했습니까? : P
ToolmakerSteve

2
...이 제안이 문제의 목적에 맞지 않게 만드는 이유는 OP가 지연 후에 UI 작업을 명시 적으로 원한다는 것입니다. 따라서 백그라운드 스레드 (이미 문제를 해결하는 데 필요한 것보다 더 무거운 무게)를 만들고 잤다가 UI 스레드로 돌아 가야하는 솔루션이 있습니다. Handler + postRunnable이 모든 것을 한 번에 수행합니다. 두 번째 스레드를 작성하는 시스템 오버 헤드가 없습니다.
ToolmakerSteve

2
@ToolmakerSteve 지금 행복한 : D? 주요 질문은 "안드로이드에서 스레드 또는 프로세스를 일시 중지 / 절전하는 방법"입니다. 그래서 내 대답은 간단했습니다 :). 누군가가 "실을 잠자는 방법"에 대해 구글이라면이 질문이 표시됩니다. 그 / 그녀는 아마도 내 대답을 찾고있을 것입니다 : P. 하지만 좋아, 나는 전체 응답을 추가;)
Dawid Drozd

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()어떻게해야?
Philipp Reichart

간단하고 일반적이며 빠른 예외 메시지가 필요할 때 e.getLocalizedMessage ()를 사용합니다
Byt3

1
그러나 UI 클릭 메소드 내부에서 UI에 대한 추가 업데이트를 할 OP가 요구하는 상황에서는이 작업을 수행하지 않는 것이 좋습니다. 허용되는 Handler/postDelayed솔루션에는 두 가지 장점이 있습니다. (1) 두 번째 스레드의 시스템 오버 헤드를 방지하고 (1) UI 스레드에서 실행되므로 예외없이 UI를 변경할 수 있습니다.
ToolmakerSteve

1
질문의 주요 목표와 직접 관련이 없지만 예외를 포착해서는 안됩니다. 오히려 InterruptedException을 잡아라. 예외를 잡으면 잘못 될 수있는 모든 것을 잡아서 다른 방법으로 잡을 수있는 문제를 숨길 수 있습니다.
Herve Thu

16

당신은 아마 그렇게하고 싶지 않을 것입니다. sleep()버튼 클릭 이벤트 핸들러에 명시를두면 실제로 전체 UI를 잠깐 잠글 수 있습니다. 한 가지 대안은 일종의 단일 샷 타이머 를 사용하는 것입니다 . 배경색을 다시 기본 색으로 변경하고 타이머에서 예약하려면 TimerTask 를 만듭니다 .

또 다른 가능성은 Handler 를 사용하는 것 입니다. 타이머 사용에서 처리기 사용으로 전환 한 사람에 대한 자습서 가 있습니다 .

또한 프로세스를 일시 중지 할 수 없습니다. Java (또는 Android) 프로세스에는 최소한 하나의 스레드가 있으며 스레드 만 휴면 할 수 있습니다.


14

CountDownTime을 사용합니다

new CountDownTimer(5000, 1000) {

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

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

}.start(); 

이것은 유용합니다.
UzaySan

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
왜 postDelayed하지 않습니까? 타이머가 필요하지 않습니다.
RichieHH

8

Yankowsky 씨의 답변 외에도을 사용할 수 있습니다 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 ​​작업을 수행 할 수 없습니다. UI 스레드에 없습니다.
ToolmakerSteve

1
UX 측면에서 데이터를로드하기 위해 사용자에게 차단 대화 상자를 표시하는 것은 좋지 않습니다 ...
2Dee

4

또는 다음을 사용할 수 있습니다.

android.os.SystemClock.sleep(checkEvery)

이것은 랩핑이 필요없는 장점이 try ... catch있습니다.


0

코 틀린과 코 루틴 을 사용한다면 간단하게 할 수 있습니다

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

UI를 업데이트해야하는 경우

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

그리고 tronman 답변에 설명 된대로 "정적 클래스"방법과 결합 할 수 있는지 두 배로하십시오

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.