1

I'm having a huge problem for days. In fact, in my activity, I call an NTP server which I do using an async-task and I do multiple database operations(I'm using Firebase Database), and whenever this activity opens, there's an ANR error. I read that for long tasks, we should use a worker thread so I put the database operations in a thread but even with that, I still get an ANR error. What else do you suggest ? (the NTP server returns the correct result and all the operations in database are done everytime, even though I get the ANR error.)

public class Start extends AppCompatActivity {
//declaring variables
@Override
protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_start);


    new Thread(new Runnable() {
        public void run(){
            finishQuiz();
        }
    }).start();

    final DatabaseReference myRef = FirebaseDatabase.getInstance().getReference();

    myRef.addValueEventListener(new ValueEventListener() {
        //in this part, I call getNetworkTime, and under specific conditions I set an intent AlarmManager

    }

Here is the function finishQuiz() I call inside the thread :

 public void finishQuiz() {

    // DEFINING THE VARIABLES NEEDED

    myRef.addListenerForSingleValueEvent( new ValueEventListener() {
        String dateD, hourD, userID, nom, prenom;
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            Date d = new Date();
            timee = d.getTime();
            try {
                timee = new Start.getNetworkTime().execute().get();
            } catch (Exception e) {
                timee = d.getTime();
            }


            String dateD = dataSnapshot.child("quiz").child("dateD").getValue(String.class);
            String hourD = dataSnapshot.child("quiz").child("heureD").getValue(String.class);
            if (!(dateD.equals("")) && !(hourD.equals(""))) {

                long nbQ = dataSnapshot.child("quiz").child("questions").getChildrenCount();
                int dureeQ = Integer.valueOf(dataSnapshot.child("quiz").child("duree").getValue().toString());
                String[] D = dateD.split("-", 3);
                String[] H = hourD.split(":", 3);
                Calendar calDebut = Calendar.getInstance();
                calDebut.set(Integer.valueOf(D[2]), Integer.valueOf(D[1]) - 1, Integer.valueOf(D[0]), Integer.valueOf(H[0]), Integer.valueOf(H[1]), Integer.valueOf(H[2]));
                Date dateDebutQ = calDebut.getTime();
                long timeQFinInMillis = dateDebutQ.getTime() + (nbQ + 1) * dureeQ * 1000;

                if (timee > timeQFinInMillis) {



                    try {
                        final SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm");
                        Calendar caldateQ = Calendar.getInstance();
                        String[] dateDT = dateD.split("-", 3);
                        String[] hourDT = hourD.split(":", 3);
                        caldateQ.set(Integer.valueOf(dateDT[2]), Integer.valueOf(dateDT[1]) - 1, Integer.valueOf(dateDT[0]), Integer.valueOf(hourDT[0]), Integer.valueOf(hourDT[1]), Integer.valueOf(hourDT[2]));
                        long c = caldateQ.getTimeInMillis();
                        List<Date> listPast = new ArrayList<>();
                        List<Date> listFuture = new ArrayList<>();
                        for (DataSnapshot ds : dataSnapshot.child("next quizs").getChildren()) {
                            String dateNext = ds.getKey();
                            try {

                                Date dateNx = formatter.parse(dateNext);
                                Date dateQQQ = caldateQ.getTime();
                                Date dateQQ = formatter.parse(formatter.format(dateQQQ));
                                long timeNx = dateNx.getTime();
                                if (timeNx < timee) {
                                    listPast.add(dateNx);

                                }
                                else
                                {
                                    listFuture.add(dateNx);
                                }
                            } catch (Exception e) {

                            }
                        }

                        for (int i = 0; i < listPast.size(); i++) {
                            myNextQuiz.child(formatter.format(listPast.get(i))).removeValue();
                        }

                        if (listFuture.size()==0) {
                            myQuiz.child("dateD").setValue("");
                            myQuiz.child("heureD").setValue("");
                            myQuiz.child("duree").setValue(10);
                            myQuiz.child("questions").setValue("This will be removed anyways");
                        } else 
//I get ANR error in this case
{



                                Date minuD = listFuture.get(0);
                                for (int k = 1; k < listFuture.size(); k++) {
                                    if ((listFuture.get(k).compareTo(minuD) < 0)) {
                                        minuD = listFuture.get(k);
                                    }
                                }
                                    String date = formatter.format(minuD);
                                    String[] DH = date.split(" ", 2);
                                    myQuiz.child("dateD").setValue(DH[0]);
                                    myQuiz.child("heureD").setValue(DH[1] + ":00");
                                    String ddd = dataSnapshot.child("next quizs").child(date).child("duree").getValue().toString();
                                    myQuiz.child("duree").setValue(ddd);
                                    myQuiz.child("questions").removeValue();
                                    int j = 1;
                                   for (DataSnapshot ds : dataSnapshot.child("next quizs").child(date).child("questions").getChildren()) {
                                       String quest = ds.child("question").getValue(String.class);
                                       String sol = ds.child("sol").getValue(String.class);
                                       String answA = ds.child("A").getValue(String.class);
                                       String answB = ds.child("B").getValue(String.class);
                                       String answC = ds.child("C").getValue(String.class);
                                       String answD = ds.child("D").getValue(String.class);
                                       myQuiz.child("questions").child("" + j).child("question").setValue(quest);
                                       myQuiz.child("questions").child("" + j).child("sol").setValue(sol);
                                       myQuiz.child("questions").child("" + j).child("A").setValue(answA);
                                       myQuiz.child("questions").child("" + j).child("B").setValue(answB);
                                       myQuiz.child("questions").child("" + j).child("C").setValue(answC);
                                       myQuiz.child("questions").child("" + j).child("D").setValue(answD);
                                       j++;
                                   }
                            }

                        myPreQuiz.child(dateD + " " + hourD).child("dateD").setValue(dateD);
                        myPreQuiz.child(dateD + " " + hourD).child("heureD").setValue(hourD);
                        for (DataSnapshot ds : dataSnapshot.child("current quiz").child("number").getChildren()) {
                            userID = ds.getKey();
                            nom = dataSnapshot.child("utilisateurs").child(userID).child("Nom").getValue(String.class);
                            prenom = dataSnapshot.child("utilisateurs").child(userID).child("Prenom").getValue(String.class);
                            myPreQuiz.child(dateD + " " + hourD).child("gagnants").child(userID).setValue(nom + " " + prenom);
                        }
                        myCurrQuiz.child("currentQ").setValue("0");
                        myCurrQuiz.child("number").removeValue();

                    } catch (Exception e) {
                       //show Exception

                  } }}}

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {

        }
    });}

