วิธีการเรียกวิธีหลังจากความล่าช้าใน Android


769

ฉันต้องการที่จะสามารถเรียกวิธีต่อไปนี้หลังจากความล่าช้าที่ระบุ ในวัตถุประสงค์ c มีบางสิ่งเช่น:

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

มีวิธีนี้เทียบเท่าใน Android กับ Java หรือไม่? ตัวอย่างเช่นฉันต้องสามารถเรียกวิธีหลังจาก 5 วินาที

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

คำตอบ:


1858

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



109
วิธีการแก้ปัญหานี้มีประโยชน์เฉพาะในเธรด UI มิฉะนั้นในหัวข้อปกติคุณต้องใช้ Looper ซึ่งไม่ใช่รุ่นที่ดีที่สุดที่ฉันคิดว่า
olivier_sdg

2
@olivier_sdg ทำไมคุณต้องใช้งาน looper?
djechlin

37
@djechlin ตัวจัดการต้องเชื่อมโยงกับ Looper ซึ่งจะประมวลผล Runnable ที่คุณโพสต์ () เธรด UI มาพร้อมกับ Looper แล้วดังนั้นคุณสามารถสร้าง Handler () ใหม่บน UI ของเธรดและโพสต์ () เรียกใช้โดยตรงไปยังเธรดนั้น Runnables เหล่านี้ทำงานบนเธรด UI หากต้องการให้ Runnables ดำเนินการกับเธรดอื่นคุณต้องสร้างเธรดใหม่จากนั้น Looper.prepare () สร้าง Handler ใหม่ () และ Looper.loop () Runnables ใด ๆ ที่โพสต์ไปที่ Handler ใหม่นี้จะดำเนินการกับเธรดใหม่นี้ หากคุณไม่ทำสิ่งนี้โพสต์ () จะส่งข้อยกเว้น
Dororo

12
ในกรณีที่คุณต้องการคุณยังสามารถยกเลิกการดำเนินการเป็นเวลานานเป็น Runnable ยังคงอยู่ในคิวข้อความโดยการเรียกบนremoveCallbacks(Runnable r) Handler
Dennis

9
ควรimport android.os.handler
KaKa

322

ฉันไม่สามารถใช้คำตอบอื่นใดในกรณีของฉัน ฉันใช้ตัวจับเวลา java ดั้งเดิมแทน

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

43
สิ่งนี้ดีกว่าตัวที่ใช้ตัวจัดการเนื่องจากไม่มีปัญหา Looper เมื่อตัวจัดการไม่ได้ทำงานบนเธรด UI
Ben H

32
คุณควรอ้างอิงถึงตัวจับเวลาของคุณเพื่อที่จะยกเลิกเมื่อมันไม่จำเป็นอีกต่อไปเนื่องจากตามเอกสาร Android: "เมื่อไม่จำเป็นต้องใช้ตัวจับเวลาอีกต่อไปผู้ใช้ควรโทรยกเลิก () ซึ่งปล่อยเธรดของตัวจับเวลาและแหล่งข้อมูลอื่น ๆ ตัวจับเวลาที่ไม่ได้ยกเลิกอย่างชัดเจนอาจเก็บทรัพยากรไว้ไม่สิ้นสุด "
Pooks

14
ความสนใจ! สิ่งนี้ไม่ทำงานบนเธรด UI การรันสิ่งนี้บนเธรด ui ทำให้เกิดข้อผิดพลาดร้ายแรง: android.view.ViewRootImpl $ CalledFromWrongThreadException: เฉพาะเธรดดั้งเดิมที่สร้างลำดับชั้นมุมมองเท่านั้นที่สามารถสัมผัสมุมมองได้
vovahost

13
@vovahost เป็นเพียงเพราะคุณกำลังอัปเดตส่วนประกอบ UI ภายในบล็อคตัวจับเวลา
ทิม

10
โปรดทราบว่า java.util.Timer (และ TimerTask) จะถูกคัดค้านใน JDK 9 TimerTask สร้างเธรดใหม่สำหรับงานที่ไม่ดีมาก
Varvara Kalinina

183

