In my Android app I have up to 4 asynchronous tasks that depend on each other, which means that one task has to finish before the next one can go one with the retreived data. Now this can be quite unclear at some point when the code looks something like this:
final AsyncTask<Void, Void, Boolean> taskOne = new AsyncTask<Void, Void, Boolean>() {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Void... params) {
// retrieve required data
return true;
}
#Override
protected void onPostExecute(Boolean success) {
if (success) {
// start second task here
final AsyncTask<Void, Void, Boolean> taskTwo = new AsyncTask<Void, Void, Boolean>() {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Void... params) {
// retrieve required data
return true;
}
protected void onPostExecute(Boolean success) {
if (success) {
// start third task here
final AsyncTask<Void, Void, Boolean> taskThree = new AsyncTask<Void, Void, Boolean>() {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Void... params) {
// retrieve required data
return true;
}
protected void onPostExecute(Boolean success) {
if (success) {
// and so on ...
}
}
}
taskThree.execute();
}
}
}
taskTwo.execute();
}
}
}
taskOne.execute();
What would be the best practice to achieve this behaviour with a more readable code?
Thanks in advance
TaskOne
Class TaskOne extends AsyncTask{
onPostExecute(boolean success){
if(success){
new TaskTwo().execute();
}
}
}
TaskTwo
Class TaskTwo extends AsyncTask{
onPostExecute(boolean success){
if(success){
new TaskThree().execute();
}
}
}
TaskThree
Class TaskThree extends AsyncTask{
onPostExecute(boolean success){
if(success){
//do something
}
}
}
I think you should crash with Interface. In your case it's called Listener or Callback. I didn't test the code. But it looks like that
Class A extend Activity implement ServerRequestListener{
public ServerRequestListener listener;
#Override
onCreate (Bundle bundle){
listener = this;
doTaskOne();
}
public void doTaskOne(){
final AsyncTask<Void, Void, Boolean> taskOne = new AsyncTask<Void, Void, Boolean>() {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Void... params) {
// retrieve required data
return true;
}
#Override
protected void onPostExecute(Boolean success) {
if (success) {
listener.onSuccess(new JSON());
}
}
}
taskOne.execute();
}
public interface ServerRequestListener {
void onSuccess(Json);
void onFailure(Error);
}
#Override
onSuccess(Json json){
//call second task
}
#Override
onFailure(Error error){
}
}
Related
I'm trying to display a ProgressDialog in my Activity while I'm executing a task with AsyncTask. Here my code below.
My problem is that onPreExecute() is called (I checked it with print) but my progressDialog is not shown while my function sendRequest is executed in doInBackground(..). I don't understand what it happens and I don't know how to solve that. I googled it but I didn't find any suitable solution. If you have any idea it would be great for me.
private static Activity activity;
private static ProgressDialog dialog;
public MyClass(Activity activity){
this.activity = activity;
}
public static String sendRequest(String request){
//do something
}
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = ProgressDialog.show(activity,
"ProgressDialog",
"Wait!");
}
#Override
protected String doInBackground(String... params) {
String result = sendRequest(params[0]);
return result;
}
#Override
protected void onPostExecute(final String result) {
dialog.dismiss();
}
Try:
progressDialog = new ProgressDialog(context);
progressDialog.setTitle("title");
progressDialog.setMessage("message");
progrsesDialog.show();
Try this
private class AsyncTaskRunner extends AsyncTask<String, String, String> {
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(CardPaymentActivity.this,
"Progress", "please wait...");
}
#Override
protected String doInBackground(String... params) {
publishProgress("sleep time..."); // Calls onProgressUpdate()
return null;
}
#Override
protected void onPostExecute(String result) {
progressDialog.dismiss();
}
#Override
protected void onProgressUpdate(String... text) {
}
}
and call AsyncTaskRunner class in your activity class like this
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_card_payment);
AsyncTaskRunner myTask = new AsyncTaskRunner();
myTask.execute();
}
I want to publish the result of my AsyncTask (a string) in a textView.
Here is my Main:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ReadRss readRss=new ReadRss(this);
readRss.execute();
......
}
Here is my AsyncTask:
public class ReadRss extends AsyncTask<Void,Void,Void> {
public ReadRss(Context context){
}
#Override
protected void onPreExecute() {
}
#Override
protected void onPostExecute(Void aVoid) {
}
#Override
protected Void doInBackground(Void... params) {
ProcessXml();
return null;
}
private void ProcessXml() {
//HERE CREATE MY STRING
String myresult="example";
TextView txt_ris = (TextView)findViewById(R.id.txt_ris); <---HOW CAN I DO THIS?
txt_ris.setText(myresult);
}
}
}
}
FindViewById don't work in the AsyncTask so how can i get the TextView in here?
Maybe i can pass it as a paramiter in the AsyncTask, What is the syntax?
You need to place UI work in onPostExecute method, since doInBackground executes in not UI thread
public class ReadRss extends AsyncTask<Void,Void,String> {
public ReadRss(Context context){
}
#Override
protected void onPreExecute() {
}
#Override
protected void onPostExecute(String string) {
TextView txt_ris = (TextView)findViewById(R.id.txt_ris);
txt_ris.setText(myresult);
}
#Override
protected String doInBackground(Void... params) {
return ProcessXml();
}
private String ProcessXml() {
//HERE CREATE MY STRING
return "example";
}
}
For your TextView to be correctly referenced you need a context and you already have a reference to your starting Activity in your AsyncTask constructor, so you can do something like:
public class ReadRss extends AsyncTask<Void,Void,Void> {
private TextView tv;
private YourStartingActivity activity;
public ReadRss(Context context){
activity = (YourStartingActivity)context;
tv = (TextView)activity.findViewById(R.id.txt_ris)
}
#Override
protected void onPreExecute() {
...
}
#Override
protected void onPostExecute(Void aVoid) {
(follow Michael Spitsin instructions here)
}
#Override
protected Void doInBackground(Void... params) {
...
}
}
I'm trying to show a progress dialog while the twitter feed is loading up...However the progress dialog remains on screen when the twitter feed appears. Any help is much appreciated.
public class MainActivity extends ListActivity {
final static String twitterScreenName = "CFABUK";
final static String TAG = "MainActivity";
private AsyncTask<Object, Void, ArrayList<TwitterTweet>> tat;
boolean done;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
done=false;
AndroidNetworkUtility androidNetworkUtility = new AndroidNetworkUtility();
if (androidNetworkUtility.isConnected(this)) {
TwitterAsyncTask syn=new TwitterAsyncTask();
syn.execute(twitterScreenName,this);
ProgressDialog pd = new ProgressDialog(MainActivity.this);
pd.setMessage("loading");
pd.show();
do {
if(!(syn.getStatus()==AsyncTask.Status.RUNNING)) {
pd.dismiss();
pd.cancel();
done=true;
}
} while(done=false);
} else {
Log.v(TAG, "Network not Available!");
}
}
}
You must call ProgressDialog show() method on AsyncTasks onPreExecute(). For example:
class MyTask extends AsyncTask<Void, Void, Void> {
ProgressDialog pd;
#Override
protected void onPreExecute() {
super.onPreExecute();
pd = new ProgressDialog(MainActivity.this);
pd.setMessage("loading");
pd.show();
}
#Override
protected Void doInBackground(Void... params) {
// Do your request
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if (pd != null)
{
pd.dismiss();
}
}
}
You must use a onPreExecute and onPostExecute of AsyncTask class. For example:
class AsyncData extends AsyncTask<Void, Void, Void>{
#Override
protected void onPreExecute() {
super.onPreExecute();
// init progressdialog
}
#Override
protected Void doInBackground(Void... arg0) {
// get data
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// dismiss dialog
}
}
The methods onPreExecute(), doInBackground() and onPostExecute() of AsyncTask are used for purpose that you mentioned -
public class MainActivity extends ListActivity {
final static String twitterScreenName = "CFABUK";
final static String TAG = "MainActivity";
private AsyncTask<Object, Void, ArrayList<TwitterTweet>> tat;
boolean done;
Context context;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
done=false;
context = this;
new NetworkTask().execute();
}
}
class NetworkTask extends AsyncTask<String, String, String>
{
Context ctx = context ;
#Override
protected void onPreExecute()
{
super.onPreExecute();
pDialog = new ProgressDialog(getActivity());
pDialog.setMessage("Working ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
#Override
protected String doInBackground(String... args)
{
//Do your background work here and pass the value to onPostExecute
AndroidNetworkUtility androidNetworkUtility = new AndroidNetworkUtility();
if (androidNetworkUtility.isConnected(ctx)) {
TwitterAsyncTask syn=new TwitterAsyncTask();
syn.execute(twitterScreenName,this);
while(done)
{
if(!(syn.getStatus()==AsyncTask.Status.RUNNING))
{
done=true;
}
else
{
Log.v(TAG, "Network not Available!");
}
}
return done + "";
}
protected void onPostExecute(String result)
{
//Do something with result and close the progress dialog
pDialog.dismiss();
}
ProgressBar is best alternative for ProgressDialog. A user interface element that indicates the progress of an operation.
ProgressDialog is deprecated in latest versions.
For more info see android developer official site: https://developer.android.com/reference/android/widget/ProgressBar.html
I know there was similiar problem to this, but I still haven't found an answer. The problem is that progress dialog for this long operation won't show up, but still process is being done. I think there is problem with the context, but dunno how to solve this.
public class MainActivity extends Activity {
Utilities uti = new Utilities();
SharedPreferences prefs = null;
private ContactServiceActivity contactService;
ProgressDialog mProgressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
contactService = new ContactServiceActivity(getApplicationContext());
doFirstRun();
Intent i = new Intent(getBaseContext(), ContactListActivity.class);
startActivity(i);
}
private void doFirstRun() {
SharedPreferences settings = getSharedPreferences("pl.stxnext.stxcontactsync", MODE_PRIVATE);
if (settings.getBoolean("isFirstRun", true)) {
new firstRunTask().execute();
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("isFirstRun", false);
editor.commit();
}
}
private class firstRunTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog = new ProgressDialog(MainActivity.this);
mProgressDialog.setTitle("Trwa synchronizacja danych");
mProgressDialog.setMessage("Może to zająć chwilę, proszę czekać.");
mProgressDialog.setIndeterminate(false);
mProgressDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
contactService.getAssetsAtFirstRun();
return null;
}
#Override
protected void onPostExecute(Void result) {
mProgressDialog.dismiss();
uti.showToast(getBaseContext(), "Zapisano kontakty.");
}
}
}
create one constructor like:
Context _context;
public firstRunTask(Context context)
{
_context=context;
}
and use this _context for context in dialog.
Try like this
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
// Do something
return "Executed";
}
#Override
protected void onPostExecute(String result) {
if(mProgressDialog.isShowing()){
mProgressDialog.dismiss();
}
}
#Override
protected void onPreExecute() {
ShowLoading();
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
private void ShowLoading(){
mProgressDialog = new ProgressDialog(this);
//mProgressDialog.setMessage("Loading Please wait ....");
mProgressDialog.setIndeterminate(false);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.setCancelable(false);
mProgressDialog.show();
}
You are starting an activity after starting the asyctask by calling doFirstRun(); , and thus you are not seeing the progressdialog created. if you remove/comment the startActivity portion as follows, it should work:
doFirstRun();
// comment the following
//Intent i = new Intent(getBaseContext(), ContactListActivity.class);
//startActivity(i);
If you still want to start that activity anyway, then you should start the asynctask after that.
Do this-
private class firstRunTask extends AsyncTask<Void, Void, Void> {
ProgressDialog mProgressDialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog=ProgressDialog.show(MainActivity.this, "Trwa synchronizacja danych", "Może to zająć chwilę, proszę czekać.");
}
#Override
protected Void doInBackground(Void... params) {
contactService.getAssetsAtFirstRun();
return null;
}
#Override
protected void onPostExecute(Void result) {
if(mProgressDialog != null)
{
if(mProgressDialog.isShowing())
{
mProgressDialog.dismiss();
uti.showToast(getBaseContext(), "Zapisano kontakty.");}
}
}
I have a button on 6 different Activities. Clicking on that button does almost the same task with different params depending on the Activity.
This will be done using an AsyncTask and in onPostExecute() the button state will be changed.
someButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Task().execute("param1", "param2");
}
}
private class Task extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
//background task using params[0], params[1]
return "success" or "error";
}
#Override
protected void onPostExecute(String result) {
if (result == "success") {
//change the someButton state
}else{
//show an error message
}
}
Instead of having the same AsyncTask in all the 6 Activities, how can I use a single Asynctask from all the Activities and change the respective view?
You should create Task, with methods onSuccess, onFailure and override them.
public class Task extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
//background task using params[0], params[1]
return "success" or "error";
}
#Override
protected void onPostExecute(String result) {
if (result == "success") {
onSuccess(result);
}else{
onFailure(result);
}
}
protected void onSuccess(String result) {};
protected void onFailure(String result) {};
}
and then in activity use it like this:
someButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Task(){
#Override
protected void onSuccess(String result){
// do what you want
}
#Override
protected void onFailure(String result){
// do what you want
}
}.execute("param1", "param2");
}
}
Put your Task in its own file and make it public.
Create a callback interface:
public interface TaskCallback {
public void onSuccess(String result);
public void onFailure(String errorMessage);
}
Give such a callback to your Task:
public class Task extends AsyncTask<String, Void, String> {
private TaskCallback callback;
public Task(TaskCallback callback) {
this.callback = callback;
}
#Override
protected String doInBackground(String... params) {
//background task using params[0], params[1]
return "success" or "error";
}
#Override
protected void onPostExecute(String result) {
if (result == "success") {
callback.onSuccess(result);
} else{
callback.onFailure(errorMessage);
}
}
}
And then implement the callback when creating the Task instance in your activity:
someButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
private TaskCallback callback = new TaskCallback() {
#Override
public void onSuccess(String result) {
//change the someButton state
}
#Override
public void onFailure(String errorMessage) {
//show an error message
}
}
new Task(callback).execute("param1", "param2");
}
}