Search code examples
javaandroidandroid-handler

Handler(Handler.Callback) is deprecated


Handler(android.os.Handler.Callback) is deprecated what should I use instead?

Handler handler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(@NonNull Message message) {
        switch(message.what) {
            case READ_MESSAGE:
                byte[] readBuff = (byte[]) message.obj;
                String tempMessage = new String(readBuff, 0, message.arg1);
                readMsg.setText(tempMessage);
                break;
        }
        return true;
    }
});

Solution

  • From API level 30, there are 2 constructors are deprecated.

    Google explains the reason below.

    Implicitly choosing a Looper during Handler construction can lead to bugs where operations are silently lost (if the Handler is not expecting new tasks and quits), crashes (if a handler is sometimes created on a thread without a Looper active), or race conditions, where the thread a handler is associated with is not what the author anticipated. Instead, use an Executor or specify the Looper explicitly, using Looper#getMainLooper, {link android.view.View#getHandler}, or similar. If the implicit thread local behavior is required for compatibility, use new Handler(Looper.myLooper(), callback) to make it clear to readers.

    Solution 1: Use an Executor

    1. Execute code in the main thread.

    // Create an executor that executes tasks in the main thread. 
    Executor mainExecutor = ContextCompat.getMainExecutor(this);
    
    // Execute a task in the main thread
    mainExecutor.execute(new Runnable() {
        @Override
        public void run() {
            // You code logic goes here.
        }
    });
    

    2. Execute code in a background thread

    // Create an executor that executes tasks in a background thread.
    ScheduledExecutorService backgroundExecutor = Executors.newSingleThreadScheduledExecutor();
    
    // Execute a task in the background thread.
    backgroundExecutor.execute(new Runnable() {
        @Override
        public void run() {
            // Your code logic goes here.
        }
    });
    
    // Execute a task in the background thread after 1 second.
    backgroundExecutor.schedule(new Runnable() {
        @Override
        public void run() {
            // Your code logic goes here
        }
    }, 1, TimeUnit.SECONDS);
    

    Note: Remember to shut down the executor after using.

    backgroundExecutor.shutdown(); // or backgroundExecutor.shutdownNow();
    

    3. Execute code in a background thread and update UI on the main thread.

    // Create an executor that executes tasks in the main thread. 
    Executor mainExecutor = ContextCompat.getMainExecutor(this);
    
    // Create an executor that executes tasks in a background thread.
    ScheduledExecutorService backgroundExecutor = Executors.newSingleThreadScheduledExecutor();
    
    // Execute a task in the background thread.
    backgroundExecutor.execute(new Runnable() {
        @Override
        public void run() {
            // Your code logic goes here.
            
            // Update UI on the main thread
            mainExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    // You code logic goes here.
                }
            });
        }
    });
    

    Solution 2: Specify a Looper explicitly by using one of the following constructors.

    1. Execute code in the main thread

    1.1. Handler with a Looper

    Handler mainHandler = new Handler(Looper.getMainLooper());
    

    1.2 Handler with a Looper and a Handler.Callback

    Handler mainHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message message) {
            // Your code logic goes here.
            return true;
        }
    });
    

    2. Execute code in a background thread

    2.1. Handler with a Looper

    // Create a background thread that has a Looper
    HandlerThread handlerThread = new HandlerThread("HandlerThread");
    handlerThread.start();
    
    // Create a handler to execute tasks in the background thread.
    Handler backgroundHandler = new Handler(handlerThread.getLooper()); 
    

    2.2. Handler with a Looper and a Handler.Callback

    // Create a background thread that has a Looper
    HandlerThread handlerThread = new HandlerThread("HandlerThread");
    handlerThread.start();
    
    // Create a handler to execute taks in the background thread.
    Handler backgroundHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message message) {
            // Your code logic goes here.
            return true;
        }
    });
    

    Note: Remember to release the thread after using.

    handlerThread.quit(); // or handlerThread.quitSafely();
    

    3. Execute code in a background thread and update UI on the main thread.

    // Create a handler to execute code in the main thread
    Handler mainHandler = new Handler(Looper.getMainLooper());
    
    // Create a background thread that has a Looper
    HandlerThread handlerThread = new HandlerThread("HandlerThread");
    handlerThread.start();
    
    // Create a handler to execute in the background thread
    Handler backgroundHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message message) {
            // Your code logic goes here.
            
            // Update UI on the main thread.
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    
                }
            });
            
            return true;
        }
    });