I am using parse.com to make as a backend for an Android app. I have several "inBackground" related functions that need to happen consecutively and then send the results back to my Activity which I use to build a ListView. I am looking for a "clean" way to do this, such as writing a class with methods to call from my Activity. I can't figure out how to do this in an external class though. Take the following code for example:
List<ParseObject> list = ParseUtility.getList();
We will define getList() as something like
private List<ParseObject> result;
public List<ParseObejct> getList() {
ParseQuery<ParseObject> query = ParseQuery.getQuery(TABLE_NAME);
query.whereEqualTo(KEY, VALUE);
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> list, ParseException e) {
if (e == null) {
result = list;
} else {
result = null;
}
}
});
return result;
}
I believe that the "findInBackground" would cause this method to return before "result" is set to the correct value. What is a workaround to this?
If you want to get result from your function you have to use 'synchronized' method ParseQuery.find(...) instead of 'asynchronous' ParseQuery.findInBackground(...). And then call this function from a worker thread or service or AsyncTask, etc...
public static List<ParseObejct> getList() {
ParseQuery<ParseObject> query = ParseQuery.getQuery(TABLE_NAME);
query.whereEqualTo(KEY, VALUE);
result = query.find();
}
new AsyncTask<Void, Void, List<ParseObject>>() {
#Override
protected List<ParseObject> doInBackground(Void... params)
{
return ParseUtility.getList();
}
}.execute();
Related
i'm new to android and coding in general
i have many textviews in my app so i'm retrieving string from parse and displaying it in textview.
i'm using the following parse query
ParseQuery<ParseObject> query=ParseQuery.getQuery("Topics");
query.getInBackground("fRGt3oz8af", new GetCallback<ParseObject>(){
public void done(ParseObject arg0, ParseException arg1) {
if (arg1==null)
{
subTopicName = arg0.getString("class_1");
textView.setText("" + subTopicName);
}
else
{
Log.d("topic", "Error: " + arg1.getMessage());
}
}});
since i've many textview i have to repeat the same code for retrieve each string. so i'm trying to avoid code redundancy.
my question is how can i put the above query in different java class and call that method for retrieving each strings? or is there different method way to do it. I've never worked on parse server before so I'm really struggling with this.
Any help would be appreciated.
Try something like this:
interface ParseCallback {
void onComplete(String result);
//todo onError() ?
}
protected void parse(ParseCallback callback) {
ParseQuery<ParseObject> query = ParseQuery.getQuery("Topics");
query.getInBackground("fRGt3oz8af", new GetCallback<ParseObject>() {
public void done(ParseObject arg0, ParseException arg1) {
if (arg1 == null) {
String subTopicName = arg0.getString("class_1");
if (subTopicName != null) {
callback.onComplete(subTopicName);
}
} else {
Log.d("topic", "Error: " + arg1.getMessage());
}
}
});
}
public void example() {
parse(result -> {
runOnUiThread(() -> {
myTextView.setText(result);
});
});
}
I would recommend to create observer pattern and on implementing the interface callback function you will able to get notified in your UI.
i.e. Create a new class extending ParseQuery and override done function. Create an interface in this class and call the interface function inside done function. Then implement this interface in your Activity class and update the UI.
Hope it give you some idea on how to achieve what you are looking for.
So, I made a function to return an ArrayList of strings. In that function, i have an if/else statement. In the if statement I start a background thread using AsyncTask. My question is, will my function return me the ArrayList called queriedCardIDList before I finish the AsyncTask? And if so, how do I work around this?
Cheers!
public ArrayList<String> getCardIDList()
{
if(shouldIQuery())
{
QueryCardsAsyncTask queryCardsAsyncTask = new QueryCardsAsyncTask();
queryCardsAsyncTask.execute();
}
else
{
myPreferences.loadCardsPrefs();
for(CardModel c : myPreferences.getSavedCards())
{
queriedCardIDList.add(c.getCardID());
}
return queriedCardIDList;
}
return queriedCardIDList;
}
Manage your async task as mentioned below,
public class QueryCardsAsyncTask extends AsyncTask<Void, Void, ArrayList<String>> {
private ArrayList<String> queriedCardIDList = new ArrayList<>();
#Override
protected ArrayList<String> doInBackground(Void... params) {
if (shouldIQuery()) {
// You logic to be written in async task
} else {
// else part, get your data from preference
myPreferences.loadCardsPrefs();
for (CardModel c : myPreferences.getSavedCards()) {
queriedCardIDList.add(c.getCardID());
}
}
return queriedCardIDList;
}
#Override
protected void onPostExecute(ArrayList<String> cardIdList) {
super.onPostExecute(cardIdList);
// Now use cardIdList here as per your requirement
}
}
Then just call async task only
QueryCardsAsyncTask queryCardsAsyncTask = new QueryCardsAsyncTask();
queryCardsAsyncTask.execute();
I would like to send and email on the background of my app.
I followed this example and implemented it
http://javapapers.com/android/android-email-app-with-gmail-smtp-using-javamail/
public class SendMailTask extends AsyncTask {
private ProgressDialog statusDialog;
private Activity sendMailActivity;
public SendMailTask(Activity activity) {
sendMailActivity = activity;
}
protected void onPreExecute() {
statusDialog = new ProgressDialog(sendMailActivity);
statusDialog.setMessage("Getting ready...");
statusDialog.setIndeterminate(false);
statusDialog.setCancelable(false);
statusDialog.show();
}
#Override
protected Object doInBackground(Object... args) {
try {
Log.i("SendMailTask", "About to instantiate GMail...");
publishProgress("Processing input....");
GMail androidEmail = new GMail(args[0].toString(),
args[1].toString(), (List) args[2], args[3].toString(),
args[4].toString());
publishProgress("Preparing mail message....");
androidEmail.createEmailMessage();
publishProgress("Sending email....");
androidEmail.sendEmail();
publishProgress("Email Sent.");
Log.i("SendMailTask", "Mail Sent.");
} catch (Exception e) {
publishProgress(e.getMessage());
Log.e("SendMailTask", e.getMessage(), e);
}
return null;
}
#Override
public void onProgressUpdate(Object... values) {
statusDialog.setMessage(values[0].toString());
}
#Override
public void onPostExecute(Object result) {
statusDialog.dismiss();
}
}
The code is working fine
However, i have a presentation and i need to explain the code.
In the code, SendMailTask extends AsyncTask without any extra parameters not even Void
I m stuck in this point because i searched and no one is using this way.
Can anyone explain it to me?
without the parameters, AsyncTask will assume the default class (which is Object)
public class SendMailTask extends AsyncTask <Object1, Object2, Object3> {
#Override
protected Object doInBackground(Object1... args) {
...
//publishProgress calls "onPublishProgress" method
//e.g. publishProgress("email sent.");
publishProgress(object2);
//last line returns to "onPostExecute" method
//e.g. return null;
return object3;
}
#Override
public void onProgressUpdate(Object2... values) {
...
}
#Override
public void onPostExecute(Object3 result) {
...
}
}
Object1 is the array of parameters you pass in when initializing the asyncTask
new SendMailTask(SendMailActivity.this).execute(fromEmail,
fromPassword, toEmailList, emailSubject, emailBody);
so fromEmail, fromPassword, etc, etc all goes into the array of Object1.
you access them in doInBackground method using arg[ index ].
If you not specify any Generic parameter , You will see it will take Object as a type (Base Class for all Classes)
So in case of using only AsyncTask
You are actually dealing with Object
eg- See the parameter of doInBackground() in the given link
Honestly, the way they've extended AsyncTask isn't terribly smart. It causes a number of annoying warnings in Android Studio, and it would have been just as easy to extend AsyncTask<Object, Object, Object>, it's the same effect, but it removes the warnings.
All of that said, in order to use the class, you can simply call the following:
Object[] args = new Object[]{
arg1,
arg2,
etc
};
new SendMailTask(activity).execute(args);
You just need to check the GMail constructor to see how you should order your args.
I'm trying to load the categories for my app from my Parse database. I can return the result by setting an EditText view to a value of the String ArrayList that i download from the database. But when i return the ArrayList in the doInBackground method, and try to set the same EditText to the result in the onPostExecute method, it says that the index is out of bounds and the ArrayList size is 0. This is my code:
private class DownloadCategories extends AsyncTask<Void, Void, ArrayList<String>> {
protected ArrayList<String> doInBackground(Void... voi) {
final ArrayList<String> load = new ArrayList<String>();
ParseQuery<ParseObject> query = ParseQuery.getQuery("Categories");
query.findInBackground(new FindCallback<ParseObject>() {
#SuppressLint("NewApi")
public void done(List<ParseObject> objects, ParseException e) {
String category;
if (e == null) {
for (int i = 0; i < objects.size(); i++) {
ParseObject pObject = objects.get(i);
category = pObject.getString("name");
load.add(category);
}
// onSucced(objects);
} else {
}
//This is where i successfully can set the EditText to the first index.
address.setText(load.get(0));
}
});
return load;
}
protected void onPostExecute(ArrayList<String> loadedCats) {
//This is where it gives me a null pointer error, since loadedCats is empty.
address.setText(loadedCats.get(0));
}
}
Should I just use a class variable an access the variable in the onPostExecute method, or just update the UI from the doInBackground method after i have downloaded the categories, or do you have a solution to the problem with the result?
Thanks in advance.
You don't need the parent AsyncTask, you're already using findInBackground.
What causes the issue here is that you're running the findInBackground in the background, so it's parent AsyncTask will not wait until the done method is called. Instead, it's returning the empty ArrayList. After that the done method is called so it doesn't make any difference to the list.
I am trying to unzip a folder using Android's AsyncTask. The class (called Decompress) is an inner class of Unzip where Unzip itself is a non-Activity class. The pseudo-code is:
public class Unzip {
private String index;
private String unzipDest; //destination file for storing folder.
private Activity activity;
private boolean result; //result of decompress.
public void unzip(String loc) {
Decompress workThread = new Decompress(loc, activity);
workThread.execute();
if(unzip operation was successful) {
display(index);
}
//Class Decompress:
class Decompress extends AsyncTask<Void, Integer, Boolean> {
private ProgressDialog pd = null;
private Context mContext;
private String loc;
private int nEntries;
private int entriesUnzipped;
public Decompress(String location, Context c) {
loc = location;
mContext = c;
nEntries = 0;
entriesUnzipped = 0;
Log.v(this.toString(), "Exiting decompress constructor.");
}
#Override
protected void onPreExecute() {
Log.v(this.toString(), "Inside onPreExecute.");
pd = new ProgressDialog(mContext);
pd.setTitle("Unzipping folder.");
pd.setMessage("Unzip in progress.");
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
Log.v(this.toString(), "Showing dialog and exiting.");
pd.show();
}
#Override
protected Boolean doInBackground(Void... params) {
//unzip operation goes here.
unzipDest = something; //unzip destination is set here.
if(unzip operation is successful) {
result = true;
index = url pointing to location of unzipped folder.
} else {
result = false;
}
}
#Override
protected void onPostExecute(Boolean result) {
if(result) {
if(pd != null) {
pd.setTitle("Success");
pd.setMessage("folder is now ready for use.");
pd.show();
pd.dismiss();
pd = null;
Log.v(this.toString(), "Unzipped.");
index = unzipDest + "/someURL";
Log.v(this.toString(), "index present in: " + index);
}
} else {
pd = ProgressDialog.show(mContext, "Failure", "Cannot unzip.");
pd.dismiss();
}
}
}
Problems I am facing:
1. The value of unzipDest and index, updated in doInBackground, remain null to Unzip and all its objects. How can I ensure that the values remain updated?
2. I know that doInBackground occurs in a thread separate from the main UI thread. Does that mean that any values updated in the new thread will be lost once that thread returns?
How can I ensure that the values remain updated?
They will be updated since they are member variables. However, since AsyncTask is asynchrounous, they might not be updated yet when you check them. You can use an interface to create a callback when these values are updated. This SO answer covers how to do this
Does that mean that any values updated in the new thread will be lost once that thread returns?
No they shouldn't be "lost". They probably just haven't been changed in the AsyncTask when you check them.
Since this isn't your actual code I can't see when you are trying to access them but you can use the interface method or call the functions that need these values in onPostExecute(). You also can do a null check before trying to access them. It just depends on the functionality and flow that you need as to which is the best way. Hope that helps.
Edit
In the answer I linked to, you tell the Activity that you will use that interface and override its method(s) with implements AsyncResponse in your Activity declaration after creating the separate interface class
public class MainActivity implements AsyncResponse{
then, in your Activity still, you override the method you declared in that class (void processFinish(String output);)
#Override
void processFinish(String output){ // using same params as onPostExecute()
//this you will received result fired from async class of onPostExecute(result) method.
}
then this is called in onPostExecute() when the listener sees that it is done with delegate.processFinish(result); delegate is an instance of AsyncResponse (your interface class)
public class AasyncTask extends AsyncTask{
public AsyncResponse delegate=null;
#Override
protected void onPostExecute(String result) {
delegate.processFinish(result);
}
Interface example taken from linked answer above and adjusted/commented for clarity. So be sure to upvote that answer if it helps anyone.