programing tip

Android에서 지연 후 메서드를 호출하는 방법

itbloger 2020. 9. 30. 08:52
반응형

Android에서 지연 후 메서드를 호출하는 방법


지정된 지연 후에 다음 메서드를 호출 할 수 있기를 원합니다. 객관적인 c에는 다음과 같은 것이 있습니다.

[self performSelector:@selector(DoSomething) withObject:nil afterDelay:5];

자바와 함께 안드로이드 에이 메소드와 동등한 것이 있습니까? 예를 들어 5 초 후에 메서드를 호출 할 수 있어야합니다.

public void DoSomething()
{
     //do something here
}

Kotlin

Handler().postDelayed({
  //Do something after 100ms
}, 100)


자바

final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
  @Override
  public void run() {
    //Do something after 100ms
  }
}, 100);



제 경우에는 다른 답변을 사용할 수 없었습니다. 대신 네이티브 자바 타이머를 사용했습니다.

new Timer().schedule(new TimerTask() {          
    @Override
    public void run() {
        // this code will be executed after 2 seconds       
    }
}, 2000);

참고 : 이 답변은 질문에서 Android를 컨텍스트로 지정하지 않았을 때 제공되었습니다. Android UI 스레드에 대한 답변 은 여기를 참조하십시오.


Mac OS API를 사용하면 현재 스레드가 계속되고 작업이 비동기 적으로 실행되도록 예약하는 것처럼 보입니다. Java에서는 동일한 기능이 java.util.concurrent패키지에 의해 제공됩니다 . Android가 어떤 제한을 부과할지 잘 모르겠습니다.

private static final ScheduledExecutorService worker = 
  Executors.newSingleThreadScheduledExecutor();

void someMethod() {
  Runnable task = new Runnable() {
    public void run() {
      /* Do something… */
    }
  };
  worker.schedule(task, 5, TimeUnit.SECONDS);
}

5 초 후에 UI 스레드에서 무언가를 실행하는 경우 :

new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
    @Override
    public void run() {
        //Do something here
    }
}, 5000);

UIThread 내에서 Handler를 사용할 수 있습니다.

runOnUiThread(new Runnable() {

    @Override
    public void run() {
         final Handler handler = new Handler();
         handler.postDelayed(new Runnable() {
           @Override
           public void run() {
               //add your code here
           }
         }, 1000);

    }
});

모든 훌륭한 답변에 감사 드리며 제 요구에 가장 적합한 솔루션을 찾았습니다.

Handler myHandler = new DoSomething();
Message m = new Message();
m.obj = c;//passing a parameter here
myHandler.sendMessageDelayed(m, 1000);

class DoSomething extends Handler {
    @Override
    public void handleMessage(Message msg) {
      MyObject o = (MyObject) msg.obj;
      //do something here
    }
}

이 데모보기 :

import java.util.Timer;
import java.util.TimerTask;

class Test {
     public static void main( String [] args ) {
          int delay = 5000;// in ms 

          Timer timer = new Timer();

          timer.schedule( new TimerTask(){
             public void run() { 
                 System.out.println("Wait, what..:");
              }
           }, delay);

           System.out.println("Would it run?");
     }
}

Handler를 사용해야하지만 다른 스레드에있는 경우 runonuithread사용 하여 UI 스레드에서 처리기를 실행할 수 있습니다 . 이렇게하면 전화를 요청하는 예외가 발생하지 않습니다.Looper.Prepare()

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //Do something after 1 second
            }
        }, 1000);
    }
});

꽤 지저분 해 보이지만 이것이 방법 중 하나입니다.


View.postDelayed()아래의 간단한 코드 를 사용하는 것을 선호 합니다.

mView.postDelayed(new Runnable() {
    @Override
    public void run() {
        // Do something after 1000 ms
    }
}, 1000);

내 가장 짧은 해결책은 다음과 같습니다.

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        //Do something after 100ms
    }
}, 100);

KotlinJava다양한 방법

1. 사용 Handler

Handler().postDelayed({
    TODO("Do something")
    }, 2000)

2. TimerTask 사용

Timer().schedule(object : TimerTask() {
    override fun run() {
        TODO("Do something")
    }
}, 2000)

또는 더 짧게

Timer().schedule(timerTask {
    TODO("Do something")
}, 2000)

또는 가장 짧은 것은

Timer().schedule(2000) {
    TODO("Do something")
}

3. 사용 Executors

