-1

I want to set some code on a timer, but when I use a Timer I get an android.view.ViewRootImpl$CalledFromWrongThreadException. So I was wondering if there's any other way to code this so I don't get an error? I've looked into using some other timers that repeat code, but they all seem to use a public void in them and would assumedly do the same thing.

TimerTask task = new TimerTask() {
        @Override
        public void run() {
            rvMessagesSubjectGroupPage.setLayoutManager(new LinearLayoutManager(SubjectGroupPage.this, RecyclerView.VERTICAL, true));
            final ArrayList<MessageObj> messages = new ArrayList<>();
            ArrayList<MessageObj> messagesAdap = readMessages(rvMessagesSubjectGroupPage, messages);
            mMessageAdapter = new MessageListAdapter(SubjectGroupPage.this, messagesAdap);
            rvMessagesSubjectGroupPage.setAdapter(mMessageAdapter);
            rvMessagesSubjectGroupPage.scrollToPosition(5);
        }
    };
    Timer timer = new Timer();
    long delay = 0;
    long intevalPeriod = 1000;
    timer.scheduleAtFixedRate(task, delay, intevalPeriod);
}

public ArrayList<MessageObj> readMessages(final RecyclerView rv, final ArrayList<MessageObj> messages) {
    db.collection("messagesIT")
            .orderBy("Timesent", Query.Direction.DESCENDING)
            .get()
            .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                @Override
                public void onComplete(@NonNull Task<QuerySnapshot> task){
                    if (task.isSuccessful()) {
                        for (QueryDocumentSnapshot document : task.getResult()) {
                            String message = document.getString("Message");
                            String senderName = document.getString("SenderName");
                            String sender = document.getString("Sender");
                            Timestamp ts = document.getTimestamp("Timesent");
                            Date timesent = ts.toDate();
                            MessageObj mess;

                            sharedpreferences = getSharedPreferences(MyPREFERENCES, Context.MODE_PRIVATE);
                            SharedPreferences.Editor editor = sharedpreferences.edit();

                            if (currentUser.getUid().equals(sender)) {
                                mess = new MessageObj(message, sender, senderName, timesent, true);
                                editor.putBoolean("isCurrentUser", true);
                                editor.commit();
                            } else {
                                mess = new MessageObj(message, sender, senderName, timesent, false);
                                editor.putBoolean("isCurrentUser", false);
                                editor.commit();
                            }
                            messages.add(mess);
                        }
                    } else {
                        Log.d(TAG, "Error getting documents: ", task.getException());
                    }
                }
            }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            showToast("There has been an error, please try again later.");
            Log.d(TAG, "Error: " + e);

        }
    });

    return messages;
}

Error:

E/AndroidRuntime: FATAL EXCEPTION: Timer-0
Process: oxley.it.collectivelearning, PID: 9784
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
    at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:8161)
    at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1391)
    at android.view.View.requestLayout(View.java:22384)
    at android.view.View.requestLayout(View.java:22384)
    at android.view.View.requestLayout(View.java:22384)
    at android.view.View.requestLayout(View.java:22384)
    at android.view.View.requestLayout(View.java:22384)
    at android.view.View.requestLayout(View.java:22384)
    at androidx.constraintlayout.widget.ConstraintLayout.requestLayout(ConstraintLayout.java:3172)
    at android.view.View.requestLayout(View.java:22384)
    at androidx.recyclerview.widget.RecyclerView.requestLayout(RecyclerView.java:4202)
    at android.view.ViewGroup.removeAllViews(ViewGroup.java:5577)
    at androidx.recyclerview.widget.RecyclerView$5.removeAllViews(RecyclerView.java:900)
    at androidx.recyclerview.widget.ChildHelper.removeAllViewsUnfiltered(ChildHelper.java:193)
    at androidx.recyclerview.widget.RecyclerView.setLayoutManager(RecyclerView.java:1334)
    at oxley.it.collectivelearning.SubjectGroupPage$6.run(SubjectGroupPage.java:138)
    at java.util.TimerThread.mainLoop(Timer.java:555)
    at java.util.TimerThread.run(Timer.java:505)
S.Wilko
  • 11
  • 6
  • 1
    Possible duplicate of [Android "Only the original thread that created a view hierarchy can touch its views."](https://stackoverflow.com/questions/5161951/android-only-the-original-thread-that-created-a-view-hierarchy-can-touch-its-vi) – a_local_nobody Aug 10 '19 at 08:53

1 Answers1

0

Any operation which is done in relation with the UI should be done in the UI thread. By default, it is the UI thread but the Timer runs in a background task.

So, inside the Timer thread, implement your code which modifies anything in the UI within this block

runOnUiThread(new Runnable() {

@Override
public void run() {

    // Stuff that updates the UI

}
});