And here's my async Task :

private class getNetworkTime extends AsyncTask<Void, Void, Long> {

    @Override
    protected Long doInBackground(Void... params) {
        String TIME_SERVER = "2.android.pool.ntp.org";
        try{
        NTPUDPClient timeClient = new NTPUDPClient();
        InetAddress inetAddress = InetAddress.getByName(TIME_SERVER);
        TimeInfo timeInfo = timeClient.getTime(inetAddress);
        long returnTime = timeInfo.getMessage().getTransmitTimeStamp().getTime();   //server time

        return returnTime;
    } catch (Exception e) {
        Date d = new Date();
        long l=d.getTime();
        return l;
    }
    }


    protected void onPostExecute(Long result) {

    }

    @Override
    protected void onPreExecute() {

    }

    @Override
    protected void onProgressUpdate(Void... values) {
    }
}

If it is helpful, before I use the NTP server, my code used to work perfectly, and I tested without the AlarmManager part and it worked fine too, and also, in the function finishQuiz(), as I mentioned in a comment, only that particular case gives the ANR error(which happens to be the most common case for my app), I mean without entering that block, there's no ANR error.

user97
  • 11
  • 3
  • 1
    "I did not include any code because it's too long" It would be helpful for you to identify if there is a subset of your code that might make for a minimal, complete, and verifiable example (possibly replacing database ops with simpler queries or even no-op sleeps if you can still reproduce the problem with them). Without it, we can only guess as to what is going on, and what possible deficiencies may exist in your code. – nanofarad Apr 13 '19 at 01:16
  • I edited my answer, I hope this can help – user97 Apr 13 '19 at 02:10
  • maybe you could use thread pool: http://blogs.innovationm.com/multiple-asynctask-in-android/ – Alexandre Apr 13 '19 at 02:30

1 Answers1

0

Even though you start executing your finishQuiz method on a background thread, the firebase callbacks are called back on the main (UI) thread. This is likely causing your ANR.

Try executing the code in the onDataChange() callback on a background thread.

new Thread(new Runnable() {
    public void run(){

          // PUT YOUR CODE FROM onDataChange() HERE, or use AsyncTask


    }
}).start();

See this: Firebase Android: onDataChange() event always executed in Main UI Thread?

AzraelPwnz
  • 506
  • 2
  • 12