Executors.newSingleThreadScheduledExecutor().schedule({
    TODO("Do something")
}, 2, TimeUnit.SECONDS)

자바에서

1. 사용 Handler

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        //Do something
    }
}, 2000);

2. 사용 Timer

new Timer().schedule(new TimerTask() {          
    @Override
    public void run() {
        // Do something
    }
}, 2000);

3. 사용 ScheduledExecutorService

private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();

Runnable runnable = new Runnable() {
  public void run() {
      // Do something
  }
  };
worker.schedule(runnable, 2, TimeUnit.SECONDS);

final Handler handler = new Handler(); 
Timer t = new Timer(); 
t.schedule(new TimerTask() { 
    public void run() { 
        handler.post(new Runnable() { 
            public void run() { 
                //DO SOME ACTIONS HERE , THIS ACTIONS WILL WILL EXECUTE AFTER 5 SECONDS...
            }
        }); 
    } 
}, 5000); 

당신이 사용하는 경우 안드로이드 스튜디오 3.0 이상 당신은 람다 표현식을 사용할 수 있습니다. 이 메서드 callMyMethod()는 2 초 후에 호출됩니다.

new Handler().postDelayed(() -> callMyMethod(), 2000);

지연된 실행 파일을 취소해야하는 경우 다음을 사용하십시오.

Handler handler = new Handler();
handler.postDelayed(() -> callMyMethod(), 2000);

// When you need to cancel all your posted runnables just use:
handler.removeCallbacksAndMessages(null);

Timer를 제안합니다 . 매우 특정한 간격으로 메서드를 호출하도록 예약 할 수 있습니다. 이렇게하면 UI가 차단되지 않으며 메서드가 실행되는 동안 앱이 공감할 수 있습니다.

다른 옵션은 wait (); 메서드를 사용하면 지정된 시간 동안 현재 스레드를 차단합니다. 이로 인해 UI 스레드에서이 작업을 수행하면 UI가 응답하지 않습니다.


가장 간단한 솔루션에 이것을 사용할 수 있습니다.

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        //Write your code here
    }
}, 5000); //Timer is in ms here.

그렇지 않으면 아래는 또 다른 깨끗한 유용한 솔루션이 될 수 있습니다.

new Handler().postDelayed(() -> 
{/*Do something here*/}, 
5000); //time in ms

새로 도입 된 람다 식을 사용하여 훨씬 깔끔하게 만들 수 있습니다.

new Handler().postDelayed(() -> {/*your code here*/}, time);

이것을 호출하는 더 간단한 방법을 만들었습니다.

public static void CallWithDelay(long miliseconds, final Activity activity, final String methodName)
    {
        new Handler().postDelayed(new Runnable() {

            @Override
            public void run() {
                try {
                    Method method =  activity.getClass().getMethod(methodName);
                    method.invoke(activity);
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }, miliseconds);
    }

그것을 사용하려면 다음을 호출하십시오. .CallWithDelay(5000, this, "DoSomething");


아래 하나는 얻을 때 작동합니다.

java.lang.RuntimeException : Looper.prepare ()를 호출하지 않은 스레드 내부에 핸들러를 작성할 수 없습니다.

final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
  @Override
  public void run() {
    //Do something after 100ms
  }
}, 100);

Simple line Handle Post 지연의 경우 다음과 같이 할 수 있습니다.

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        // Do someting
    }
}, 3000);

이게 도움이 되길 바란다


.NET Framework를 사용하는 것은 매우 쉽습니다 CountDownTimer. 자세한 내용은 https://developer.android.com/reference/android/os/CountDownTimer.html

import android.os.CountDownTimer;

// calls onTick every second, finishes after 3 seconds
new CountDownTimer(3000, 1000) { 

   public void onTick(long millisUntilFinished) {
      Log.d("log", millisUntilFinished / 1000);
   }

   public void onFinish() {
      // called after count down is finished
   } 
}.start();

이 고양이의 피부를 살리는 방법이 너무 많기 때문에 여기에서 고려해야 할 몇 가지 사항이 있습니다. 답변은 이미 모두 선택되고 선택되었지만. "대부분이 간단한 대답을 선택했다"는 이유로 잘못된 방향으로가는 사람을 피하기 위해 적절한 코딩 지침으로 이것을 다시 검토하는 것이 중요하다고 생각합니다.

따라서 먼저이 스레드에서 전체적으로 승자가 선택한 답변 인 간단한 Post Delayed 답변에 대해 논의하겠습니다.

