SyncTask in separate class, reach my views - android

I have Asynch in a separate class, and I need to change setText on some of the TextViews
How this possible?
OR should I keep AsyncTask inside my Class?
private class DownloadImageTask extends AsyncTask<Object, Void, AdModel> {
#Override
protected AdModel doInBackground(Object... params) {
return getAd();
}
protected void onPostExecute(AdModel result) {
textTitle.setText(result.getTitle());
}
}

You could create a constructor for your AsyncTask that takes a reference to your activity. You might want to be careful about not leaking your activity reference by nulling it out from within your AsyncTask when it's done.

private class DownloadImageTask extends AsyncTask {
private TextView text;
DownloadImageTask(TextView txtToUpdate) {
text = txtToUpdate;
}
#Override
protected AdModel doInBackground(Object... params) {
return getAd();
}
protected void onPostExecute(AdModel result) {
text.setText(result.getTitle());
text = null;
}
}
or ..better... create listener interface, which You will invoke at onPostExecute. Implementation of listener interface should update TextView.

Related

How to handle UI in asynctask?

Generally I update UI in postExecute method.
e.g.
public class SampleActivity extends Activity{
TextView textSample;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aadd_addtocheck);
textSample = (TextView) findViewById(R.id.lin);
STask sampleTask = new Stask();
sampleTask.execute();
}
class GetAdd extends AsyncTask<Void, Void, JSONObject> {
#Override
protected JSONObject doInBackground(Integer... params) {
// TODO Auto-generated method stub
UserFunctions u = new UserFunctions();
return u.getNewAdd();
}
#Override
protected void onPostExecute(JSONObject result) {
super.onPostExecute(result);
textSample.setText(result.getString("Something");
}
However, my asyncTask become large and I want to move them to different class (before they were a subclass). Therefor, I wonder how to to update UI ( like setting texviews) when asynctask will be a separete class.
You pass either the Context, Activity, or the individual Views to the AsyncTask's constructor and store them as member variables, then update them on onPostExecute().
Be sure to store Context or Activity as a WeakReference to prevent memory leaks.
If you are going to put the AsyncTask in a separate file, you might be likely to reuse that AsyncTask from other Activities, so I think that the best practise would be to make a callback to the activity so it does all the UI handling.
For doing that what you should do is create an Interface like the following:
public interface OnGetAddCompletedListener {
public void onGetAddCompleted(String text);
}
Receive the callback in the constructor of your AsyncTask and call the method in it in onPostExecute
public class GetAdd extends AsyncTask<Void, Void, JSONObject> {
private OnGetAddCompletedListener callback;
public GetAdd(OnGetAddCompletedListener callback) {
this.callback = callback;
}
#Override
protected JSONObject doInBackground(Integer... params) {
// TODO Auto-generated method stub
UserFunctions u = new UserFunctions();
return u.getNewAdd();
}
#Override
protected void onPostExecute(JSONObject result) {
super.onPostExecute(result);
callback.onGetAddCompleted(result.getString("Something");
}
}
And then, implement the interface in the Activity you are executing it so it handles the UI modifications when you get the data in the AsycTask:
public class SampleActivity extends Activity implements OnGetAddCompletedListener {
TextView textSample;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aadd_addtocheck);
textSample = (TextView) findViewById(R.id.lin);
STask sampleTask = new Stask();
sampleTask.execute();
}
public void onGetAddCompleted(String text) {
textSample.setText(text);
}
}
With this approach, if you decide to reuse that AsyncTask from other activity you will be able to do different things when the AsyncTask has ended in case you want to do so.
You can pass arguments into the constructor of your AsyncTask when you call it. Let's say that in your main activity you have the following:
TextView tv = (TextView) findViewById(R.id.my_text_view);
Stask sampleTask = new Stask(tv);
sampleTask.execute();
When you are creating your AsyncTask, you have:
class Stask extends AsyncTask ...(){
final TextView textView;
public Stask(Textview inputFromOtherClass){
this.textView = inputFromOtherClass;
}
}
This way, the TextView created in your main activity can exist as an instance in your AsyncTask.
EDIT:As someone else posted, you can do something similar for the Context, which is useful in creating various instances.

objects not added to arraylist (asynctask)

In my main activity I got an arraylist called data. I call an asynctask and do some stuff that gives me a different arraylist called values.
In the post execute of the asynctask I want to use items in 'values' to add some objects to 'data'. However, when debugging I noticed that the objects dont get added.
public class MainActivity extends Activity
{
ArrayList<DataItem> data;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
data = new ArrayList<DataItem>();
update();
}
public void update()
{
AsyncCallAWS thisTask = new AsyncCallAWS();
thisTask.execute();
}
private class AsyncCallAWS extends AsyncTask<String, Void, Void>
{
ArrayList<String> values = new ArrayList<String>();
protected void onPostExecute(Void result)
{
Log.i(TAG, "onPostExecute");
DataItem d;
for(String s : values)
{
d = new DataItem();
d.setValue(s);
d.setDataStreamName("test");
data.add(d);
}
}
//code to fill array
I'm guessing it's because I try to add items from the asynctask? Idk how to solve this, I need the data arraylist for a listview.
In AsyncTask class override method onProgressUpdate(), where you will add elements to array. Then in doInBackground() call publishProgress() for sending elements to onProgressUpdate(). Here http://developer.android.com/reference/android/os/AsyncTask.html -is great example.
private class TestAsyncTask extends AsyncTask<Object, String, Object> {
#Override
protected Object doInBackground(Object... params) {
String item = "";
//Do some stuff
publishProgress(item);
return null;
}
#Override
public void onProgressUpdate(String... value) {
data.add(value[0]);
}
#Override
protected void onPostExecute(Object result) {
}
}
I dont think you should create objects in the onPostExecute-method. Instead create it in the doInBackground-method of the class that extends AsyncTask, and then use set-methods in the onPostExecute-metod.

Call AsyncTask from another class

In an existing app I have an activity with an inner class which extends AsyncTask, this looks like the following:
public class Activity_1 extends BaseActivity {
....
new async().execute();
...
public class asyncextends AsyncTask<Void, Void, String> {
protected String doInBackground(Void... progress) { ... }
protected void onPreExecute() { ... }
protected void onPostExecute(String result) { ... }
}
}
Now, I need to call the same doInBackground-method from another activity, but the onPostExecute() of the this inner class operates on some local UI variables and hence it's not possible to use it from outside the clas.
Is there any way I can call this AsyncTask, and just override the onPostExecute andonPreExecute-method, or shall I create yet another inner-class in the other activity, do the same background thing (of course move it to common utility-class or something), etc...?
You can make a separate abstract package private class, extending AsyncTask and implementing doInBackground() method:
abstract class MyAsyncTask extends AsyncTask<Void, Void, String> {
#Override
final protected String doInBackground(Void... progress) {
// do stuff, common to both activities in here
}
}
And in your activities just inherit from MyAsyncTask (new class probably should be private, by the way), implementing onPostExecute() and onPreExecute() methods:
public class Activity_1 extends BaseActivity {
...
new Async1().execute();
...
private class Async1 extends MyAsyncTask {
#Override
protected void onPreExecute(){
// Activity 1 GUI stuff
}
#Override
protected void onPostExecute(String result) {
// Activity 1 GUI stuff
}
}
}
If onPreExecute and onPostExecute contain some common actions as well, you can apply the following pattern:
abstract class MyAsyncTask extends AsyncTask<Void, Void, String> {
public interface MyAsyncTaskListener {
void onPreExecuteConcluded();
void onPostExecuteConcluded(String result);
}
private MyAsyncTaskListener mListener;
final public void setListener(MyAsyncTaskListener listener) {
mListener = listener;
}
#Override
final protected String doInBackground(Void... progress) {
// do stuff, common to both activities in here
}
#Override
final protected void onPreExecute() {
// common stuff
...
if (mListener != null)
mListener.onPreExecuteConcluded();
}
#Override
final protected void onPostExecute(String result) {
// common stuff
...
if (mListener != null)
mListener.onPostExecuteConcluded(result);
}
}
and use it in your activity as following:
public class Activity_1 extends BaseActivity {
...
MyAsyncTask aTask = new MyAsyncTask();
aTask.setListener(new MyAsyncTask.MyAsyncTaskListener() {
#Override
void onPreExecuteConcluded() {
// gui stuff
}
#Override
void onPostExecuteConcluded(String result) {
// gui stuff
}
});
aTask.execute();
...
}
You can also have your Activity implement MyAsyncTaskListener as well:
public class Activity_1 extends BaseActivity implements MyAsyncTask.MyAsyncTaskListener {
#Override
void onPreExecuteConcluded() {
// gui stuff
}
#Override
void onPostExecuteConcluded(String result) {
// gui stuff
}
...
MyAsyncTask aTask = new MyAsyncTask();
aTask.setListener(this);
aTask.execute();
...
}
I wrote the code from the head, so it might contain errors, but it should illustrate the idea.
Its so simple just Simply build an object of main class and than call the inner class like this
OuterMainClass outer = new OuterMainClass();
outer.new InnerAsyncClass(param)
.execute();
this answer is too late to help you but hope it help others.
Thanks
1.Create a constructor of AsynckTask in ClassOne.
2.Crate object or ClassOne by new keyword.
3.Call Async Task by object
ClassOne{
class AsyncParmas extends AsyncTask {
public ADDloadGeofenceDetails() {
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Object doInBackground(Object... params) {
}
}
Class ClassTwo{
ClassOne obj= new ClassOne ();
obj.new AsyncParmas ().execute();
}
}
GoodLuck Who were facing problem.
If we create one static method which is in one class and and will be execute in any class in doInBackground of AsyncTask we can easily update UI through same class and even in different class .

Wait for AsyncTask to finish

Hi I'm making Login page that access MySQL database. But my Activity always runs the code that check fail/success before it finishes the AsyncTask.
I tried using asynctask.get() method, but it just freeze my UI and doesn't work.
I tried this answer that said I should call the result-checker method inside onPostExecute().
But since I need to change the TextView to show success/failed, it results in NullPointerException because I instantiate the TextView inside onCreate().
I can't move the TextView instantiation into constructor because it will return NullPointerException unable to instantiate activity ComponentInfo.
Login.java
public class Login extends Activity{
//declare global Views here
protected void onCreate(Bundle bundle){
//Setup views
}
protected void onClick(View v){
//Setup necessary variables
AsyncClass async = new AsyncClass(this);
async.execute(username, password);
}
public void checkSuccess(boolean success){
if(success)
textView1.setText("Success");
else
textView1.setText("Failed");
}
}
AsyncClass.java
public class AsyncClass extends AsyncTask<String, String, JSONObject>{
protected JSONObject doInBackground(String... params){
//access database
}
protected void onPostExecute(JSONObject json){
//read the json result
Login login = new Login();
login.checkSuccess(true);
}
}
Any solution? Thanks
How about making AsyncTask as your inner class?
So your code should look something like below.
public class Login extends Activity {
//declare global Views here
protected void onCreate(Bundle bundle) {
//Setup views
}
protected void onClick(View v) {
new AsyncClass().execute(username, password);
}
public void checkSuccess(boolean success) {
if (success) textView1.setText("Success");
else textView1.setText("Failed");
}
class AsyncClass extends AsyncTask < String, String, JSONObject > {
protected JSONObject doInBackground(String...params) {
//access database
}
protected void onPostExecute(JSONObject json) {
checkSuccess(true / false);
}
}
}
try this
protected void onPostExecute(JSONObject json){
//read the json result
Login login = (Login)context; // object that you pass to task constructor
login.checkSuccess(true);
}
Also you can add progress dialog to your task to indicate some job execution
public class BaseTask<T> extends AsyncTask<Object, Void, T> {
public Context context;
public ProgressDialog dialog;
public BaseTask(Context context) {
this.context = context;
this.dialog = new ProgressDialog(context);
}
#Override
protected void onPreExecute() {
this.dialog.setMessage(context.getResources().getString(R.string.loading));
this.dialog.show();
}
#Override
protected T doInBackground(Object... objects) {
//....
return something;
}
#Override
protected void onPostExecute(T result) {
if (dialog != null && dialog.isShowing())
dialog.dismiss();
// do something
}
}
You cannot edit the UI from the async task thread. In order to make updates to the UI thread, use the onProgressUpdate() method. This method is part of your AsyncTask class, is actually executed in the main UI Thread (I hope you use the async task as a nested class btw, since it is declared public I guess your not. You should change that). The onProgressUpdate() Method is called by the OS itself if you call publishProgress(...) inside your Async task.
A small sample:
protected JSONObject doInBackground(String... params){
publishProgress("test");
}
/**
* This method is part of the Async Task
*/
protected void onProgressUpdate(String... progress) {
login.checkSuccess(true);
}
I would use it this way, just override your onPostExecute where you need it or create a own interface
//create a object f your asyncclass and
//override the onPostExecute where you need it
mInfo = new ASYNCCLASS({
#Override
public void onPostExecute(Object result){
//doSomething something with your views!
}
}).execute();
Waiting is not the answer, because you do not know how long your Asynctask will take to end.
Code above is not tested, just pseudoce, but it should show what i mean.
Do not have my IDE round here, so if anybody would correct the brackets if neccessary would be great!
Greetz

Android: How to update an UI from AsyncTask if AsyncTask is in a separate class?

I hate inner class.
I've a main activity who launches a 'short-life' AsyncTask.
AsyncTask is in a separate file, is not an inner class of main activity
I need async task updates a textView from main Activity.
I know i can update a TextView from onProgressUpdate, if AsyncTask is a inner class
But how from an external, indipendent, async task ?
UPDATE: This looks like working :
In acitivty i call the task
backgroundTask = new BackgroundTask(this);
backgroundTask.execute();
In the constructor i've
public BackgroundTask(Activity myContext)
{
debug = (TextView) myContext.findViewById(R.id.debugText);
}
where debug was a private field of AsyncTask.
So onProgressUpdate I can
debug.append(text);
Thanks for all of you suggestions
AsyncTask is always separate class from Activity, but I suspect you mean it is in different file than your activity class file, so you cannot benefit from being activity's inner class. Simply pass Activity context as argument to your Async Task (i.e. to its constructor)
class MyAsyncTask extends AsyncTask<URL, Integer, Long> {
WeakReference<Activity> mWeakActivity;
public MyAsyncTask(Activity activity) {
mWeakActivity = new WeakReference<Activity>(activity);
}
...
and use when you need it (remember to NOT use in during doInBackground()) i.e. so when you would normally call
int id = findViewById(...)
in AsyncTask you call i.e.
Activity activity = mWeakActivity.get();
if (activity != null) {
int id = activity.findViewById(...);
}
Note that our Activity can be gone while doInBackground() is in progress (so the reference returned can become null), but by using WeakReference we do not prevent GC from collecting it (and leaking memory) and as Activity is gone, it's usually pointless to even try to update it state (still, depending on your logic you may want to do something like changing internal state or update DB, but touching UI must be skipped).
Using Interface
1) Create one Interface
public interface OnDataSendToActivity {
public void sendData(String str);
}
2) Implements it in your Activity
public class MainActivity extends Activity implements OnDataSendToActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
new AsyncTest(this).execute(new String[]{"AnyData"}); // start your task
}
#Override
public void sendData(String str) {
// TODO Auto-generated method stub
}
}
3) Create constructor in AsyncTask(Activity activity){}
Register your Interface in AsyncTask file
and call interface method as below.
public class AsyncTest extends AsyncTask<String, Integer, String> {
OnDataSendToActivity dataSendToActivity;
public AsyncTest(Activity activity){
dataSendToActivity = (OnDataSendToActivity)activity;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
dataSendToActivity.sendData(result);
}
}
Here, your OnPostExecute will call after all task done by AsyncTask and will get "result"
as a parameter, returned by doInBackground(){ return "";}.
While "dataSendToActivity.sendData(result);" it will call activity's overrided method "public void sendData(String str) {}".
An edge case to remember: Be sure to pass this, i.e. you current activity's context to AsyncTask and not create another instance of your activity, otherwise your Activity will be destroyed and new one is created.
Make an static function in your activity class passing context in it to update your text view and then call this function in your AsynkTask class to update.
In Activity class:
public static void updateTextView(){
//your code here
}
In AynckTask class call this function.
Just pass the context (activity or whatever) to your AsyncTask in a constructor and then in onSuccess or onProgressUpdate call whatever you need on the context.
I wrote a small extension to AsyncTask for this kind of scenario. It allows you to keep your AsyncTask in a separate class, but also gives you convenient access to the Tasks's completion:
public abstract class ListenableAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result>{
#Override
protected final void onPostExecute(Result result) {
notifyListenerOnPostExecute(result);
}
private AsyncTaskListener<Result> mListener;
public interface AsyncTaskListener<Result>{
public void onPostExecute(Result result);
}
public void listenWith(AsyncTaskListener<Result> l){
mListener = l;
}
private void notifyListenerOnPostExecute(Result result){
if(mListener != null)
mListener.onPostExecute(result);
}
}
So first you extend ListenableAsyncTask instead of AsyncTask. Then in your UI code, make a concrete instance and set listenWith(...).
The Question has already been answered, still im posting how it should be done i guess..
Mainactivity class
public class MainActivity extends Activity implements OnClickListener
{
TextView Ctemp;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Ctemp = (TextView) findViewById(R.id.Ctemp);
doConv = (Button) findViewById(R.id.doConv);
doConv.setOnClickListener(this);
}
#Override
public void onClick(View arg0) // The conversion to do
{
new asyncConvert(this).execute();
}
}
now in the async class
public class asyncConvert extends AsyncTask<Void, Void, String>
{
SoapPrimitive response = null;
Context context;
public asyncConvert(Context callerclass)
{
contextGUI = callerclass;
}
.
.
.
.
protected void onPostExecute(String result)
{
((MainActivity) contextGUI).Ctemp.setText(result); // changing TextView
}
}
/**
* Background Async Task to Load all product by making HTTP Request
* */
public static class updateTExtviewAsyncTask extends AsyncTask<String, String, String> {
Context context;
ProgressDialog pDialog;
String id, name;
String state_id;
//--- Constructor for getting network id from asking method
public updateTExtviewAsyncTask(Context context,String id,String city)
{
context = context;
state_id = id;
city_name = city;
}
/* *
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute()
{
super.onPreExecute();
pDialog = ProgressDialog.show(context, "","Please wait...", true, true);
pDialog.show();
}
/**
* getting All products from url
* */
protected String doInBackground(String... args)
{
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url) {
YourClass.UpdateTextViewData("Textview data");
}
}
// place this code inside your activity class and also declare updating textview static
public static void UpdateTextViewData(String tvData)
{
tv.setText(tvData);
}

Categories

Resources