Issue
I've a SignUp activity which is supposed to check if a particular node exists in the Firebase realtime Database. If it does then notify the user else proceed with the sign up process. I'm using an AsyncTask to do that check but the problem is that when AsyncTask returns the value , my main thread has already been executed the rest. I'm using AsyncTask.execute().get() to fetch value which is supposed to pause the main thread but it is not working.
SignUp Activity
int userRegistered;
firebaseDatabase = FirebaseDatabase.getInstance();
databaseReference = firebaseDatabase.getReference("students");
ProgressDialog progressDialog =
ProgressDialog.show(context_signup,"Registering","Wait");
Log.d("signup","DB_CHECKER_STARTING");
try{
DatabaseCheckTask databaseCheckTask = new DatabaseCheckTask();
userRegistered = databaseCheckTask.execute(roll_no).get();
}
catch (InterruptedException | ExecutionException e){
userRegistered = 0;
}
switch (userRegistered){
case 1:
Log.d("signup","SIGNUP");
SignUpTask signUpTask = new SignUpTask();
signUpTask.execute(first_name,last_name,roll_no,phone_no,serial);
sharedPreferences.edit().putBoolean(Constants.FIRST_RUN,false).apply();
break;
case 2:
Log.d("signup","NOSIGNUP");
Toast.makeText(context_signup,"Student with this Roll number is
registered already..",Toast.LENGTH_LONG).show();
break;
case 3:
Log.d("signup","DATABASE_ERROR");
Toast.makeText(context_signup,"Error connecting to database! Please try again after some time.",Toast.LENGTH_LONG).show();
break;
default:
Log.d("signup","DEFAULT_CASE");
Toast.makeText(context_signup,"Slow",Toast.LENGTH_LONG).show();
}
Log.d("signup","DISMISS");
progressDialog.dismiss();
DatabaseCheckTask
public class DatabaseCheckTask extends AsyncTask<String,Integer,Integer>{
int isRegistered;
@Override
protected Integer doInBackground(String... strings) {
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("students");
databaseReference.child(strings[0]).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
Log.d("db_checker","ROLL_MATCHED");
isRegistered = 2;
}
else {
Log.d("db_checker","ROLL_NOT_MATCHED");
isRegistered = 1;
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
Log.d("checker","database error");
isRegistered = 3;
}
});
return isRegistered;
}
}
Debug Log
D/signup: DB_CHECKER_STARTING
D/signup: DEFAULT_CASE
D/signup: DISMISS
D/NetworkSecurityConfig: No Network Security Config specified, using platform
default
V/FA: Recording user engagement, ms: 5473
V/FA: Connecting to remote service
V/FA: Activity paused, time: 785707071
D/FA: Logging event (FE): user_engagement(_e),
Bundle[{firebase_event_origin(_o)=auto, engagement_time_msec(_et)=5473,
firebase_screen_class(_sc)=SignUp,
firebase_screen_id(_si)=6624230925954519568}]
V/FA: Connection attempt already in progress
V/FA: onActivityCreated
I/art: Do full code cache collection, code=245KB, data=251KB
I/art: After code cache collection, code=221KB, data=188KB
D/FA: Connected to remote service
V/FA: Processing queued up service tasks: 2
V/FA: onActivityCreated
D/FA: Logging event (FE): screen_view(_vs),
Bundle[{firebase_event_origin(_o)=auto, firebase_previous_class(_pc)=SignUp,
firebase_previous_id(_pi)=6624230925954519568,
firebase_screen_class(_sc)=SignUp,
firebase_screen_id(_si)=6624230925954519569}]
V/FA: Activity resumed, time: 785707379
D/OpenGLRenderer: endAllActiveAnimators on 0x9a56f880 (InsetDrawable) with handle 0x98617430
D/db_checker: ROLL_MATCHED
See in the Debug Log how ROLL_MATCHED is achieved after executing the default case while it was supposed to get achieved before even entering the switch case statement.
Solution
You have to move your code, as suggested in the other answers to the onPostExecute()
method, otherwise you can't know when to get the result because it is running on a separate thread.
So you can do something like the example below :
public class DatabaseCheckTask extends AsyncTask<String,Integer,Integer>{
int isRegistered;
/* use WeakReference to avoid leaks */
private WeakReference<ProgressBar> progressBarRef;
private WeakReference<Activity> activityRef;
public DatabaseCheckTask(ProgressBar progressBar, Activity activity){
this.progressBarRef = new WeakReference<>(progressBar);
this.activityRef = new WeakReference<>(activity);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
// get the progressBar
ProgressBar progressBar = progressBarRef.get();
// show the progressBar
progressBar.setVisibility(View.VISIBLE);
}
@Override
protected void onPostExecute(Integer userRegistered) {
super.onPostExecute(userRegistered);
Activity mActivity = activityRef.get();
switch (userRegistered){
case 1:
Log.d("signup","SIGNUP");
SignUpTask signUpTask = new SignUpTask();
/* Assuming you pass these variables to you asynctask.execute() and stock them
globally */
signUpTask.execute(first_name,last_name,roll_no,phone_no,serial);
/* you have a reference to the activity, so you can get sharedPrefereces doing
mActivity.getSharedPref.... */
sharedPreferences.edit().putBoolean(Constants.FIRST_RUN,false).apply();
break;
case 2:
Log.d("signup","NOSIGNUP");
Toast.makeText(mActivity,"Student with this Roll number is
registered already..",Toast.LENGTH_LONG).show();
break;
case 3:
Log.d("signup","DATABASE_ERROR");
Toast.makeText(mActivity,"Error connecting to database! Please try again
after some time.",Toast.LENGTH_LONG).show();
break;
default:
Log.d("signup","DEFAULT_CASE");
Toast.makeText(mActivity,"Slow",Toast.LENGTH_LONG).show();
}
ProgressBar progressBar = progressBarRef.get();
progressBar.setVisibility(View.INVISIBLE);
}
You have to use WeakReference to avoid leaks and then you can controle your ProgressBar visibility (the progressBar ref), showing Toasts and getting SharedPreferences (The activity ref).
I replaced the ProgressDialog
by ProgressBar
because it is deprecated in API level 26
And finally, you can use your AsyncTask like below:
DatabaseCheckTask task = new DatabaseCheckTask(progressBar, MainActivity.this);
task.execute(/* Your variables);
UPDATE :
But the problem here, in your AsyncTask doInBackground()
, you are just adding listener, wich is running on separate thread too, that is the reason why even if you add your code in onPostExecute(), it is not working (the event is not fired yet).
A solution is to move each "case" statement code to the adequate placement in your listener. (You do not need AsyncTask). Just create a function that takes roll_no
as parameter and that add the listener
Answered By - E.Abdel
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.