My main application does this: It retrievs data from the internet and has 3 button, when OnClicked, i am going to 3 other screens. because the data loading may be a little slow, I want to use an async Task. This is my sample code for asynctask.
class LoginProgressTask extends AsyncTask {
#Override
protected Boolean doInBackground(String... params) {
try {
Thread.sleep(4000); // Do your real work here
} catch (InterruptedException e) {
e.printStackTrace();
}
return Boolean.TRUE; // Return your real result here
}
#Override
protected void onPreExecute() {
showDialog(AUTHORIZING_DIALOG);
}
#Override
protected void onPostExecute(Boolean result) {
// result is the value returned from doInBackground
removeDialog(AUTHORIZING_DIALOG);
}
}
and this is my sample of my main activity:
public class MainScreen extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainTheme();
}
public void MainTheme(){
retrieve_data(); //function for getting the data
... action with the buttons, onClicks Listener
}
}
My question is how can I mix those codes in One activity to make it work, becuase I haven't understood AsyncTask. Or what I should return in the doInBackground?
I learned it from >> AsynTask link. may be it will helpful to you too, first read the whole example then start applying it on your code.
For example, if you have a Button to login, you should do something like this:
Button button; //Here button to go other sreen
public void onCreate(){
//some business code here
//notice: you have declare you button to your layout. I don't post it, but maybe you know how to
button.setOnClickListener(new OnClickListener){
#Override
public void onClick(View view){
LoginProcessTask loginTask = new LoginProcessTask(this);
login.excute(data of param1);
}
}
}
And you should notice that, in your LoginProcessTask, you have wrongly extended it. It must be (just for example):
class LoginProgressTask extends AsyncTask<String, Integer, Integer>{ ......}
You can use a Service instead of AsyncTask. This will help you.
Related
I'm trying to understand how AsyncTask callbacks work. This is how my MainActivity looks so far:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyAsyncTask AsyncTask = new MyAsyncTask(arg1,arg2,arg3).execute();
}
And this is my AsyncTask class:
public class MyAsyncTask extends AsyncTask<String, Void, Result> {
private AsyncListener listener;
public MyAsyncTask(AsyncListener listener) {
this.listener = listener;
}
public MyAsyncTask() {
}
#Override
protected Result doInBackground(String... strings) {
return null;
}
#Override
public void onPostExecute(Result result) {
listener.onTaskCompleted();
}
public interface AsyncListener{
void onTaskCompleted();
}
}
This is just the skeleton structure I came up with. I want to implement that I call multiple functions inside the AsyncTask like setting an app launch counter with SharedPreference or initializing AdMob Ads. What would be the best way to implement that?
Your structure is not completely correct because you have 3 parameters in the Activity usage, but your AsyncTask should be "calling back" to the interface listener with some result.
For example
#Override
public void onPostExecute(Result result) {
if (listener != null) {
listener.onTaskCompleted(result);
}
}
So, you need to update the interface method to accept a parameter.
Then you need to pass in an implementation of that interface & method (or anonymous class) to the AsyncTask, then you have a callback.
Regarding the calling of multiple methods, you can use multiple callbacks for different tasks, but it really depends on your end goal.
I'm trying to pass the callback action of a button from the main activity to an AsyncTask class. For now i just pass the Button in the constructor of the AsyncTask class and i do it directly in there:
public AsyncTaskClass(Button btnOk){
this.btnOk = btnOk;
}
#Override
protected void onPreExecute() {
btnOk.setOnClickListener(btnOkListener);
Log.i("AsyncTask", "onPreExecute");
}
private View.OnClickListener btnOkListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
//things to do
}
};
#Override
protected Boolean doInBackground(Void... params) { //etc
Is this good practice? Is there a better way of doing it, perhaps by using an external CallBack Interface? If so, how it can be made? Thank you for your time!
You never, ever pass views, fragments, activities, etc as parameters to threads. The lifecycle of Android can make you nasty surprises like, instances of views, that are not related to any UI container, since it has been replaced by other from the stack. Anyway a callback from click event will always arrive in the UI thread. So either you start the asynch task from onClick() which is simple. Or if in your case, the task is already alive you can call it from the onClick(). But the Asynch task should never know that there is a button!
MyTask myTask;
class MyTask extends AsyncTask{
private boolean shouldDoTheStuff = false;
public synchronized void doSomeStuff(){
shouldDoTheStuff = true;
}
protected synchronized Boolean doInBackground(Void... params) {
while(true){
Thread.sleep(200);
if(shouldDoTheStuff){
//react to the click
shouldDoTheStuff = false;
}
}
}
}
private View.OnClickListener btnOkListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
myTask.doSomeStuff();
}
};
Instead of synchronized you can use AtomicBoolen, which is more clean way.
I am running a book services app on android where the user downloads the book onto his device.The book files are 1mb and above.
Can Async Task be considered as the best practice for this kind of operation.
Are there any other approaches to performing downloads in the background thread.
Please Advice.
Generally it is beleived that AsyncTask is not meant for long running tasks, but sometimes it is a simple way to perform a simple task (no matter how much time it will take). But the thing is,some of the developers perform it in a wrong way.
public class MainActivity extends Activity {
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// Somewhere the AsyncTask is started
public class MyAsyncTask extends AsyncTask<Void, Void, String> {
#Override protected String doInBackground(Void... params) {
// Do work
return result;
}
#Override protected void onPostExecute(String result) {
Log.d("MyAsyncTask", "Received result: " + result);
}
}
}
The Problem with the above code is, When you start an AsyncTask inside an Activity and you rotate the device or any configuration change happens, the Activity will get destroyed and a new instance will be created. But the AsyncTask will not die and keep on going until it completes. Problems1) Since activities are heavy, this could lead to memory issues if several AsyncTask are started.2) Another issue is that the result of the AsyncTask could be lost, if it's intended to act on the state of the activity.
So we need to fix two problems
1) Activity should not be kept in memory when destroy by the framework.
2) Result of the AsyncTAsk should be delivered to the current Activity Instance.
And to Solve these Problems we need otto http://square.github.io/otto/
To use otto create a MyBus.java which we have to use it as a singleton
public class MyBus {
private static final Bus BUS = new Bus();
public static Bus getInstance() {
return BUS;
}
}
Create a AsyncTaskResultEvent.java file
public class AsyncTaskResultEvent {
private String result;
public AsyncTaskResultEvent(String result) {
this.result = result;
}
public String getResult() {
return result;
}
}
Now in your MainActivity, Do AsyncTask
public class MyAsyncTask extends AsyncTask<Void, Void, String> {
#Override protected String doInBackground(Void... params) {
Random random = new Random();
final long sleep = random.nextInt(10);
try {
Thread.sleep(sleep * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Slept for " + sleep + " seconds";
}
#Override protected void onPostExecute(String result) {
MyBus.getInstance().post(new AsyncTaskResultEvent(result));
}
}
Now the Activity that starts the AsyncTask will get the result later.
To fix the memory leak problem add the below code in MainActivity
#Override protected void onDestroy() {
MyBus.getInstance().unregister(this);
super.onDestroy();
}
#Subscribe public void onAsyncTaskResult(AsyncTaskResultEvent event) {
Toast.makeText(this, event.getResult(), Toast.LENGTH_LONG).show();
}
and put this line of code in your OnCreate Method
MyBus.getInstance().register(this);
Now If a configuration change happens we'll automatically be notified of the result in the new Activity instance since it's registered to the event bus.
I want to access activity and set text from async class.
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button getBtn = (Button) findViewById(R.id.btn_result);
getBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
TextView txt_res = (TextView)findViewById(R.id.txt_Result);
new GetText(txt_res).execute(); // Async class
}
});
}
}
//Async Class
public class GetText AsyncTask<Void, Void, Void>{
private TextView txt_res;
public GetText (TextView txt_res) {
this.txt_res = txt_res;
}
#Override
protected Void doInBackground(Void... params) {
try {
String Result = GetTextFromDb();
} catch (Exception e) {
}
return null;
}
#Override
protected void onPostExecute(Void result)
{
try
{
Log.v("Success", "Success"); // I see "Success" at Logcat
txt_res.SetText("Success"); // Textview didn't change
}catch (Exception e) {
Log.v("Error", e.getMessage()); // No error at Logcat
}
}
}
I redefine my question. Textview don't change. Whats my mistake.
I redefine my question again. Textview didn't change at two functions(doInBackground, onPostExecute)
You basically have 2 options. You cannot directly access the main thread from asych obviously, so you must use the proper format.
If the text view needs to be updated after the task finishes, simply do the updating in onPostExecute
If the textview is displaying some intermediate progress, use onProgressUpdate
Edit:
Ok so here is your problem now. With asycn tasks, you must return a value from doInBackground. Change the type to String, and change onPostExecute(String result). Void means you are returning nothing. You will also have to change the second of the three parameters at the top of the async task to string as well.
Also, the method is textview.setText(""); not textview.SetText(""). The latter should not compile
I admit, I'm new at this whole Android stuff. I am trying to make an app but randomly I get Force close errors and I really don't know why. My application has many activities, none of them finish() when I start a new one. I get data from the web (via web services and direct image downloading) and I use AsyncTask a lot. Most of the time it crashes on the asynctask. Here is a sample on how I do things:
private BackTask backTask;
Activity ctx = this;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.trackslist);
backTask = new BackTask();
backTask.execute();
}
protected class BackTask extends AsyncTask<Context, String, myObject>
{
#Override
protected myObject doInBackground(Context... params)
{
try{
if (hasInternet(ctx)==true)
{
//access the web SERVICE here
//initialize myObject WITH result FROM the web
return myObject
}
else
{
return null
}
}catch(Exception ex){
return null;
}
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
#Override
protected void onProgressUpdate(String... values)
{
super.onProgressUpdate(values);
}
#Override
protected void onCancelled()
{
super.onCancelled();
}
#Override
protected void onPostExecute( myObject result )
{
super.onPostExecute(result);
if (result==null || result.isEmpty())
{
//no valid result, show a message
}
else
{
//result valid do something with it
}
}
}
#Override
public void onPause()
{
if (backTask!=null && ! backTask.isCancelled())
{
backTask.cancel(true);
}
super.onPause();
}
public void btnStartOnClick(View target) {
Intent intent = new Intent(this, MyNewActivity.class);
startActivity(intent);
}
When the activity gets onPause() the task is being canceled. I am not sure what happens during the try/catch if a error appears, from what I've did, it should return null, but I think here I miss something. As I said before, randomly I get a force close even if I am on another Activity. This is really frustrating as I can't offer a app that has this behavior. So, what am I doing wrong ?
There is problem in your code. I have corrected as follows: You find I have added this while calling async task.
Your async task accept context as argument and you was not passing that.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.trackslist);
backTask = new BackTask();
backTask.execute(this);
}
You need to ask inside your AsyncTask class for isCancelled() and then decide what to do.
Check this question. It has a good explanation by Romain Guy:
You can stop an AsyncTask. If you call
cancel(true), an interrupt will be
sent to the background thread, which
may help interruptible tasks.
Otherwise, you should simply make sure
to check isCancelled() regularly in
your doInBackground() method. You can
see examples of this at
code.google.com/p/shelves.