고려해야 할 몇 가지 사항입니다. 게시 지연 후 메모리 누수, 죽은 개체, 사라진 수명주기 등이 발생할 수 있습니다. 따라서 제대로 처리하는 것도 중요합니다. 몇 가지 방법으로이를 수행 할 수 있습니다.

현대적인 발전을 위해 KOTLIN에서 공급하겠습니다.

다음은 콜백에서 UI 스레드를 사용하고 콜백을 쳤을 때 활동이 여전히 살아 있고 잘 있는지 확인하는 간단한 예입니다.

  Handler(Looper.getMainLooper()).postDelayed({
            if(activity != null && activity?.isFinishing == false){
                txtNewInfo.visibility = View.GONE
            }
        }, NEW_INFO_SHOW_TIMEOUT_MS)

그러나 활동이 사라지면 콜백을 칠 이유가 없기 때문에 여전히 완벽하지 않습니다. 그래서 더 좋은 방법은 그것에 대한 참조를 유지하고 이와 같은 콜백을 제거하는 것입니다.

    private fun showFacebookStylePlus1NewsFeedOnPushReceived(){
        A35Log.v(TAG, "showFacebookStylePlus1NewsFeedOnPushReceived")
        if(activity != null && activity?.isFinishing == false){
            txtNewInfo.visibility = View.VISIBLE
            mHandler.postDelayed({
                if(activity != null && activity?.isFinishing == false){
                    txtNewInfo.visibility = View.GONE
                }
            }, NEW_INFO_SHOW_TIMEOUT_MS)
        }
    }

그리고 물론 onPause에서 정리를 처리하여 콜백에 부딪히지 않도록합니다.

    override fun onPause() {
        super.onPause()
        mHandler.removeCallbacks(null)
    }

이제 우리는 명백한 것에 대해 이야기 했으므로 현대 코 루틴과 kotlin을 사용한 더 깨끗한 옵션에 대해 이야기합시다 :). 아직 사용하지 않는다면 정말 빠진 것입니다.

   fun doActionAfterDelay() 
        launch(UI) {
            delay(MS_TO_DELAY)           
            actionToTake()
        }
    }

또는 항상 해당 메서드에서 UI 시작을 수행하려면 다음을 수행하면됩니다.

  fun doActionAfterDelay() = launch(UI){ 
      delay(MS_TO_DELAY)           
      actionToTake()
  }

물론 PostDelayed와 마찬가지로 지연 호출 후 활동 확인을 수행하거나 다른 경로와 마찬가지로 onPause에서 취소 할 수 있도록 취소를 처리해야합니다.

var mDelayedJob: Job? = null
fun doActionAfterDelay() 
   mDelayedJob = launch(UI) {
            try {
               delay(MS_TO_DELAY)           
               actionToTake()
            }catch(ex: JobCancellationException){
                showFancyToast("Delayed Job canceled", true, FancyToast.ERROR, "Delayed Job canceled: ${ex.message}")
            }
        }
   }
}

// 정리 처리

override fun onPause() {
   super.onPause()
   if(mDelayedJob != null && mDelayedJob!!.isActive) {
      A35Log.v(mClassTag, "canceling delayed job")
      mDelayedJob?.cancel() //this should throw CancelationException in coroutine, you can catch and handle appropriately
   }
}

launch (UI)를 메서드 서명에 넣으면 작업이 호출 코드 줄에 할당 될 수 있습니다.

따라서 이야기의 교훈은 지연된 작업으로 안전하고, 콜백을 제거하거나 작업을 취소하고, 물론 지연 콜백에서 항목을 만질 수있는 올바른 수명주기가 있는지 확인하는 것입니다. 코 루틴은 취소 가능한 작업도 제공합니다.

또한 일반적으로 코 루틴과 함께 올 수있는 다양한 예외를 처리해야한다는 점도 주목할 가치가 있습니다. 예를 들어 취소, 예외, 시간 초과 등 사용하기로 결정한 것입니다. 코 루틴을 실제로 사용하기로 결정한 경우 더 고급 예제가 있습니다.

   mLoadJob = launch(UI){
            try {
                //Applies timeout
                withTimeout(4000) {
                    //Moves to background thread
                    withContext(DefaultDispatcher) {
                        mDeviceModelList.addArrayList(SSDBHelper.getAllDevices())
                    }
                }

                //Continues after async with context above
                showFancyToast("Loading complete", true, FancyToast.SUCCESS)
            }catch(ex: JobCancellationException){
                showFancyToast("Save canceled", true, FancyToast.ERROR, "Save canceled: ${ex.message}")
            }catch (ex: TimeoutCancellationException) {
                showFancyToast("Timed out saving, please try again or press back", true, FancyToast.ERROR, "Timed out saving to database: ${ex.message}")
            }catch(ex: Exception){
                showFancyToast("Error saving to database, please try again or press back", true, FancyToast.ERROR, "Error saving to database: ${ex.message}")
            }
        }

