我有一个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。
答案 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
作为参数并添加侦听器的函数