1. Are you ready for the Galaxy S20? Here is everything we know so far!

Can't create handler inside thread that has not called Looper.prepare()

Discussion in 'Android Development' started by mcpixel, Aug 1, 2019.

  1. mcpixel

    mcpixel Newbie
    Thread Starter

    Stack trace:
    Code (Java):
    1. 08-01 19:19:43.254 5291-5291/com.example.app1 E/APP: RUNNING
    2. 08-01 19:19:43.254 5291-5291/com.example.app1 E/APP: onChanged
    3. 08-01 19:19:43.259 5291-5320/com.example.app1 E/WM-WorkerWrapper: Work [ id=495d1e86-0f1f-42a5-9997-3a3c01b878d3, tags={ *****, com.example.app1.UploadWorker } ] failed because it threw an exception/error
    4.     java.util.concurrent.ExecutionException: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
    5.        at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:516)
    6.        at androidx.work.impl.utils.futures.AbstractFuture.get(AbstractFuture.java:475)
    7.        at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:284)
    8.        at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:75)
    9.        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
    10.        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
    11.        at java.lang.Thread.run(Thread.java:856)
    12.     Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
    13.         at android.os.Handler.<init>(Handler.java:121)
    14.         at android.app.Activity.<init>(Activity.java:749)
    15.         at androidx.core.app.ComponentActivity.<init>(ComponentActivity.java:39)
    16.         at androidx.activity.ComponentActivity.<init>(ComponentActivity.java:84)
    17.         at androidx.fragment.app.FragmentActivity.<init>(FragmentActivity.java:127)
    18.         at androidx.appcompat.app.AppCompatActivity.<init>(AppCompatActivity.java:77)
    19.         at com.example.app1.MainActivity.<init>(MainActivity.java:19)
    20.         at com.example.app1.UploadWorker.doWork(UploadWorker.java:20)
    21.         at androidx.work.Worker$1.run(Worker.java:85)
    22.         at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
    23.         at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
    24.         at java.lang.Thread.run(Thread.java:856)
    Code (Java):
    1. package com.example.app1;
    3. import android.content.Context;
    4. import android.util.Log;
    6. import androidx.annotation.NonNull;
    7. import androidx.work.Data;
    8. import androidx.work.Worker;
    9. import androidx.work.WorkerParameters;
    11. public class UploadWorker extends Worker {
    13.     public UploadWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
    14.         super(context, workerParams);
    15.     }
    17.     @NonNull
    18.     @Override
    19.     public Result doWork() {
    20.         String key = new MainActivity().KEY_NAME;
    21.         Data ret = new Data.Builder().putLong(key, System.currentTimeMillis()).build();
    22.         Log.e("APP", "doWork");
    23.         return Result.success(ret);
    24.     }
    25. }
    Code (Java):
    1. package com.example.app1;
    3. import androidx.appcompat.app.AppCompatActivity;
    4. import androidx.lifecycle.LiveData;
    5. import androidx.lifecycle.Observer;
    6. import androidx.work.BackoffPolicy;
    7. import androidx.work.Constraints;
    8. import androidx.work.Data;
    9. import androidx.work.OneTimeWorkRequest;
    10. import androidx.work.WorkInfo;
    11. import androidx.work.WorkManager;
    13. import android.os.Bundle;
    14. import android.util.Log;
    16. import java.util.List;
    17. import java.util.concurrent.TimeUnit;
    19. public class MainActivity extends AppCompatActivity {
    21.     public final String KEY_NAME = "string1";
    23.     @Override
    24.     protected void onCreate(Bundle savedInstanceState) {
    25.         super.onCreate(savedInstanceState);
    26.         setContentView(R.layout.activity_main);
    28.         Log.e("START", "Start");
    30.         Constraints constraints = new Constraints.Builder().setRequiresCharging(true).build();
    31.         Data data = new Data.Builder().putString(KEY_NAME, "Mike").build();
    32.         OneTimeWorkRequest uploadWordRequest = new OneTimeWorkRequest.Builder(UploadWorker.class)
    33.                 .setConstraints(constraints)
    34.                 .setInitialDelay(10, TimeUnit.SECONDS)
    35.                 .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 5, TimeUnit.SECONDS)
    36.                 .setInputData(data)
    37.                 .addTag("tag")
    38.                 .build();
    39.         WorkManager w = WorkManager.getInstance(getApplicationContext());
    40.         w.enqueue(uploadWordRequest);
    41.         LiveData<List<WorkInfo>> l = w.getWorkInfosByTagLiveData("tag");
    42.         l.observe(this, new Observer<List<WorkInfo>>() {
    43.             @Override
    44.             public void onChanged(List<WorkInfo> workInfos) {
    45.                 if(workInfos.get(0).getState() == WorkInfo.State.RUNNING)
    46.                     Log.e("APP", "RUNNING");
    47.                 Log.e("APP", "onChanged");
    48.             }
    49.         });
    50.     }
    51. }
    I am writing on android 4.1.1 and it seems this error applies to my code, but I did not understand how to fix it. I will be glad to any help

  2. Best Answer:
    Post #2 by RLScott, Aug 2, 2019 (1 points)
  3. RLScott

    RLScott Newbie

    The first thing you should do is re-evaluate why you are trying to use a handler in a thread other than the UI thread (which as a system-supplied looper).

    Handlers only work by virtue of loopers. Almost everybody who uses handlers uses them in the UI thread because the UI thread runs under a looper. A looper is like a dispatcher that dispatches events to handlers in your code. These events can be anything from button presses to timers expiring. The UI code is built upon the idea that it is supposed to respond to events and then quickly return to the system (which is a looper).

    A worker thread, on the other hand, is generally something that you start up to do something on its own without any interaction with the user. There are special mechanisms provided by Android to allow a worker thread to signal to the UI how it is going and when it is done. But basically the thread just runs straight line code, being interrupted only by Android OS time sharing and by calling blocking system methods (functions that must wait for something to happen before they can return.) It is never a good idea to have a thread sit "spinning its wheels" so to speak.

    So if you really want to use a handler in your worker thread (as distinct from the User Interface thread on which the rest of your app runs) you have to become very familiar with loopers and how they are used. But I suspect you don't really want to create a handler. If you want to communicate with the UI thread, then use one of the recommended methods of doing that.
  4. mcpixel

    mcpixel Newbie
    Thread Starter

    I figured out this question by removing from the code the creation of a new MainActivity class to access the variable inside it. That was my biggest mistake.

Share This Page