모두가 새 실행 파일이나 메시지를 게시하기 전에 핸들러를 정리하는 것을 잊은 것 같습니다. 그렇지 않으면 잠재적으로 축적되어 나쁜 행동을 유발할 수 있습니다.

handler.removeMessages(int what);
// Remove any pending posts of messages with code 'what' that are in the message queue.

handler.removeCallbacks(Runnable r)
// Remove any pending posts of Runnable r that are in the message queue.

또 다른 까다로운 방법이 있습니다. 실행 가능한 UI 요소가 변경 될 때 예외가 발생하지 않습니다.

public class SimpleDelayAnimation extends Animation implements Animation.AnimationListener {

    Runnable callBack;

    public SimpleDelayAnimation(Runnable runnable, int delayTimeMilli) {
        setDuration(delayTimeMilli);
        callBack = runnable;
        setAnimationListener(this);
    }

    @Override
    public void onAnimationStart(Animation animation) {

    }

    @Override
    public void onAnimationEnd(Animation animation) {
        callBack.run();
    }

    @Override
    public void onAnimationRepeat(Animation animation) {

    }
}

다음과 같이 애니메이션을 호출 할 수 있습니다.

view.startAnimation(new SimpleDelayAnimation(delayRunnable, 500));

애니메이션은 모든 뷰에 연결할 수 있습니다.


게으른 게으른 사람들에게 Kotlin 의 대답은 다음과 같습니다 .

Handler().postDelayed({
//doSomethingHere()
}, 1000)

나는 더 깨끗한 것을 좋아한다 : 여기 내 구현, 당신의 메소드 내에서 사용할 인라인 코드가 있습니다.

new Handler().postDelayed(new Runnable() {
  @Override
  public void run() {
    //Do something after 100ms
  }
}, 100);

안드로이드에 적합한 솔루션 :

private static long SLEEP_TIME = 2 // for 2 second
.
.
MyLauncher launcher = new MyLauncher();
            launcher.start();
.
.
private class MyLauncher extends Thread {
        @Override
        /**
         * Sleep for 2 seconds as you can also change SLEEP_TIME 2 to any. 
         */
        public void run() {
            try {
                // Sleeping
                Thread.sleep(SLEEP_TIME * 1000);
            } catch (Exception e) {
                Log.e(TAG, e.getMessage());
            }
            //do something you want to do
           //And your code will be executed after 2 second
        }
    }

RxAndroid를 사용하면 스레드 및 오류 처리가 훨씬 쉬워집니다. 지연 후 다음 코드가 실행됩니다.

   Observable.timer(delay, TimeUnit.SECONDS)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(aLong -> {
           // Execute code here
        }, Throwable::printStackTrace);

유사한 솔루션이지만 사용하기 훨씬 더 깨끗합니다.

이 함수를 클래스 외부에 작성하십시오.

fun delay(duration: Long, `do`: () -> Unit) {

    Handler().postDelayed(`do`, duration)

}

용법:

delay(5000) {
    //Do your work here
}

Android에서는 모든 기능의 실행을 지연시키기 위해 kotlin 코드 아래에 작성할 수 있습니다.

class MainActivity : AppCompatActivity() {

private lateinit var handler: Handler

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    handler= Handler()
    handler.postDelayed({
        doSomething()
    },2000)
}

private fun doSomething() {
    Toast.makeText(this,"Hi! I am Toast Message",Toast.LENGTH_SHORT).show()
}
}

이 작업을 수행하는 방법에는 여러 가지가 있지만 가장 좋은 방법은 아래와 같은 핸들러를 사용하는 것입니다.

long millisecDelay=3000

Handler().postDelayed({
  // do your work here
 },millisecDelay)

참고 URL : https://stackoverflow.com/questions/3072173/how-to-call-a-method-after-a-delay-in-android

반응형