หมายเหตุ:คำตอบนี้ได้รับเมื่อคำถามไม่ได้ระบุ Android เป็นบริบท สำหรับคำตอบเฉพาะสำหรับเธรด UI ของ Android ให้ดูที่นี่


ดูเหมือนว่า 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);
  
}

3
นี่ไม่เคยเรียก Runnable ให้ฉัน
Supuhstar

14
ในฐานะที่เป็นหมายเหตุด้านข้าง: สิ่งนี้ช่วยให้คุณสามารถยกเลิกงานในภายหลังซึ่งอาจเป็นประโยชน์ในบางสถานการณ์ เพียงเก็บการอ้างอิงถึงผลScheduledFuture<?>ตอบแทนworker.schedule()และเรียกcancel(boolean)วิธีการ
Dennis

ฉันคิดว่าคำตอบนี้ล้าสมัยแล้ว .schedule ดูเหมือนจะไม่เป็นวิธีของ Runnable อีกต่อไป ... ? : /
beetree

5
@beetree ScheduledExecutorServiceมันเป็นวิธีการในการ
erickson

3
สิ่งนี้ใช้ไม่ได้หากมีวัตถุที่เกี่ยวข้องกับเธรด ui คุณต้องเรียกใช้ runOnUIThread (runnable ใหม่ () {run () .... }); หรือโพสต์ runnable โดยใช้ตัวจัดการวัตถุจากด้านใน run () {}
Jayant Arora

107

สำหรับการดำเนินการบางอย่างใน UI Thread หลังจาก 5 วินาที:

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

8
ยืนยันนี่เป็นทางออกที่ดีที่สุดในการป้องกันการโทรไปยัง looper.prepare และวางสิ่งทั้งหมดลงในเธรด UI
Tobliug

ขอบคุณสำหรับสิ่งนี้ช่วยฉันด้วยปัญหา Looper :)
Tia

1
ฉันจะระมัดระวังเกี่ยวกับการสร้างตัวจัดการใน looper หลักจากนั้นในหัวข้อนี้ไม่ควรทำงานเป็นเวลานาน
Shayan_Aryan

40

คุณสามารถใช้ตัวจัดการภายใน UIThread:

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

    }
});

36

ขอบคุณสำหรับคำตอบที่ยอดเยี่ยมทั้งหมดฉันพบโซลูชันที่เหมาะสมกับความต้องการของฉันมากที่สุด

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

ไม่เป็นไรถ้าฉันใช้วิธีการนี้เพื่อรับผลตอบรับแบบสัมผัสเมื่อคลิกรายการ .. view.setColor (some_color) แล้วลบสีนี้ในตัวจัดการหลังจาก x วินาที ... ?
eRaisedToX

24

Kotlin& Javaหลายวิธี

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

1
@ JanRabe ขอบคุณสำหรับคำแนะนำของคุณ ฉันให้คุณค่ากับมัน How to call a method after a delay in Androidแต่คำถามคือ ดังนั้นฉันจึงมุ่งไปที่ ตรงประเด็น มิฉะนั้นการรั่วไหลของจาวาเป็นหัวข้อใหญ่ที่ต้องทำความเข้าใจกับผู้พัฒนาแยกต่างหาก
Khemraj

20

ดูการสาธิตนี้:

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

20

หากคุณต้องใช้ตัวจัดการ แต่คุณอยู่ในเธรดอื่นคุณสามารถใช้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);
    }
});

ดูค่อนข้างยุ่ง แต่นี่เป็นอีกวิธีหนึ่ง


4
ใช้งานได้ฉันไม่สามารถแก้ไขโพสต์ของคุณเนื่องจากกฎ SO โง่ที่มีอักขระอย่างน้อย 6 ตัวที่ต้องแก้ไข แต่มี '()' หายไปหลังจาก 'ตัวจัดการใหม่' ควรเป็น 'ตัวจัดการใหม่ ()'
Jonathan Muller

2
แทนที่จะวางทุกอย่างลงในเธรด UI คุณสามารถทำได้: ตัวจัดการใหม่ (Looper.getMainLooper ())
Tobliug

17

ฉันชอบที่จะใช้View.postDelayed()วิธีการรหัสง่าย ๆ ด้านล่าง:

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

1
ไม่ตรึงองค์ประกอบ ui เองหรือไม่เพราะจะถูกกำหนดไว้ในตัวจัดการมุมมอง
JacksOnF1re

