Android AsyncTask未及时返回值
我有一个注册活动,它应该检查Firebase实时数据库中是否存在特定节点。如果有,则通知用户,否则继续注册过程。我正在使用AsyncTask进行检查,但问题是,当AsyncTask返回值时,我的主线程已经执行了剩余的部分。我正在使用AsyncTask.execute().get()获取值,该值应该暂停主线程,但它不起作用 注册活动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
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);
}
更新:
但是这里的问题是,在AsyncTaskdoInBackground()
中,您只是添加了侦听器,它也在单独的线程上运行,这就是为什么即使您在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);
}
更新:
但是这里的问题是,在AsyncTaskdoInBackground()
中,您只是添加了侦听器,它也在单独的线程上运行,这就是为什么即使您在onPostExecute()中添加代码,它也不起作用(事件尚未触发)。
解决方案是将每个“case”语句代码移动到侦听器中的适当位置。(您不需要异步任务)。只需创建一个函数,该函数以
roll\u no
为参数,并添加侦听器异步任务,该任务将在与主线程不同的单独线程上执行该进程,因此主线程将继续执行其代码。因此,在主线程上运行的AsyncTask的onPostExecute()方法中从Firebase DB获取数据后,必须检查特定节点是否存在,有关AsyncTask的更多信息,请参见此链接:Async Task将在与主线程不同的单独线程上执行进程,因此主线程将继续执行其代码。因此,在主线程上运行的AsyncTask的onPostExecute()方法中从Firebase DB获取数据后,您必须检查特定节点是否存在。有关AsyncTask的更多信息,请参阅以下链接:是否存在此问题,仍然存在相同的问题。然而,为了检测问题,我在以前的代码中添加了一个额外的案例,发现检查节点是否存在的方法暂时没有返回值。请看一看。因为我不想编辑原始代码。谢谢!我不知道listener正在一个单独的线程上运行。这就解释了问题。这样做了,还是一样的问题。然而,为了检测问题,我在以前的代码中添加了一个额外的案例,发现检查节点是否存在的方法暂时没有返回值。请看一看。因为我不想编辑原始代码。谢谢!我不知道listener正在一个单独的线程上运行。这就解释了这个问题。