将 AsyncTask 重置为多次执行

Reset AsyncTask to multiple execution

有什么方法可以多次使用AsyncTask.execute()吗?

我正在使用 AsyncTask 检查我的房间数据库中是否存在 User

我的Login.class看起来像这样:

public class Login extends AsyncTask<String, Boolean, Boolean> {

public Login(Context context, LoginListener listener){
    db = ApplicationDatabase.getDatabase(context); //i get Room here
    this.context = context; //context of app
    this.listener = listener; //my interfece for observe Boolean, works ok
}

@Override
protected Boolean doInBackground(String... body){
    try {
        user = db.userDao().getUser(body[0], body[1]);
        if (user != null)
            return Boolean.TRUE; //we find user with credentials
        else {
            return Boolean.FALSE; //we not find user with that credentials (from body)
        }
    }
    catch(Exception e){
        return null;
    }
}

protected void onPostExecute(Boolean result) {
    listener.onLoginPerformed(result); //Boolen to activity
    selfRestart(); //i want to restart task here
}

private void selfRestart(){
    //maybe something to do here? its my own method
}

private ApplicationDatabase db;
private User user;
private LoginListener listener;
private Context context;

我是这样调用Task的(我的Activity.class):

login = new Login(getApplicationContext(), this); 
//this is an interface that i implements in Activity definition

loginButton.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v){
            //execute() here, i cuted some not necesery code from here
            try {
                // im using get because i want to get valu from AsyncTask
                login.execute(email, password).get();
            }
            catch(Exception e){ }
}

我读到,我们可以通过创建新的 AsyncTask (Task = new Login()) Whosebug Thread 来重置 AsyncTask,但它对我不起作用。当我尝试在 Login class:

中做这样的事情时
private void selfRestart(){
    Login task = new Login(context, listener);
    task.execute("");
    //im calling it in onPostExecute()
}

我的 android 应用崩溃了。我的问题是,重置在不同文件中实现的 AsyncTask 和我的 Activity class 的最佳方法是什么?或者也许有更好的方法使 Login activity 比在 AsyncTask?

中实现整个登录逻辑更好

编辑:

Logcat:

2019-01-24 15:45:31.407 1048-1048/com.example.admin.keystroke_dynamics E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.admin.keystroke_dynamics, PID: 1048
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Boolean.booleanValue()' on a null object reference
    at com.example.admin.keystroke_dynamics.Activities.LoginActivity.onLoginPerformed(LoginActivity.java:62)
    at com.example.admin.keystroke_dynamics.Login.onPostExecute(Login.java:38)
    at com.example.admin.keystroke_dynamics.Login.onPostExecute(Login.java:14)
    at android.os.AsyncTask.finish(AsyncTask.java:692)
    at android.os.AsyncTask.-wrap1(AsyncTask.java)
    at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:709)
    at android.os.Handler.dispatchMessage(Handler.java:105)
    at android.os.Looper.loop(Looper.java:156)
    at android.app.ActivityThread.main(ActivityThread.java:6523)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)

你说,

I call Task in this way (my Activity.class):

login = new Login(getApplicationContext(), this); 
//this is an interface that i implements in Activity definition

loginButton.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v){
            //execute() here, i cuted some not necesery code from here
            try {
                // im using get because i want to get valu from AsyncTask
                login.execute(email, password).get();
            }
            catch(Exception e){ }
}

,但是不,你 不是 "calling" 你的任务。您正在创建任务的单个实例,并设置一个事件处理程序来执行该任务——那个特定的实例——只要 loginButton 被单击。由于每个 AsyncTask 实例可能只执行一次,因此第二次单击登录按钮时将失败(如果不是更早,则出于其他原因)。

你也说,

I Read, that we can reset AsyncTask by making new AsyncTask (Task = new Login())

,但是 no,它不会重置任何东西,实际上 AsyncTask 对象无法重置。您阅读的建议是用新实例替换 用过的AsyncTask。实例化一个新的 AsyncTask 对其他人没有特别的影响。如果您想采用这种方法,那么它可能看起来像这样:

loginButton.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v){
            Login myLoginTask = login; // keep a reference to the current task
            login = new Login(... arguments ...); // create a new task for the next click

            try {
                // use the original task
                myLoginTask.execute(email, password).get();
            }
            catch(Exception e){ }
}

该特定实现要求 login 为非 final,因此可能是包含 class 的实例变量,而不是您的代码所在方法的局部变量摘录。

但是,您最好的前进方式很可能是完全放弃 AsyncTask。当你这样使用它时:

                login.execute(email, password).get();

...你破坏了整个目的。您正在使运行该线程的线程阻塞直到任务完成(这就是 AsyncTask::get 对于 的 ),因此该任务实际上是同步的。如果那是您的要求,那么您应该更直接地完成所需的工作,而不是将其包装在 AsyncTask.