javaandroidclicklistener

Why does my clickListener make my app crash only the second time i call it


i got a small problem while coding a simple android app. On my main activity there's a button and the callback associated with it get a json file of users in an AsynchTask. After getting the file, I display the name of one of them in a textView. For the moment everything. Then I rotate my device(the trouble remains even if I don't rotate it) and click again on that button. The app crashes and I don't have any idea why could you help me please ?

here's the crash log :

2019-12-16 08:47:45.258 16758-16863/com.example.labo4bis E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
    Process: com.example.labo4bis, PID: 16758
    java.lang.RuntimeException: An error occurred while executing doInBackground()
        at android.os.AsyncTask$4.done(AsyncTask.java:399)
        at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
        at java.util.concurrent.FutureTask.run(FutureTask.java:271)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:919)
     Caused by: java.lang.RuntimeException: Only one Looper may be created per thread
        at android.os.Looper.prepare(Looper.java:108)
        at android.os.Looper.prepare(Looper.java:103)
        at com.example.labo4bis.MainActivity$LoadUsersTask.doInBackground(MainActivity.java:80)
        at com.example.labo4bis.MainActivity$LoadUsersTask.doInBackground(MainActivity.java:71)
        at android.os.AsyncTask$3.call(AsyncTask.java:378)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
        at java.lang.Thread.run(Thread.java:919) 

here's my code : main activity :

public class MainActivity extends AppCompatActivity {
    private UserDAO dao = new UserDAO();
    private LoadUsersTask task;
    @BindView(R.id.button2)
    Button actionButton;
    @BindView(R.id.hello)
    TextView t;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        Log.i("lab4","create");


        actionButton.setOnClickListener(new Button.OnClickListener(){
            @Override
            public void onClick(View v) {
                task = new LoadUsersTask();
                task.execute();
            }
        });

        if(savedInstanceState != null) {
            t.setText(savedInstanceState.getString("name"));
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("name",t.getText().toString());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i("lab4","destroy");
        if(task != null) {
            task.cancel(true);
        }
    }

   private class LoadUsersTask extends AsyncTask<Void,Void,List<User>> {
        @Override
        protected void onPostExecute(List<User> users) {
            super.onPostExecute(users);
            t.setText(users.get(0).getName());
        }

        @Override
        protected List<User> doInBackground(Void... voids) {
            Looper.prepare();
            return dao.getAllUsers();
        }

       @Override
       protected void onCancelled() {
           super.onCancelled();
           Log.i("lab4","asynchdestroy");
       }
   }
}

class DAO :

public class UserDAO {
    public UserDAO() {
    }

    public List<User> getAllUsers() {
        UserService service = new Retrofit.Builder()
                .baseUrl(UserService.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build().create(UserService.class);

        List<User> repoList = null;
        try {
            repoList = service.getUsers().execute().body();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return repoList;
    }
}

Solution

  • This line inside your doInBackground() method is the culprit:

    Looper.prepare();
    
    Caused by: java.lang.RuntimeException: Only one Looper may be created per thread
        at android.os.Looper.prepare(Looper.java:108)
        at android.os.Looper.prepare(Looper.java:103)
        at com.example.labo4bis.MainActivity$LoadUsersTask.doInBackground(MainActivity.java:80)
    

    Why are you calling this? I don't see anything related to Handlers in your code. If you can just delete it, then do so.

    If you need to keep it for a reason that we just can't see, then you should check to see whether the looper is already prepared:

    if (Looper.myLooper() == null) {
        Looper.prepare();
    }