AsyncTask没有及时返回值

时间:2018-07-13 07:37:16

标签: android firebase-realtime-database android-asynctask

我有一个SignUp活动,该活动应该检查 Firebase实时数据库中是否存在特定的节点。如果确实如此,则通知用户,否则继续进行注册过程。我正在使用AsyncTask进行检查,但问题是当AsyncTask返回值时,其余部分已经执行了。我正在使用 AsyncTask.execute()。get()来获取应该暂停主线程但不起作用的值。

注册活动

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;
    }
}

调试日志

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

在调试日志中查看执行默认情况后如何实现ROLL_MATCHED,而应该在甚至输入switch case语句之前也要实现ROLL_MATCHED。

3 个答案:

答案 0 :(得分:1)

将切换块移动到onPostExecute()内的DatabaseCheckTask

@Override 
protected void onPostExecute(Integer integer)
 { 
super.onPostExecute(integer);
 //move your switch code here 
}

答案 1 :(得分:1)

AsyncTask在与主线程不同的单独线程上执行其代码,因此主线程将继续执行其代码,而AsyncTask将在单独的线程上运行其代码。您将不得不等到AysncTask的doInBackground()方法完成执行,然后才继续执行SignUp或其他操作(视情况而定)。因此,您必须将代码转移到运行在主线程上的onPostExecute()上。要了解有关AsyncTask及其方法的更多信息,请参见this注意:在AsyncTask完成执行之前,您不能暂停主线程,但可以等到AsyncTask生成其结果为止,请参见this

答案 2 :(得分:0)

您必须按照onPostExecute()方法的其他答案中的建议移动代码,否则,由于它在单独的线程上运行,因此您不知道何时获得结果。 因此,您可以执行以下示例:

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);

}

您必须使用WeakReference来避免泄漏,然后可以控制ProgressBar的可见性(progressBar ref),显示Toasts并获取SharedPreferences(活动ref)。

我将ProgressDialog替换为ProgressBar,因为API level 26中已弃用了

最后,您可以使用如下所示的AsyncTask:

DatabaseCheckTask task = new DatabaseCheckTask(progressBar, MainActivity.this);
task.execute(/* Your variables);

更新:

但是这里的问题是,在您的AsyncTask doInBackground()中,您只是添加了侦听器,也正在单独的线程上运行,这就是即使将代码添加到onPostExecute()中的原因,它不起作用(该事件尚未触发)。

一种解决方案是将每个“ case”语句代码移到侦听器中的适当位置。 (您不需要AsyncTask)。只需创建一个以roll_no作为参数并添加侦听器的函数