1
ไม่งานที่โพสต์จะถูกดำเนินการใน 1 วินาที แต่ในระหว่าง UI เธรดที่สองนี้จะทำงานที่มีประโยชน์อื่น ๆ
demaksee

14

นี่คือทางออกที่สั้นที่สุดของฉัน:

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

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

10

หากคุณใช้Android Studio 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);

เราจะยกเลิกสิ่งนี้ได้อย่างไร
Damia Fuentes

ฉันประหลาดใจที่จำนวนที่นี่จะย้ายเข้าสู่ Kotlin อย่างมีความสุข แต่ก็ไม่สนใจ Lambda Expressions ซึ่งเป็น Java มาตรฐานอย่างสมบูรณ์
TomDK

6

ฉันแนะนำตัวจับเวลาช่วยให้คุณสามารถกำหนดวิธีการที่จะเรียกในช่วงเวลาที่เฉพาะเจาะจงมาก สิ่งนี้จะไม่บล็อก UI ของคุณและทำให้แอปของคุณทำงานได้อย่างต่อเนื่องขณะที่กำลังดำเนินการตามวิธีการ

ตัวเลือกอื่น ๆ คือการรอ (); วิธีการนี้จะบล็อกเธรดปัจจุบันตามระยะเวลาที่กำหนด นี่จะทำให้ UI ของคุณหยุดตอบสนองหากคุณทำสิ่งนี้บนเธรด UI


2
Thread.sleep () ดีกว่า Object.wait () รอหมายความว่าคุณคาดว่าจะได้รับการแจ้งเตือนและกำลังซิงโครไนซ์รอบ ๆ กิจกรรมบางอย่าง โหมดสลีปบ่งบอกว่าคุณไม่ต้องการทำอะไรในเวลาที่กำหนด ตัวจับเวลาเป็นวิธีที่จะไปหากคุณต้องการให้การกระทำเกิดขึ้นแบบไม่พร้อมกันในเวลาต่อมา
ทิมเบนเดอร์

1
นั่นเป็นความจริง. นั่นเป็นเหตุผลที่ฉันระบุว่าเป็นตัวเลือกอื่น ;-)
Nate

6

สำหรับความล่าช้าของ Simple Post Handle Post คุณสามารถทำดังต่อไปนี้:

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

ฉันหวังว่านี่จะช่วยได้


5

คุณสามารถใช้สิ่งนี้สำหรับการแก้ปัญหาที่ง่ายที่สุด:

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

5

คุณสามารถทำให้มันสะอาดขึ้นโดยใช้แลมบ์ดานิพจน์ที่เพิ่งเปิดตัวใหม่:

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

5

ดังนั้นมีบางสิ่งที่ควรพิจารณาที่นี่เนื่องจากมีหลายวิธีในการดูแลแมวตัวนี้ แม้ว่าคำตอบจะได้รับการคัดเลือกและเลือกแล้ว ฉันคิดว่ามันเป็นสิ่งสำคัญที่จะได้รับการเยี่ยมชมอีกครั้งพร้อมแนวทางการเข้ารหัสที่เหมาะสมเพื่อหลีกเลี่ยงทุกคนที่ไปในทิศทางที่ผิดเพียงเพราะ "เลือกคำตอบง่ายๆส่วนใหญ่"

ดังนั้นก่อนอื่นเรามาพูดคุยเกี่ยวกับคำตอบแบบโพสต์ล่าช้าแบบง่าย ๆ นั่นคือผู้ชนะที่เลือกคำตอบโดยรวมในหัวข้อนี้

สองสิ่งที่ควรพิจารณา หลังจากการโพสต์ล่าช้าคุณสามารถพบการรั่วไหลของหน่วยความจำวัตถุที่ตายวงจรชีวิตที่หายไปและอื่น ๆ ดังนั้นการจัดการอย่างถูกต้องจึงเป็นสิ่งสำคัญเช่นกัน คุณสามารถทำได้สองวิธี

เพื่อประโยชน์ในการพัฒนาที่ทันสมัยฉันจะจัดหาใน 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)
    }

