Android AsyncTask未及时返回值

Android AsyncTask未及时返回值,android,firebase-realtime-database,android-asynctask,Android,Firebase Realtime Database,Android Asynctask,我有一个注册活动,它应该检查Firebase实时数据库中是否存在特定节点。如果有,则通知用户,否则继续注册过程。我正在使用AsyncTask进行检查,但问题是,当AsyncTask返回值时,我的主线程已经执行了剩余的部分。我正在使用AsyncTask.execute().get()获取值,该值应该暂停主线程,但它不起作用 注册活动 int userRegistered; firebaseDatabase = FirebaseDatabase.getInstance(); databaseRefe

我有一个注册活动,它应该检查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();
数据库检查任务

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

请参阅调试日志中的ROLL_MATCHED(滚动匹配)是如何在执行默认情况后实现的,而在输入switch case语句之前就应该实现它。

onPostExecute()
中移动
数据库检查任务中的开关块

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

DatabaseCheckTask

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

AsyncTask在不同于主线程的单独线程上执行其代码,因此主线程将继续执行其代码,而AsyncTask将在单独线程上运行其代码。您必须等待AysncTask的
doInBackground()
方法完成其执行,然后只进行注册或其他操作(取决于具体情况)。因此,您必须将代码转移到在主线程上运行的
onPostExecute()
。要了解有关AsyncTask及其方法的更多信息,请参阅。
注意:在AsyncTask完成其执行之前,不能暂停主线程,但可以等到AsyncTask生成其结果,请参阅。

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

您必须移动代码,正如对
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);

}
更新:

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


解决方案是将每个“case”语句代码移动到侦听器中的适当位置。(您不需要异步任务)。只需创建一个函数,该函数以
roll\u no
为参数,并添加侦听器您必须移动代码,正如对
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);

}
更新:

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


解决方案是将每个“case”语句代码移动到侦听器中的适当位置。(您不需要异步任务)。只需创建一个函数,该函数以
roll\u no
为参数,并添加侦听器异步任务,该任务将在与主线程不同的单独线程上执行该进程,因此主线程将继续执行其代码。因此,在主线程上运行的AsyncTask的onPostExecute()方法中从Firebase DB获取数据后,必须检查特定节点是否存在,有关AsyncTask的更多信息,请参见此链接:Async Task将在与主线程不同的单独线程上执行进程,因此主线程将继续执行其代码。因此,在主线程上运行的AsyncTask的onPostExecute()方法中从Firebase DB获取数据后,您必须检查特定节点是否存在。有关AsyncTask的更多信息,请参阅以下链接:是否存在此问题,仍然存在相同的问题。然而,为了检测问题,我在以前的代码中添加了一个额外的案例,发现检查节点是否存在的方法暂时没有返回值。请看一看。因为我不想编辑原始代码。谢谢!我不知道listener正在一个单独的线程上运行。这就解释了问题。这样做了,还是一样的问题。然而,为了检测问题,我在以前的代码中添加了一个额外的案例,发现检查节点是否存在的方法暂时没有返回值。请看一看。因为我不想编辑原始代码。谢谢!我不知道listener正在一个单独的线程上运行。这就解释了这个问题。