I'm trying to build a demo app with 2 buttons, one downloads a video and the other downloads a PDF. I want to take care of the downloading in the background thread through AsyncTask. So far I have starter code with implemented methods. I haven't added the code for what I want to download yet because I want to figure out the logic behind separate downloads so for now, I have Log messages.
This is the code:
public class MainActivity extends AppCompatActivity {
Button downloadVideo, downloadPDF;
DownloadingClass downloadingClass = new DownloadingClass();
private static final String TAG = "omar.asynctaskdemo;";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
downloadVideo = findViewById(R.id.download_video);
downloadPDF = findViewById(R.id.download_pdf);
downloadVideo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {}
});
downloadPDF.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {}
});
}
private class DownloadingClass extends AsyncTask<Void, Void, Void>{
#Override
protected void onPreExecute() {
super.onPreExecute();
Log.d(TAG, "doInBackground: Before");
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Log.d(TAG, "doInBackground: After");
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
Log.d(TAG, "doInBackground: Progress");
}
#Override
protected Void doInBackground(Void... voids) {
Log.d(TAG, "doInBackground: Content to download");
return null;
}
}
}
I'd appreciate a concise explanation on how to go about it.
Don't do this
DownloadingClass downloadingClass = new DownloadingClass();
Always create just before you kick of the task:
new DownloadingClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
This is because you can't reuse the AsyncTask. It has status and will not run again once status is "Finished".
if you have same input/output type in both download methods u can use same DownloadingClass by Declaring an object for each methods , like :
DownloadingClass downloadPDF = new DownloadingClass();
DownloadingClass downloadVideo = new DownloadingClass();
then just call downloadPDF.execute();/downloadVideo.execute();
or u can manage them by ExecutorService :
How to wait for all threads to finish, using ExecutorService?
Related
Here is my problem. I have created a asyncTask to link to my database and send and receive information using JSON.
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
progressDialog.dismiss();
returnValues = dataParsed.split("\\s+");
mainActivity.getValue(this is the function that calls anotherfunction in
asyncTask)
Log.v("ARRAY LENGTH", String.valueOf(returnValues.length));
}
public String[] returnmyString(){
//return mySaveData;
Log.v("ARRAY LENGTH 2", String.valueOf(returnValues.length));
return returnValues;
}
I create the asyncTask object within my activity based class and then call that object.execute. My problem is that my code will continue to run once calling the object.execute and one of the lines calls a function within the asyncTask class before it is done executing all the code.
process.activitySave(1); //<---Process is the object for the asyncTask class
process.ContextSave(this,ServerURLSource,myParameters);
process.execute()
changedData = process.returnmyString(); //<-- this is the line of code that gets implemented that returns a null value
I have tried creating a Mainactivity object in the asyncTask class and then calling a function then that retrieves the value but my app crashes when I do this. any help would be appreciated. I would like to put some sort of listener in the mainactivity class as it seems I cannot reference any of the functions from my mainactivity class in my asyncTask class.
This is the function within the asyncTask to return the value:
public String[] returnmyString(){
//return mySaveData;
Log.v("ARRAY LENGTH", String.valueOf(returnValues.length));
return returnValues;
}
Method 1 is the basic, anonymous inner class implementation. Because of the inner AsyncTask class is not static class, you can access to the CustomActivity's properties from that implementation.
In Method 2, AsyncClass implemented separately. If you gave your activity to this class, it can be call back your desired method after execution. This method, for our example is the #setChangedData method. CustomAsyncTask call backs the #setChangedData in the #onPostExecute.
public class CustomActivity extends AppCompatActivity {
String mChangedData;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Method 1 - change data into the anonymously implemented AsyncTask class
new AsyncTask<Integer, Void, Void>() {
#Override
protected Void doInBackground(Integer... params) {
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
CustomActivity.this.mChangedData = "foo"; // this changes mChangedData as "foo"
}
}.execute(1);
// Method 2 - change data into the custom AsyncTask class
new CustomAsyncTask(this).execute(2);
}
public void setChangedData(String changedData){
this.mChangedData = changedData;
}
static class CustomAsyncTask extends AsyncTask<Integer, Void, Void> {
CustomActivity mActivity;
public CustomAsyncTask(CustomActivity activity) {
this.mActivity = activity;
}
#Override
protected Void doInBackground(Integer... params) {
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
mActivity.setChangedData("bar");
}
}
}
And, as method 3, if you want to separate you Activity and AsyncTask more loosely, this is the handler method:
public class CustomActivity extends AppCompatActivity {
private String mChangedData;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CustomAsyncTask task = new CustomAsyncTask();
task.setOnDataChangedListener(new CustomAsyncTask.OnDataChangedListener() {
#Override
public void onDataChanged(String data) {
mChangedData = data;
}
});
task.execute(1);
}
private static class CustomAsyncTask extends AsyncTask<Integer, Void, Void> {
private OnDataChangedListener onDataChangedListener;
#Override
protected Void doInBackground(Integer... params) {
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if(onDataChangedListener != null) {
onDataChangedListener.onDataChanged("foo");
}
}
void setOnDataChangedListener(OnDataChangedListener onDataChangedListener) {
this.onDataChangedListener = onDataChangedListener;
}
interface OnDataChangedListener {
void onDataChanged(String data);
}
}
}
I am well aware that blocking the UI is not a good idea in general but there are some scenarios where my app simply cannot do any other work until some long running operations (e.g. loading data from a server) are complete.
Assume the user clicks the "Load Data" button. To indicate that no UI interaction is possible until the data is loaded I would like to grey out the screen and show some kind of activity indicator. This is no problem at all, I simply overlay the screen with a new Fragment.
The question is: How can I present this overlay fragment?
public void onLoadDataClick() {
// grey out the screen by simple showing a new Fragment
showActivityIndicatorOverlay();
// Start the long running opeartion
doVeryMuchWork();
dismissActivityIndicatorOverlay();
}
public void showActivityIndicatorOverlay() {
FragmentTransaction ft = context.getSupportFragmentManager().beginTransaction();
ActivityIndicatorOverlayFragment overlayFragment = ActivityIndicatorOverlayFragment.newInstance("Loading Data");
overlayFragment.show(ft, "activityIndicator");
}
This does NOT work. The overlay does not show up. If I remove dismissActivityIndicatorOverlay() the overlay shows up after the long running operation completed. This is not too suprising: I assume that the showing the new fragment is handeled at the end of the current run-loop or at the start of the next loop. Of course the long running operation has to complete before the run-loop ends and thus the overlay is displayed too late...
The obvious solution is of course to run the operation in a background thread using an AsyncTask:
public void onLoadDataClick() {
LoadDataTask loadTask = new LoadDataTask();
loadTask.execute();
}
private class LoadDataTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
showActivityIndicatorOverlay();
}
#Override
protected Void doInBackground(Void... params) {
doVeryMuchWork();
}
#Override
protected void onPostExecute() {
dismissActivityIndicatorOverlay();
}
}
I was surprised, that this solution doesn't work either. It behaves exactly like the first approach: The overlay does not appear. When onPostExecute() is removed the overlay appears after the operation is complete. the Why is that?
What is the correct solution to present such an activity indicator?
I'd suggest the use of a ProgessDialog.
Declare a ProgressDialog as an instance variable. Something like : ProgressDialog pDialog;
then inside onCreate() :
pDialog = new ProgressDialog(this);
//The next two methods will ensure that the user is unable to
//cancel the Progress Dialog unless you explicitly
//do so by calling `pDialog.dismiss();`
pDialog.setCancelable(false);
pDialog.setCanceledOnTouchOutside(false);
Modify AsyncTask somewhat like this :
private class LoadDataTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
pDialog.setMessage("Loading Data.. Please Wait.");
pDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
doVeryMuchWork();
}
#Override
protected void onPostExecute() {
pDialog.dismiss();
}
}
A ProgressDialog is very much the canonical solution for these cases...
private class LoadDataTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog mProgress;
#Override
protected void onPreExecute() {
mProgress = new ProgressDialog(context);
mProgress.setTitle("So much to do");
mProgress.setMessage("Doing very much work");
mProgress.setIndeterminate(true);
mProgress.setCancelable(false);
mProgress.show();
}
#Override
protected Void doInBackground(Void... params) {
doVeryMuchWork();
}
#Override
protected void onPostExecute() {
mProgress.dismiss();
}
}
As for your attempted solutions, the first one does not work for the very reasons you state. The second should, though.
You can do something like this, if you're not doing heavy stuff precisely on setContentView(R.layout.main)
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
handler = new Handler();
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
//Do some heavy stuff
return null;
}
#Override
public void onPostExecute(Void result){
handler.post(new Runnable(){
#Override
public void run(){
setContentView(R.layout.main);
}
});
}
}.execute();
}
OR you can use progress dialog
private class LongTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog pd;
Context context;
public LongTask(Context c)
{
this.context = c;
}
#Override
protected void onPreExecute() {
pd = new ProgressDialog(context);
pd.setTitle("Please wait...!");
pd.setMessage("Loding the information");
pd.setIndeterminate(true);
pd.setCancelable(false);
pd.show();
}
#Override
protected Void doInBackground(Void... params) {
// do your heavy tasks here
}
#Override
protected void onPostExecute() {
if (pd.isShowing())
pd.dismiss();
}
}
Call AsyncTask like this
new LongTask(your_activity.this).execute();
In my android app, i am doing time consuming task extending AsyncTask, and want to display the progress in Toast messages. Toast messages are also displayed onPre() and onPost().
I am able to display Toast messages onPre() & onPost() but not able to show onProgressUpdate(Integer... progress).
Following is my code...
public class MainClass extends Activity {
public void Start(View view) {
DemoTasks runner = new DemoTasks(this);
runner.execute("Start");
}
private class DemoTasks extends AsyncTask<String, Integer, Integer> {
private Context context;
public DemoTasks(Context context){
this.context = context;
}
#Override
protected Integer doInBackground(String... params) {
try {
publishProgress(0);
doWork();
Thread.sleep(5000L);
publishProgress(100);
} catch (Exception localException) {
Log.d("POST", localException.getMessage());
}
return 100;
}
#Override
protected void onPostExecute(Integer result) {
Toast.makeText(context, "post", Toast.LENGTH_SHORT).show();
}
#Override
protected void onPreExecute() {
Toast.makeText(context, "pre", Toast.LENGTH_SHORT).show();
}
#Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
Toast.makeText(context, "progress-" + progress, Toast.LENGTH_SHORT).show();
}
}
}
Also in my doInBackgroud(String...params) ...Thread.sleep is also not working.
As soon as onPre() gets executed, onPost() also executes after that!!!!
You can try this,
showProgress ();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
dialog.cancel();
Intent i=new Intent(getApplicationContext(),Main.class);
startActivity(i);
finish();
}
}, 3000); //number of seconds
private ProgressDialog dialog;
public void showProgress () {
dialog = new ProgressDialog(this);
dialog.setCancelable(true);
dialog.setMessage("Please wait");
dialog.show();}
Bascially,you can access the UI on any method, even In doinBackground you can access the UI using runOnUIthread.
here is one AsyncTask Example. This will show a peogress dialog while executing the task.
private class LoginProcessing extends AsyncTask<Object, Void, Void> {
private LoginCredentials myLoginCredentials;
private ProgressDialog progressDialog;
public LoginProcessing(LoginCredentials Credentials) {
super();
myLoginCredentials=Credentials;
progressDialog.setMax(100);
progressDialog.setMessage("Please Wait..");
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setProgress(0);
progressDialog.show();
}
protected void onPreExecute (){
}
#Override
protected Void doInBackground(Object... arg0) {
// TODO Auto-generated method stub
//Code to do the process in background
return null;
}
#Override
protected void onProgressUpdate(Long... progress) {
// int percent = (int)(100.0*(double)progress[0]/mFileLen + 0.5);
progressDialog.setProgress(progress);
}
protected void onPostExecute(Void result){
progressDialog.dismiss();
//Your code after the process
}
}
You can call this Task as,
new LoginProcessing(loginCredentials).execute();
In this Example loginCredentials is the parameter I am passing to the AsyncTask. You can change it to your own parameter.
First of all I must say I'am new at Android but not at Java.
I did HttpRequest With AsyncTask.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Thread th = new Thread(new Runnable() {
#Override
public void run() {
new RequestTask().execute("http://www.url.com/ajaxrequest/?kategori=27");
}
});
th.start();
}
Created Another Class ( Name : RequesTask )
class RequestTask extends AsyncTask<String, String, String>{
private void RequestTask(String URL){
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
// Some Codes Here...
return responseString;
}
#Override
protected String doInBackground(String... uri) {
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
String responseString = null;
// Some Codes Here...
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// My Result is 'result'
}
I want to send and write this string value to TextView In MainActivty. How can i send 'result' ?
Thanks in advance..
Don't open a new thread to run the async task from this thread. It won't work (will fail on internal handler). The async task by himself open for you a new thread.
This is the right code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.your_text_view);
new RequestTask().execute("http://www.url.com/ajaxrequest/?kategori=27");
}
And in your RequestTask
#Override
protected void onPostExecute(String result) {
textView.setText(result);
}
Edit: To your question, how to access TextView from AsyncTask
You can do it in many ways. These are part of them:
Define AyncTask as an inner class inside your Activity. You can access members of Activity within AsyncTask. This option is very coupled, means async task which apparently the logic of your app is part of your ui. Like this:
class YouActivity extends Activity {
TextView textView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.your_text_view);
new RequestTask().execute("http://www.url.com/ajaxrequest/?kategori=27");
}
class RequestTask extends AsyncTask<String, String, String> {
...
#Override
protected void onPostExecute(String result) {
textView.setText(result);
}
}
}
Deliver the TextView to AsyncTask by constructor or setter method. This option is less coupled, since this AsyncTask can be used by many consumers who want to update their TextView, but the is still coupling by holding reference from AsyncTask to your views.
Your AsyncTask:
class RequestTask extends AsyncTask<String, String, String> {
TextView textView = null;
public void setTextView(TextView textView) {
this.textView = textView;
}
...
#Override
protected void onPostExecute(String result) {
if (textView != null) {
textView.setText(result);
}
}
}
And your activity:
class YouActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = (TextView) findViewById(R.id.your_text_view);
RequestTask requestTask = new RequestTask();
requestTask.setTextView(textView);
requestTask.execute("http://www.url.com/ajaxrequest/?kategori=27");
}
}
To make your program more loosely coupled and to make better separation of controller from your views, use Handlers:
class RequestTask extends AsyncTask<String, String, String> {
Handler handler = null;
public void setHandler(Handler handler) {
this.handler = handler;
}
...
#Override
protected void onPostExecute(String result) {
if (handler != null) {
Message message = new Message();
message.obj = result;
handler.sendMessage(message);
}
}
}
And your activity:
class YouActivity extends Activity {
TextView textView;
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
String value = (String) msg.obj;
textView.setText(value);
}
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.your_text_view);
RequestTask requestTask = new RequestTask();
requestTask.setHandler(handler);
requestTask.execute("http://www.url.com/ajaxrequest/?kategori=27");
}
}
Handlers cave tons of options. You can 'send message' from any thread and you can decouple your app very good with this tool.
You can either pass the TextView to RequestTask's constructor or make it a global member. And in your onPostExecute method:
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
yourTextView.setText(result);
}
That's it :)
Edit: Whoops. As sromku correctly pointed out, AsyncTask already performs the doInBackground() method in a separate thread (in background) so you should not be wrapping it in another thread. So, remove that Thread-ception.
best solution
Instead of using so many classes for different types of asynctask , I suggest you use this library
you can have a look at here
http://loopj.com/android-async-http/
your code will become very very less , instead of declaring so may asynctask seperately writing bulk of code , you can just use 4 lines of code
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
#Override
public void onSuccess(String response) {
System.out.println(response);
}
});
I is very efficient in geting the response very quickly.
I hope this will help you out. :)
I am trying to make a simple task in background and show a progress bar while it is being done.
This is the code for the main (and the only) Activity:
public class Login extends Activity {
public static ProgressDialog progressDialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
(...)
this.getWindow().requestFeature(Window.FEATURE_PROGRESS);
this.getWindow().setFeatureInt(Window.FEATURE_PROGRESS, Window.PROGRESS_VISIBILITY_ON);
progressDialog = new ProgressDialog(activity);
progressDialog.setMessage("Sending data...");
progressDialog.setCancelable(false);
(...)
// In some onClick Eevent..
JSONObject result = new Urltasks().execute(...).get();
(...)
}
}
This is the code for the activity:
class Urltasks extends AsyncTask<String, Integer, JSONObject>{
protected void onPreExecute() {
System.out.println("Inicia onPreExecute");
Login.progressDialog.show();
}
protected void onPostExecute(String result) {
Login.progressDialog.dismiss();
}
protected JSONObject doInBackground(String... arg0) {
// Some work being done. I do not use Login.progressDialog here
}
}
With this code the ProgressDialog shows up when the task ends, and it doesn't dismiss.
Problem is here:
JSONObject result = new Urltasks().execute(...).get();
Calling get() on an AsyncTask blocks the current thread, i.e. your UI thread, until the AsyncTask is executed. Therefore the progress dialog cannot run. Remove the get().
To obtain the result of the AsyncTask, you can e.g. pass in a listener callback to the asynctask that gets notified when the result is available:
class YourAsyncTask extends AsyncTask<ParamType, ProgressType, ResultType> {
private YourResultListener mListener;
interface YourResultListener {
void onResultAvailable(ResultType result);
}
YourAsyncTask(YourResultListener listener) {
mListener = listener;
}
#Override protected ResultType doInBackground(ParamType... params) {
//...
}
#Override protected void onPostExecute(ResultType result) {
mListener.onResultAvailable(result);
}
}
You can use it like:
mProgressDialog.show();
new YourAsyncTask(new YourResultListener() {
#Override void onResultAvailable(ResultType result) {
mProgressDialog.dismiss();
// use result
}).execute(params);
Personally I like to keep user interface elements such as progress dialogs decoupled from async tasks.
Don't put your progress dialog in your log in class. Keep it in the async task
this is how you show your dialog
progressDialog = ProgressDialog.show(yourActivityHERE.this, "",
"Loading... please wait.");
Edited this for you:
class Urls extends AsyncTask<String, Integer, JSONObject>{
ProgressDialog progressDialog;
protected void onPreExecute() {
progressDialog = ProgressDialog.show(yourActivityHERE.this, "",
"Loading... please wait.");
}
protected void onPostExecute(String result) {
progressDialog.dismiss();
}
protected JSONObject doInBackground(String... arg0) {
// Some work being done. I do not use Login.progressDialog here
}
}
create the constructor in your Urltasks sending the context of the calling class.
then use that context to create the progress dialog in the preExecute of your Urltasks
class Urltasks extends AsyncTask<String, Integer, JSONObject>{
Context mContext;
public static ProgressDialog progressDialog;
public UrlTasks(Context c){
mContext=c;
}
protected void onPreExecute() {
progressDialog = new ProgressDialog(mContext);
progressDialog.setMessage("Sending data...");
progressDialog.setCancelable(false);
progressDialog.show();
}
protected void onPostExecute(String result) {
progressDialog.dismiss();
}
protected JSONObject doInBackground(String... arg0) {
// Do your work here
}
}