I have a problem with my onPostExecute() method in AsyncTask class.
I have an SignupActivity:
public class SignupActivity extends AppCompatActivity implements SignupListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.signup_activity);
//new task, i pass context and interface to it
signup = new Signup(getApplicationContext(), this);
signupButon.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
if(validate()) {
try {
//new task every click
Signup newSignup = new Signup(signup);
//here start AsyncTask
newSignup.execute(name, email, password).get();
} catch (Exception e) {
Toast.makeText(ERROR);
}
// if sign up succes, == true;
if(signupValid) {
Toast.makeText(SUCCES);
finish();
} else {
Toast.makeText(ERROR);
}
}
}
});
}
// my own interface for getting result as bool from onPostExecute
#Override
public void onSignupPerformed(Boolean result){ this.signupValid = result; }
That implements my interface to catching result from onPostExecute():
public interface SignupListener{
void onSignupPerformed(Boolean result);
}
Now, AsyncTask that i trigger in code:
public class Signup extends AsyncTask<String, Boolean, Boolean> {
public Signup(Context context, SignupListener listener){
db = ApplicationDatabase.getDatabase(context);
this.context = context;
this.listener = listener;
}
public Signup(Signup signup){
//constructor to make new task based on first task
db = signup.db;
context = signup.context;
listener = signup.listener;
}
protected Boolean doInBackground(String... body){
try {
user = db.userDao().getUser(body[0], body[1], body[2]);
if (user == null) {
// user is null, so we can add new one to DB
db.userDao().insertUser(new User(body[0], body[1], body[2]));
return Boolean.TRUE; //signup go good, return true
} else {
return Boolean.FALSE; //signup go bad, return false
}
} catch(Exception e) { }
return null;
}
protected void onPostExecute(Boolean result) {
//catching result from doInBackground
listener.onSignupPerformed(result);
}
My question is, why when i first click on button, func return Boolean.TRUE but in SignupActivity signupValid variable is false (signup form not exit, but user is added to DB), but when i click signup button second time, ofc signup fail (because we make new user seconds ago) but signupValid change to true and Signup Form pass? I need to click SignupButton two times to finally exit form. Thanks for finding error in my code
EDIT:
I replaced .get() with Progress Dialog to block UI, but now i get Toast with not valid form even before AsyncTask for Signup do his job. And still, in first click signupValid is false even when from doInBackground() i get TRUE, on second click AsyncTask return FALSE but signupValid is changed to true
My UserDAO:
#Dao
public interface UserDao {
#Query("SELECT * FROM users WHERE email = :email AND password = :password AND username = :username")
User getUser(String username, String email, String password);
}
And ApplicationDatabase:
public abstract class ApplicationDatabase extends RoomDatabase {
public abstract UserDao userDao();
public static ApplicationDatabase getDatabase(final Context context){
if(INSTANCE == null){
synchronized (ApplicationDatabase.class){
if(INSTANCE == null){
INSTANCE = Room.databaseBuilder(context.getApplicationContext(), ApplicationDatabase.class, "database").build();
}
}
}
return INSTANCE;
}
private static volatile ApplicationDatabase INSTANCE;
If I understood the problem correctly - there is a race condition that makes the SignupActivity to fire the toast before the execution of Signup task is completed. Therefore:
signupButon.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
if(validate()) {
try {
//new task every click
Signup newSignup = new Signup(signup);
//here start AsyncTask
newSignup.execute(name, email, password).get();
} catch (Exception e) {
Toast.makeText(ERROR);
}
}
}
});
While these lines:
// if sign up succes, == true;
if(signupValid) {
Toast.makeText(SUCCES);
finish();
} else {
Toast.makeText(ERROR);
}
Should be a part of the listener (right now it seems that these lines are executed BEFORE the completion of your async task)
To clarify myself:
#Override
public void onSignupPerformed(Boolean result)
{
if(result) {
Toast.makeText(SUCCES);
finish();
} else {
Toast.makeText(ERROR);
}
}
Related
I'm really struggling with a simple issue that I'm hoping someone could assist in .
I have a basic application that authenticates to a database using a basic query.This query is run in the async doinbackground and returns a boolean named isSuccess.
It is then passed to a button onclick method that then determines if the user has entered the correct password. The boolean get reinitialized to true on the async method .
The problem I'm experiencing is that it seems like at the onclick stage it gets the initialised true boolean and not the changed variable value in the indobackground section.
issueing.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
String passwordd = password.getText().toString();
CheckLogin checkLogin = new CheckLogin();// this is the Asynctask, which is used to process in background to reduce load on app process
checkLogin.execute(passwordd,passwordd);
password.getText().clear();
if (checkLogin.isSuccess)
Toast.makeText(MainActivity.this, "Issue Login", Toast.LENGTH_SHORT).show();
}
});
}
public class CheckLogin extends AsyncTask<String, String, String>
{
String z = "";
boolean isSuccess = true;
#Override
protected void onPreExecute()
{
//progressBar.setVisibility(View.VISIBLE);
}
#Override
protected void onPostExecute(String r)
{
}
#Override
public String doInBackground(String... args)
{
String usernam = args[0];
String passwordd = args[1];
{
try
{
Class.forName("net.sourceforge.jtds.jdbc.Driver");
con = DriverManager.getConnection(db, un, pass); // Connect to database
if (con == null)
{
z = "Check Your Internet Access!";
}
else {
String query = " select * from employee where password = '"+ passwordd+"'" ;
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query);
String employee,pw;
if (rs.next()) {
employee= rs.getString("employee");
pw = rs.getString("password");
z = "Success";
//setSuccess(true);
isSuccess = true;
}
else if (!rs.next())
{
//setSuccess(false);
//setSuccess(false);
isSuccess = false;
z = "Invalid Password";
}
}
}
catch (Exception ex)
{
isSuccess = false;
//setSuccess(false);
z = ex.getMessage();
}
}
return null;
}
I'm suspecting that the onclick doesn't get the changed boolean value in time because of it running in the background.
This is simply because when you're using the following code:
CheckLogin checkLogin = new CheckLogin();
checkLogin.execute(passwordd,passwordd);
password.getText().clear();
if (checkLogin.isSuccess)
Toast.makeText(MainActivity.this, "Issue Login", Toast.LENGTH_SHORT).show();
}
you're thinking that the code is working in synchronous ways. CheckLogin is an AsyncTask which is working in a asynchronous way. So the CheckLogin code in the following code:
CheckLogin checkLogin = new CheckLogin();
checkLogin.execute(passwordd,passwordd);
will make a separate task and not blocking the process until it finished its job. So, Toast in your following code:
if (checkLogin.isSuccess)
Toast.makeText(MainActivity.this, "Issue Login", Toast.LENGTH_SHORT).show();
}
won't be executed because checkLogin.isSuccess is still false.
The simple fixed is by moving your check to onPostExecute of AsyncTask. Something like this:
#Override
protected void onPostExecute(String r) {
if (checkLogin.isSuccess) {
// do something with the success
}
}
The proper way is by using a listener as a callback mechanism to tell the activity that the process is finished. This will separate your Activity and AsyncTask process to make it more maintainable in the future.
You can use an AsyncTask and callback with something like this:
public class CheckLoginTask extends AsyncTask<Void, Void, Boolean> {
private String mUserName;
private String mPassword;
private ResultListener mListener;
private String mMessage;
public interface ResultListener {
void onSuccess(String message);
void onFailure(String message);
}
public CheckLoginTask(String userName, String password, ResultListener listener) {
mUserName = userName;
mPassword = password;
mListener = listener;
}
#Override protected Boolean doInBackground(Void... voids) {
boolean isSuccess = false;
// do some process with username and password
// assume there is a a message
mMessage = "Invalid password";
return isSuccess;
}
#Override protected void onPostExecute(Boolean isSuccess) {
if(isSuccess) {
mListener.onSuccess(mMessage);
} else {
mListener.onFailure(mMessage);
}
}
}
that it can be used like this:
CheckLoginTask.ResultListener listener = new CheckLoginTask.ResultListener {
#Override
public void onSuccess(String message) {
// do something when success
}
#Override
public void onFailure(String message) {
// do something with failure
}
};
CheckLoginTask checkLoginTask = new CheckLoginTask(userName, password, listener);
checkLoginTask.execute();
For what i understand from your question, you want to check for
a password and then pass the result to the activity or somewhere else.
I suggest implementing interfaces to make your code simpler and more effective.
since AsyncTasks run on a different thread, they have methods to contact with the main thread such as onPreExecute() and onPostExecute(String r) , so what you have to do is the following :
create an interface that would look like something like that :
public interface PasswordChecker {
void onChecked(Boolean isSuccess);
}
the second thing is to make your activity or class implement this interface, it would be this way :
public class MyActivity extends AppCompatActivity implements PasswordChecker {
#Override
public void onChecked(Boolean isSuccess) {
if (isSuccess) {
//Do Stuff with your isSuccess Boolean
}
}
}
or you can initialize a PasswordChecker object variable and pass it as an argument in the third step.
Make your AsyncTask require a PasswordChecker and then you must pass your activity or class, or object as an argument to the constructor, your AsyncTask would look like this :
public class CheckLogin extends AsyncTask<String,String,Boolean> {
private PasswordChecker checker;
CheckLogin(PasswordChecker checker) {
this.checker = checker;
}
#Override
protected Boolean doInBackground(String... strings) {
boolean isSuccess;
//Do Your Work..
//...
//...
//if (condition)
isSuccess = true;
return isSuccess;
}
#Override
protected void onPostExecute(Boolean isSuccess) {
super.onPostExecute(isSuccess);
checker.onChecked(isSuccess);
}
}
Finally, you must initialize your AsyncTask using a PasswordChecker object as an argument :
//Passing the activity it self (which implements PasswordChecker) as an argument
final CheckLogin checkLogin = new CheckLogin(MyActivity.this);
or
//Or by passing a custom object
PasswordChecker myChecker = new PasswordChecker() {
#Override
public void onChecked(Boolean isSuccess) {
if (isSuccess) {
Toast.makeText(MyActivity.this , "Login Success!" , Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(MyActivity.this , "Login Failed!" , Toast.LENGTH_LONG).show();
}
}
};
CheckLogin myCheckLogin = new CheckLogin(myChecker);
//Do the rest of the job
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Execute your task
checkLogin.execute("Username", "Password");
}
});
Conclusion : As you can see here, the result is passed through onPostExecute(String r), your interface will be fired ( by checker.onChecked(isSuccess); ) every time onPostExecute is called, passing the boolean as an argument, and executes the code inside it depending on its value.
The problem is doInBackground() works an a different thread then your onClick(). onClick() works on the UIThread. so you don't recieve any updates to that thread.
First change your Async task declaration to this:
public class CheckLogin extends AsyncTask<Void, Void, Boolean>
The third parameter is the result parameter that is returned by doinbackground.
so your doInBackground() and onPostExecute()will be something like this:
#Override
protected Boolean doInBackground(Void... params) {
if(some_condition) {
return true;
} else {
return false;
}
}
#Override
protected void onPostExecute(Boolean result) {
// use the result
super.onPostExecute(result);
isSuccess = result;
};
I am new to Realm (and Android development) and I would like to use a Singleton class to simplify Realm data management so it's easier for my friends to use in our group project.
EpicPandaForce have written a singleton class called RealmManager here, but I couldn't find an example in implementing it, so this is what I have tried:
public class RealmManager {
private static RealmManager instance;
private final ThreadLocal<Realm> localRealm = new ThreadLocal<>();
RealmManager(){}
public synchronized static RealmManager getInstance(){
if(instance == null){
instance = new RealmManager();
}
return instance;
}
public Realm openLocalInstance() {
Realm realm = Realm.getDefaultInstance();
if(localRealm.get() == null) {
localRealm.set(realm);
}
return realm;
}
public Realm getLocalInstance() {
Realm realm = localRealm.get();
if(realm == null) {
throw new IllegalStateException("No open Realms were found on this thread.");
}
return realm;
}
public void closeLocalInstance() {
Realm realm = localRealm.get();
if(realm == null) {
throw new IllegalStateException(
"Cannot close a Realm that is not open.");
}
realm.close();
if(Realm.getLocalInstanceCount(Realm.getDefaultConfiguration()) <= 0) {
localRealm.set(null);
}
}
public void storePreferenceDao(int userID, String rank){
final PreferenceDao preferenceDao = new PreferenceDao();
preferenceDao.setUserID(userID);
preferenceDao.setRank(rank);
openLocalInstance();
getLocalInstance().executeTransactionAsync(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.copyToRealmOrUpdate(preferenceDao);
}
}, new Realm.Transaction.OnSuccess(){
#Override
public void onSuccess(){
System.out.println("Data is stored successfully!");
}
}, new Realm.Transaction.OnError(){
#Override
public void onError(Throwable error){
System.out.println("There is an error in storePreferenceDao()");
}
});
closeLocalInstance();
}
So when my friends want to store some data, they can just use:
RealmManager.getInstance().storePreferenceDao(123, "Alpaca");
Is this how it is supposed to be used or is it redundant? How can I make it more efficient?
Actually in this case, that method can still be called only from UI thread, and the local instance should be closed in the transaction callback (otherwise the onSuccess/onError won't be called)
You could make a method that is able to execute on bg thread if able, and on current thread if already on a bg thread
// method in RealmManager
public final void runTransaction(Realm.Transaction transaction) {
runTransaction(transaction, null, null);
}
public final void runTransaction(Realm.Transaction transaction, Realm.Transaction.OnSuccess onSuccess) {
runTransaction(transaction, onSuccess, null);
}
public final void runTransaction(Realm.Transaction transaction, Realm.Transaction.OnSuccess onSuccess, Realm.Transaction.OnError onError) {
Realm realm = openLocalInstance();
if(realm.isAutoRefresh()) {
realm.executeTransactionAsync(transaction, new Realm.Transaction.OnSuccess() {
#Override
public void onSuccess() {
try {
if(onSuccess != null) {
onSuccess.onSuccess();
}
} finally {
closeLocalInstance();
}
}
}, new Realm.Transaction.OnError() {
#Override
public void onError(Throwable e) {
try {
if(onError != null) {
onError.onError(e);
}
} finally {
closeLocalInstance();
}
}
});
} else {
try {
realm.executeTransaction(transaction);
if(onSuccess != null) {
onSuccess.onSuccess();
}
} catch(Exception e) {
if(onError != null) {
onError.onError(e);
}
throw new RuntimeException(e);
} finally {
closeLocalInstance();
}
}
}
If you add this method, then you can now execute a transaction that will either be executed on background thread via async transaction method if possible, using synchronous transaction method if not on a looper thread (f.ex. background thread)
This way you can now do
public void storePreferenceDao(int userID, String rank) {
final PreferenceDao preferenceDao = new PreferenceDao();
preferenceDao.setUserID(userID);
preferenceDao.setRank(rank);
runTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.copyToRealmOrUpdate(preferenceDao);
}
}, new Realm.Transaction.OnSuccess(){
#Override
public void onSuccess(){
System.out.println("Data is stored successfully!");
}
}, new Realm.Transaction.OnError(){
#Override
public void onError(Throwable error){
System.out.println("There is an error in storePreferenceDao()");
}
});
}
Or just
public void storePreferenceDao(int userID, String rank) {
final PreferenceDao preferenceDao = new PreferenceDao();
preferenceDao.setUserID(userID);
preferenceDao.setRank(rank);
runInTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.copyToRealmOrUpdate(preferenceDao);
}
});
}
You know, I always felt I should add a runTransaction() method to that example. Whether it should default to using executeTransactionAsync by default if able or not is up for debate, though.
A simple Singleton example,
public class MySingleton {
private static MySingleton sMySingleton;
//private constructor.
private MySingleton() {
if (sMySingleton != null){
throw new RuntimeException("Use getInstance() for the instance");
}
}
public synchronized static MySingleton getInstance() {
if (sMySingleton == null){
sMySingleton = new MySingleton();
}
return sMySingleton;
}
}
Hope it helps!
This can be not the best answer but here how i am using realm in my applications
public class BaseActivity extends AppCompatActivity {
public Realm realm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base);
realm = Realm.getDefaultInstance();
}
}
Extend BaseActivity in other Activities according to your use
public class MainActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Here you can directly access realm object and perform your task
realm.where()//just example
}
#Override
protected void onDestroy() {
super.onDestroy();
if(realm!=null)
realm.close();
//Don't forget to close realm object
}
}
I am not saying this is the best way but it one the best way. using this way i can easily manage my realm class and can reduce errors related to realm.For fragments You can make BaseFragment and extend it in other fragments.
Hope this will help you...Let me know if you get any other better way for this
I got a problem with AsyncTask at Android Studio. What I am trying to do is before I create a new user, I am checking if the username and email exist in my database. Here is the part where I call the create AsyncTask:
new SignupAsyncTask(getBaseContext()).execute(userModel);
if(SignupAsyncTask.successCheck == false){
Toast.makeText(getBaseContext(), "Failed", Toast.LENGTH_SHORT).show();
} else if(SignupAsyncTask.successCheck == true){
Toast.makeText(getBaseContext(), "Success", Toast.LENGTH_SHORT).show();
}
Inside my AsyncTask, I am getting all user. Then I perform a loop to check if there is any matching username or password. If there is, I set the successCheck to false.
public class SignupAsyncTask extends AsyncTask<User, Integer, Boolean> {
ArrayList<User> list = new ArrayList<User>();
DB_User userCtrl = new DB_User();
Context context;
public static boolean successCheck = false;
public SignupAsyncTask(){}
public SignupAsyncTask(Context context){
this.context = context;
}
#Override
protected Boolean doInBackground(User... params) {
try {
list = userCtrl.getAllUser();
for(int i = 0; i < list.size(); i++){
User userObj = list.get(i);
if(params[0].getUserName().equals(userObj.getUserName())){
successCheck = false;
break;
}
else if (params[0].getEmail().equals(userObj.getEmail())){
successCheck = false;
break;
} else{
successCheck = true;
break;
}
}
} catch (JSONException e) {
e.printStackTrace();
}
if(successCheck == true){
userCtrl.SignupUser(params[0]);
}
return successCheck;
}
#Override
protected void onPostExecute(Double result){
}
#Override
protected void onProgressUpdate(Integer... progress) {
}
}
The problem that I have encountered now is for the first time when I am testing with a non-duplicate username and email, it can insert into database but somehow the toast printed out 'Failed'.
Then, when I try with another duplicate record, it does not insert into database as I set my username and email to be UNIQUE but the toast is printing out 'Success'.
It is operated in the opposite way as my code logic. Any ideas?
Thanks in advance
EDIT
public class SignupAsyncTask extends AsyncTask<User, Integer, Boolean> {
ArrayList<User> list = new ArrayList<User>();
DB_User userCtrl = new DB_User();
Context lcontext;
public static boolean successCheck = false;
public SignupAsyncTask(){}
public SignupAsyncTask(Context context){
lcontext = context;
}
#Override
protected Boolean doInBackground(User... params) {
try {
list = userCtrl.getAllUser();
for(int i = 0; i < list.size(); i++){
User userObj = list.get(i);
if(params[0].getUserName().equals(userObj.getUserName())){
successCheck = false;
break;
}
else if (params[0].getEmail().equals(userObj.getEmail())){
successCheck = false;
break;
} else{
successCheck = true;
break;
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return successCheck;
}
#Override
protected void onPostExecute(Boolean result){
if(successCheck)
{
//userCtrl.SignupUser(userobject);
Log.d("Check","Ran Success");
Toast.makeText(lcontext, "Success", Toast.LENGTH_SHORT).show();
}
else {
Log.d("Check","Ran Fail");
Toast.makeText(lcontext, "Failed", Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onProgressUpdate(Integer... progress) {
}
It's because of AsyncTask, as its name, is an asynchronous task. You need to test the result in your SignupAsyncTask class.
Add the logic to your AsyncTask onPostExecute():
#Override
protected void onPostExecute(Boolean result){
if(result == false){
// Process if false
} else if(result == true){
// Process if true
}
}
Because you can't access UI thread from SignupAsyncTask (where your class is not a member class of your caller class), you need to define an interface as listener mechanism in your caller class to receive the result from your AsyncTask. So whenever there is a change in data, it will inform the caller who implements the interface.
Something like:
public interface OnSuccessCheckReceived{
void onSuccessCheckReceived(boolean isSuccess);
}
Then you add the callback interface to SignupAsyncTask:
public class SignupAsyncTask extends AsyncTask<User, Integer, Boolean> {
...
OnSuccessCheckReceived callBack;
public SignupAsyncTask(){}
public SignupAsyncTask(Context context, OnSuccessCheckReceived callBack){
this.context = context;
this.callBack = callBack;
}
...
#Override
protected void onPostExecute(Boolean result){
//if(result == false){
// // Process if false
// callBack.onSuccessCheckReceived(false); // Tell the caller
//} else if(result == true){
// // Process if true
//}
// a more compact code
callBack.onSuccessCheckReceived(result); // Tell the caller
}
Then you need to implement the listener interface to your caller class.
Something like:
public class YourCallerActivity implements OnSuccessCheckReceived {
...
#Override
public void onSuccessCheckReceived(boolean isSuccess) {
if(isSuccess){
Toast.makeText(getBaseContext(), "Failed", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getBaseContext(), "Success", Toast.LENGTH_SHORT).show();
}
}
...
}
Then you must call your AsyncTask with:
// this is pointing to your implemented interface.
new SignupAsyncTask(getBaseContext(), this).execute(userModel);
Suggestion,
Better if you don't add a context to an AsyncTask, because when your app terminated and AsyncTask not yet finished its job, your AsyncTask will throw an Error because the previous context its pointing is already gone.
So you need to change your SignupAsyncTask constructor to:
public SignupAsyncTask(OnSuccessCheckReceived callBack){
//this.context = context; Remove this.
this.callBack = callBack;
}
and call the SignupAsyncTask with:
new SignupAsyncTask(this).execute(userModel);
UPDATE
As #trooper pointing out, you need to change your:
#Override
protected void onPostExecute(Double result){
}
to
#Override
protected void onPostExecute(Boolean result){
}
So to tell the caller class, you need to tell about the result:
#Override
protected void onPostExecute(Boolean result){
// This is a more compact code that your previous code.
callBack.onSuccessCheckReceived(result); // Tell the caller
}
based on the other signatures in your AsyncTask.
Put your logic inside onPostExecute() :
protected void onPostExecute(Boolean result){
if(successCheck){
Toast.makeText(getBaseContext(), "Success", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getBaseContext(), "Failed", Toast.LENGTH_SHORT).show();
}
}
AsyncTask executes asynchronously i.e., It does not run on a Main thread. It spawns a separate thread known as Worker thread, executes its logic and then post back the results onto the Main thread.
Edit 1
Change your code as below :
public class SignupAsyncTask extends AsyncTask<User, Integer, Boolean> {
ArrayList<User> list = new ArrayList<User>();
DB_User userCtrl = new DB_User();
Context context;
public static boolean successCheck = false;
User user = null;
public SignupAsyncTask(){}
public SignupAsyncTask(Context context){
this.context = context;
}
#Override
protected Boolean doInBackground(User... params) {
try {
user = params[0];
list = userCtrl.getAllUser();
for(int i = 0; i < list.size(); i++){
User userObj = list.get(i);
if(user.getUserName().equals(userObj.getUserName())){
successCheck = false;
break;
}
else if (user.getEmail().equals(userObj.getEmail())){
successCheck = false;
break;
} else{
successCheck = true;
break;
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return successCheck;
}
#Override
protected void onPostExecute(Boolean result){
if(result){
Toast.makeText(getBaseContext(), "Success", Toast.LENGTH_SHORT).show();
//Call SignupUser Code Here...
if(user != null) {
userCtrl.SignupUser(user);
}
} else {
Toast.makeText(getBaseContext(), "Failed", Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onProgressUpdate(Integer... progress) {
}
}
Please modify your code like this
private ArrayList<User> list;
private DB_User userCtrl;
private Context context;
private SendResponse mRes;
public SignupAsyncTask(Context context,SendResponse res){
this.context = context;
userCtrl = new DB_User();
list = new ArrayList<User>();
mRes = res;
}
#Override
protected Boolean doInBackground(User... params) {
try {
list = userCtrl.getAllUser();
for(User userObj:userCtrl.getAllUser()){
if(params[0].getUserName().equals(userObj.getUserName())
|| params[0].getEmail().equals(userObj.getEmail()))
return false;
}else{
userCtrl.SignupUser(params[0]);
return true;
}
} catch (JSONException e) {
e.printStackTrace();
return false;
}
return true;
}
#Override
protected void onPostExecute(Boolean result){
//notify through interface to activity or fragment wherever you want to
//mRes.sendResponse(result);
}
#Override
protected void onProgressUpdate(Integer... progress) {
}
I have an authentication interface with an email field and a button.
When i click the button an AsyncTask should verify if the email exist in a google app engine datastore or not.
This is the code for my asyncTask:
public class ConnexionAsyncTask extends AsyncTask<Object, Object, Inscrit> {
private static InscritApi inscritApi = null;
private Context context;
String email;
ProgressDialog dialog;
public ConnexionAsyncTask(Context context, String email) {
this.context = context;
dialog = new ProgressDialog(context);
this.email = email;
}
#Override
protected void onPreExecute() {
dialog.setMessage("Connexion en cours");
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.show();
}
#Override
protected Inscrit doInBackground(Object... params) {
if (inscritApi == null) {
InscritApi.Builder builder = new InscritApi.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null)
.setRootUrl( // some url );
inscritApi = builder.build();
}
try {
return inscritApi.get(email).execute();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Inscrit inscrit) {
MainActivity main = (MainActivity) context;
main.setInscrit(inscrit);
dialog.dismiss();
}}
And this is the MainActivity code:
public class MainActivity extends AppCompatActivity {
Inscrit inscrit;
Button btncnx;
EditText emailcnx;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btncnx = (Button) findViewById(R.id.btncnx);
emailcnx = (EditText) findViewById(R.id.emailcnx);
btncnx.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ConnexionAsyncTask task = new ConnexionAsyncTask(MainActivity.this, emailcnx.getText().toString());
task.execute();
if (inscrit == null)
Toast.makeText(MainActivity.this, "not exist", Toast.LENGTH_SHORT).show();
else
Toast.makeText(MainActivity.this, "exist", Toast.LENGTH_SHORT).show();
}
});
}
public void setInscrit(Inscrit inscrit) {
this.inscrit = inscrit;
}}
So the code should work like this:
the MainActivity should give the "inscrit" variable to the ConnexionAsyncTask
the ConnexionAsyncTask should verify if the email exist in the datastore or not and then put the result (Inscrit instance or null) in the "inscrit" variable with a setter
the MainActivity should verify if "inscrit" is null or not and show a toast
When i run my code i have to click 2 times to get the real result for example if i put "user#gmail.com" and this email exist of course in the datastore it will show me "not exist" for the first time and exist for second that's mean that the AsyncTask return the value just after the verification.
If i return value with .execute().get() it works but it blocks the ui thread and i want to show a progress Dialog.
I've tried to use a callback interface but it doesn't work either.
You should do the checking
if (inscrit == null)
Toast.makeText(MainActivity.this, "not exist", Toast.LENGTH_SHORT).show();
else
Toast.makeText(MainActivity.this, "exist", Toast.LENGTH_SHORT).show();
after your AsyncTask has finished executing. Basically, you are safe to check on inscrit nullability onPostExecute.
I have a function which makes a http request and parses the response json data. The function is called in AsyncTask class. I have a function defined to check if there is connectivity before asynctask is invoked. But once the connection checker function returns true...my function runs within the asynctask class and the device loses connectivity the application force closes.
private void parseJson()
{
// HTTP request and JSON parsing done here
}
class getData extends AsyncTask <Void,Void,Void>
{
#Override
protected Void onPreExecute(Void...arg0)
{
super.onPreExecute();
//progress dialog invoked here
}
#Override
protected Void doInBackground(Void...arg0)
{
parseJSON();
return null;
}
#Override
protected Void onPostExecute(Void...arg0)
{
super.onPostExecute();
//UI manipulated here
}
}
how do i notify the user about the exception occuring in the doInBackground() method and handle exception properly since doInBackground() doesn't allow things like firing a toast message.
Do this Way
class getData extends AsyncTask <Void,Void,Boolaen>
{
#Override
protected Void onPreExecute(Void...arg0)
{
super.onPreExecute();
//progress dialog invoked here
}
#Override
protected Boolaen doInBackground(Void...arg0)
{
try{
parseJSON();
return true;
}catch(Exception e){
e.printStackStrace();
}
return false;
}
#Override
protected Void onPostExecute(Boolaen result)
{
super.onPostExecute(result);
if(result){
//success
}else{
// Failure
}
//UI manipulated here
}
}
My approach looked like this. Introducing a generic AsyncTaskResult, where you can either store your real return value (if you need one) or the exception which occured in doInBackground(). In onPostExecute you can check if an exception has occured and notify your user (or process your return value).
AsyncTaskResult:
public class AsyncTaskResult<T> {
private T mResult;
private Exception mException = null;
public AsyncTaskResult() {
}
public AsyncTaskResult(T pResult) {
this.mResult = pResult;
}
public AsyncTaskResult(Exception pException) {
this.mException = pException;
}
public T getResult() {
return mResult;
}
public boolean exceptionOccured() {
return mException != null;
}
public Exception getException() {
return mException;
}
}
AsyncTask:
public class RessourceLoaderTask extends AsyncTask<String, String, AsyncTaskResult<String>> {
public RessourceLoaderTask() {
}
#Override
protected AsyncTaskResult<String> doInBackground(String... params) {
try {
// Checked Exception
} catch (Exception e) {
return new AsyncTaskResult<String>(e);
}
return new AsyncTaskResult<String>();
}
#Override
protected void onPostExecute(AsyncTaskResult<String> pResult) {
if (!pResult.exceptionOccured()) {
//...
} else {
// Notify user
}
}
}
Make a field in getData class. Set it in doBackground, check it in onPostExecute.