ตอนนี้เราได้พูดคุยกันอย่างชัดเจนแล้วมาพูดถึงตัวเลือกที่สะอาดตากับ coroutines และ 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
   }
}

หากคุณวางการเปิดตัว (UI) ลงในวิธีการที่เป็นลายเซ็นงานสามารถกำหนดได้ในสายของรหัสโทรศัพท์

ดังนั้นเรื่องราวของศีลธรรมจึงปลอดภัยกับการกระทำที่ล่าช้าของคุณตรวจสอบให้แน่ใจว่าคุณลบการเรียกกลับของคุณหรือยกเลิกงานของคุณและแน่นอนว่าคุณมีวงจรชีวิตที่เหมาะสมในการสัมผัสรายการที่โทรกลับล่าช้าของคุณเสร็จสมบูรณ์ Coroutines ยังมีการกระทำที่ยกเลิกได้

นอกจากนี้ยังควรสังเกตว่าโดยปกติคุณควรจัดการกับข้อยกเว้นต่าง ๆ ที่อาจมาพร้อมกับ coroutines ตัวอย่างเช่นการยกเลิกข้อยกเว้นการหมดเวลาไม่ว่าคุณจะตัดสินใจใช้อะไร นี่คือตัวอย่างขั้นสูงถ้าคุณตัดสินใจที่จะเริ่มใช้ coroutines

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

1
ไม่มีปัญหาราจีฟฉันจะใช้ขั้นตอนหนึ่งต่อไปและกล่าวถึงว่าการใช้ข้อมูลสด coroutines สามารถตระหนักถึงวงจรชีวิตและการยกเลิกด้วยตนเองเพื่อหลีกเลี่ยงการโทรล้าง แต่ไม่ต้องการที่จะโยนโค้งการเรียนรู้มากเกินไปเป็นหนึ่งคำตอบ;)
Sam

3

ฉันสร้างวิธีที่ง่ายกว่าเพื่อเรียกสิ่งนี้

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


3
ภาพสะท้อนของงานพื้นฐานนั้นเป็นอย่างไร?
Max Ch

ตั้งแต่คำถามเพื่อเรียกวิธีคล้ายกับ performSelectoriOS นี่เป็นวิธีที่ดีที่สุดที่จะทำ
HelmiB

3

ด้านล่างหนึ่งงานเมื่อคุณได้รับ

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


2

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

2

หากคุณใช้ RxAndroid การจัดการเธรดและข้อผิดพลาดจะง่ายขึ้นมาก รหัสต่อไปนี้รันหลังจากความล่าช้า

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

1

ดูเหมือนว่าทุกคนจะลืมที่จะทำความสะอาดตัวจัดการก่อนที่จะโพสต์ runnable ใหม่หรือข้อความบนมัน นอกจากนี้พวกเขาอาจสะสมและทำให้เกิดพฤติกรรมที่ไม่ดี

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.

1

นี่เป็นอีกวิธีที่ยุ่งยาก: มันจะไม่เกิดข้อยกเว้นเมื่อองค์ประกอบ 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));

ภาพเคลื่อนไหวสามารถแนบกับมุมมองใดก็ได้



1

ฉันชอบสิ่งที่สะอาดกว่า: นี่คือการใช้งานของฉัน, โค้ดแบบอินไลน์เพื่อใช้ในวิธีการของคุณ

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

0

ทางออกที่เหมาะสมใน Android:

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

0

วิธีการแก้ปัญหาที่คล้ายกัน แต่สะอาดกว่าที่จะใช้

เขียนฟังก์ชั่นนี้นอกห้องเรียน

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

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

}

การใช้งาน:

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

`ทำอะไร '
Skizo-ozᴉʞS

แค่ชื่อเก็บอะไรไว้ที่นั่น doเป็นวิธีการ inbuilt ดังนั้นเราต้องใช้ `เพื่อใช้เป็นชื่อตัวแปร
Manohar Reddy

ขอบคุณ แต่ทำไมถึงใช้ชื่อตัวแปรนี้ ฉันหมายถึงฟังก์ชั่นของมันคืออะไร
Skizo-ozᴉʞS

1
ฉันคิดเช่นdoนี้หลังจากล่าช้า 3 วินาที
โนฮา

0

ใน 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()
}
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.