Issue
Is there any way to use AsyncTask.execute()
multiple times?
Im using AsyncTask
to check, if User
exist in my Room Database.
My Login.class
looks like this:
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;
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){ }
}
I Read, that we can reset AsyncTask
by making new AsyncTask
(Task = new Login()
) StackOverflow Thread but it dont work for me. When i try to make something like this in my Login
class:
private void selfRestart(){
Login task = new Login(context, listener);
task.execute("");
//im calling it in onPostExecute()
}
My android app crashes. My question is, what is the best way to reset AsyncTask
that is implemented in diffrent file then my Activity
class? Or maybe there is better way to make Login
activity than implemented whole logic for login in AsyncTask
?
EDIT:
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)
Solution
You say,
I call
Task
in this way (myActivity.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){ } }
, but no, you are not "calling" your task that way. You are creating a single instance of the task, and setting up an event handler that executes that task -- that specific instance -- whenever the loginButton
is clicked. Since each AsyncTask
instance may be executed only once, that will fail the second time the login button is clicked (if not sooner, for some other reason).
You also say,
I Read, that we can reset AsyncTask by making new
AsyncTask
(Task = new Login()
)
, but no, that does not reset anything, and indeed AsyncTask
objects cannot be reset. The advice you read was to replace the used AsyncTask
with a fresh instance. Instantiating a new AsyncTask
has no particular effect on others. If you want to pursue that approach then it might look something like this:
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){ }
}
That specific implementation requires login
to be non-final
, so probably an instance variable of the containing class, not a local variable of the method from which your code was excerpted.
HOWEVER, your best way forward might very well be to ditch AsyncTask
altogether. When you use it like this:
login.execute(email, password).get();
... you defeat the entire purpose. You are making the thread in which that runs block until the task completes (that's what AsyncTask::get
is for), so the task is effectively synchronous. If that's what you require then you should just do the wanted work more directly instead of wrapping it up in an AsyncTask
.
Answered By - John Bollinger
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.