Yaroslav Mytkalyk
Yaroslav Mytkalyk

Reputation: 17115

Run Handler messages in a background thread

I want to run some Runnable in a background thread. I want to use Handler because it's convenient for delays. What I mean is

handler.post(runnable, delay);

Where runnable should be run in background Thread. Is it possible to create such Handler? Is there a "background" Looper somewhere or how can I create it?

P.S. I know how to do it with a custom class extends Thread but it requires a little more coding effort than doing it the handler way. So please don't post other solutions or something like

handler.post(new Runnable() {
    @Override
    public void run() {
        new Thread() {
            @Override
            public void run() {
                //action
            }
        }.start();
    }
});

I just wander if Handler can do it the "clean" way.

Upvotes: 43

Views: 46882

Answers (5)

Renetik
Renetik

Reputation: 6373

I implemented simple way of running tasks on background thread in kotlin:

fun background(function: () -> Unit) = handler.post(function)

private val handler: Handler by lazy { Handler(handlerThread.looper) }

private val handlerThread: HandlerThread by lazy {
    HandlerThread("RenetikBackgroundThread").apply {
        setUncaughtExceptionHandler { _, e -> later { throw RuntimeException(e) } }
        start()
    }
}

The general idea is that tasks are simple to execute and running one after other sequentially and uncatched exceptions are propagated to main thread so they don't get lost. Function later is basically handler running on main thread.

So you can post tasks simply like this:

 background {
    some task to do in background...  
 }

some kode

 background {
    other task to do in background...  
    later {
        on main thread when all tasks are finished...
    }
 }

Upvotes: 0

Himanshu Khandelwal
Himanshu Khandelwal

Reputation: 5761

You can simply do this:

private Handler mHandler;

private HandlerThread mHandlerThread;

public void startHandlerThread(){
    mHandlerThread = new HandlerThread("HandlerThread");
    mHandlerThread.start();
    mHandler = new Handler(mHandlerThread.getLooper());
}

Then invoke with:

mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
          // Your task goes here
        }
    },1000);

Upvotes: 89

Ayman Mahgoub
Ayman Mahgoub

Reputation: 4220

You can try something like this

    private void createHandler() {
        Thread thread = new Thread() {
            public void run() {
                Looper.prepare();

                final Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                       // Do Work
                        handler.removeCallbacks(this);
                        Looper.myLooper().quit();
                   }
                }, 2000);

                Looper.loop();
            }
        };
        thread.start();
    }

Upvotes: 10

Yuichi Araki
Yuichi Araki

Reputation: 3458

You can set up a Looper in a background thread using Looper.prepare() and Looper.loop.

Upvotes: 5

OldCurmudgeon
OldCurmudgeon

Reputation: 65889

Not clear what you mean by Handler.

It sounds like you need a thread that is fed processes to perform by a queue. You would probably benefit from investigating Executors here but here's a simple two-thread pair that communicate through a queue.

public class TwoThreads {
  public static void main(String args[]) throws InterruptedException {
    System.out.println("TwoThreads:Test");
    new TwoThreads().test();
  }
  // The end of the list.
  private static final Integer End = -1;

  static class Producer implements Runnable {
    final Queue<Integer> queue;

    public Producer(Queue<Integer> queue) {
      this.queue = queue;
    }

    @Override
    public void run() {
      try {
        for (int i = 0; i < 1000; i++) {
          queue.add(i);
          Thread.sleep(1);
        }
        // Finish the queue.
        queue.add(End);
      } catch (InterruptedException ex) {
        // Just exit.
      }
    }
  }

  static class Consumer implements Runnable {
    final Queue<Integer> queue;

    public Consumer(Queue<Integer> queue) {
      this.queue = queue;
    }

    @Override
    public void run() {
      boolean ended = false;
      while (!ended) {
        Integer i = queue.poll();
        if (i != null) {
          ended = i == End;
          System.out.println(i);
        }
      }
    }
  }

  public void test() throws InterruptedException {
    Queue<Integer> queue = new LinkedBlockingQueue<>();
    Thread pt = new Thread(new Producer(queue));
    Thread ct = new Thread(new Consumer(queue));
    // Start it all going.
    pt.start();
    ct.start();
    // Wait for it to finish.
    pt.join();
    ct.join();
  }
}

Upvotes: 0

Related Questions