Android : how to implement PullToRefreshListView in proper way - android

i am new to Android and currently start learning how to implement PullToRefreshListview by using this library of chrisbanes. can you guys please explain to me, where should i put my code to call API for getting data, and which part should i set the(ImageBitmap) after i get the data (image URL) from API. as i know, we should do something in background to avoid the UI freeze when loading Image to UI, but i am not sure. Please help.
The following is the sample code from the library:
please explain to me what should i do in GetDataTask and onPostExecute. In the case like loading image.
#Override
public void onRefresh(PullToRefreshBase<ListView> refreshView) {
// Do work to refresh the list here.
new GetDataTask().execute();
}
private class GetDataTask extends AsyncTask<Void, Void, String[]> {
#Override
protected String[] doInBackground(Void... params) {
// Simulates a background job.
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
}
return mStrings;
}
#Override
protected void onPostExecute(String[] result) {
mListItems.addFirst("Added after refresh...");
mAdapter.notifyDataSetChanged();
// Call onRefreshComplete when the list has been refreshed.
mPullRefreshListView.onRefreshComplete();
super.onPostExecute(result);
}
}
Sorry for the newbie question, i jsust want to confirm it in order to follow the standard. sorry for my bad english

I think you should put your GetDataTask in a separated class with a Listener. This is an example of a listener you can have:
public abstract class RemoteCallListener implements IRemoteCallListener {
#Override
public abstract void onString(String s); //String is just an example.
#Override
public abstract void onError(Exception e);
}
You should give the listener to your constructor if your async task.
private class GetDataTask extends AsyncTask<Void, Void, String[]> {
RemoteCallListener listener;
public GetDataTask(){
}
public GetDataTask(RemoteCallListener listener){
this.listener = listener;
}
#Override
protected String[] doInBackground(Void... params) {
// Simulates a background job.
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
}
return mStrings;
}
#Override
protected void onPostExecute(String[] result) {
listener.onString(result);
// mListItems.addFirst("Added after refresh...");
// mAdapter.notifyDataSetChanged();
// Call onRefreshComplete when the list has been refreshed.
// mPullRefreshListView.onRefreshComplete();
super.onPostExecute(result);
}
}
To make an instance of the call you should do something like
GetDataTask task = new GetDataTask(yourlistener);
task.execute("your link");
And in your 'controller'class you should make an instance of RemoteCallListener and when onString is called:
mListItems.addFirst("Added after refresh...");
mAdapter.notifyDataSetChanged();
// Call onRefreshComplete when the list has been refreshed.
mPullRefreshListView.onRefreshComplete();
You can also freeze the UI by the Dialogs class from android. An example is given here:
public final static ProgressDialog showLoading(Context c, String title,
String message, boolean indeterminate) {
ProgressDialog p = new ProgressDialog(c);
p.setTitle(title);
p.setMessage(message);
p.setCancelable(false);
p.setIndeterminate(indeterminate);
if (!indeterminate) {
// p.setProgressDrawable( c.getResources().getDrawable(
// R.drawable.progress ) );
p.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
p.setProgress(0);
p.setMax(100);
}
p.show();
return p;
}
But dont forget to close your Dialog!
You can contact me anytime if you have further questions

GetDataTask is used to call your webservice again to get the new list items. These things should be done in doInBackground. Once you get the new list item need to set the new adapter for your listview in onPostExecute.

Related

Android listview best practice with AsyncTask

I want to develop an Android application which asks a server for some data, and displays these data in a ListView.
Currently, I am using a single Activity (without fragments), and the layout is very simple: it consists of an ImageView, an EditText and a ListView. When the ImageView is clicked it gets the content of the EditText and sends it to the server as a new item and automatically updates the Listview (am calling the method of retreiving the objects after the add operation).
I created an AsyncTask class with a progress dialog inside the Activity which the job in background is getting the objects from the server and then assigning them to a List (member of the enclosing class).
With that practice, am facing a lot of problems: the list gets displayed correctly but very slowly! and when I press the ImageView the AsyncTask is then called to do its job after adding the new item but the problem is that its dialog never dismisses.
My question is what is the best practice with this situation in Android? what is the best design pattern? should I use fragments? How should I manage my Threads?
UDATE:
here is the AsyncTask:
class RemoteDataTask extends AsyncTask<Void, Void, Void> {
private UserDetailsActivity context;
RemoteDataTask(UserDetailsActivity context) {
this.context = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();;
mProgressDialog = ProgressDialog.show(context, "Looking for posts", "Loading...", true, false);
}
#Override
protected Void doInBackground(Void... params) {
UserDetailsActivity.this.posts.clear();
posts = new PostManager(context).userPosts(ParseUser.getCurrentUser());
return null;
}
#Override
protected void onPostExecute(Void result) {
postList = (ListView) findViewById(R.id.post_list);
adapter = new PostsListAdapter(context, UserDetailsActivity.this.posts);
postList.setAdapter(adapter);
mProgressDialog.dismiss();
}
}
And the method wich retreives the posts:
public void refreshPostList() {
try {
BusInfo.getInstance().register(UserDetailsActivity.this); // register the Bus to recieve results.
} catch (Exception e) {
Log.d("My application says : ;) ", "Erro registering " + e);
}
pd = ProgressDialog.show(this, "Please Wait", "Loading");
new ExprienceEdit(this, "hello").execute();
}
And the Button with its method
public void newPost(View v) {
ParseObject post = new ParseObject("Post");
post.put("content", editText.getText().toString());
post.saveInBackground();
refreshPostList();
}
<ImageView
android:id="#+id/new_post"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:onClick="newPost"
android:padding="10dp"
android:src="#drawable/ic_action_post" />
Regarding the progress dialog not being dismissed:
Where is mProgressDialog dialog declared? I suggest you move it into the RemoteDataTask. (I'm guessing you are at some point overriding the current instance and therefore the dismiss isn't working)
Regarding the slow refresh of the list, post your Adapter code. You should do correct recycling of views and you shouldn't recreate the Adapter everytime but set the data and call notifyDataSetChanged so the listView will recycle the views with the new data. Look into this answer regarding correct recycling of views: https://stackoverflow.com/a/6923513/348378
Edit 1
I also suggest this to prevent having multiple refreshTasks:
public void refreshPostList() {
if(dataTask == null) {
dataTask = new RemoteDataTask(this).execute();
}
}
#Override
protected void onPostExecute(Void result) {
// you stuff
dataTask = null;
}
You can also consider cancelling the current task and starting a new one depending on required behavior.
you should pass ProgressDialog to your AsyncTask class constructor and in any class that want to use AsyncTask class(in your case RemoteDataTask) you should instantiate progress dialog and pass as second argument to your RemoteDataTask to control the visibility from specific custom class.
maybe this help.
The best way to deal with asynctasks is by using otto :
Otto actually is a singltone bus : please refer to this website http://square.github.io/otto/
Any piece of code would be great to help you more with the problem you are facing.
Any questions I am ready to answer.
BusInfo.getInstance.register(ActivityName.this) // register the Bus to recieve results.
pd = ProgressDialog.show(ActivityName.this, "Please Wait", "Loading");
new ExperienceEdit(getApplicationContext(), "hello").execute(); //async task to be executed let us say on button click
Now the experience edit is:
public class ExperienceEdit extends AsyncTask<Void, Void, String> {
Context c;
String id;
public ExperienceEdit(Context c, String id\) {
this.c = c;
this.id = id;
}
#Override
protected String doInBackground(Void... voids) {
//right the call to back here
}
#Override
public void onPostExecute(String result) {
try {
BusInfo.getInstance().post(new ExperienceEditResult(result));
} catch (Exception e) {
e.printStackTrace();
}
}
}
The result after posting is subscribed at the activity like this :
#Subscribe
public void onAsyncTaskResult(EditExperienceResult result) {
if (pd != null)
pd.dismiss();
object = result.getResult();
if (object != null) {
if (object.equals("success")) {
Toast.makeText(getApplicationContext(), "Success", Toast.LENGTH_SHORT).show();
onBackPressed();
} else Toast.makeText(getApplicationContext(), "Failure", Toast.LENGTH_SHORT).show();
} else
Toast.makeText(getApplicationContext(), "Please try again later", Toast.LENGTH_SHORT).show();
}
The ExperienceEditResult here happens to be a string (you can have it whatever you want) :
public class ExperienceEditResult {
private String result;
public ExperienceEditResult(String result) {
this.result = result;
}
public String getResult() {
return result;
}
}
The BusInfo class is :
public class BusInfo {
private static final Bus BUS = new Bus();
public static Bus getInstance() {
return BUS;
}
}
Do not forget to unregister the bus onDestroy of the activity: BusInfo.getInstance().unregister(ActivityName.this);
If you aslso want to prevent the progress dialogue from always showing because sometimes it is showing twice due to a double click on button add this : if(pd!=null&&pd.isShowing()){
Log.v("pd is showing","showing");
} else {pd= ProgressDialgue.show...}

How to call notifyDataSetChanged() from AsyncTask onPostExecute() in another class

In onCreate() I am calling a class ChannelStore to create a singleton and my fragment's listview is using that dataset created by channelstore. Once the doInBackground() finishes I need to call notifyDateSetChanged() on the adapter but I am not sure how to accomplish that being that my AsyncTask is in one class (ChannelStore) and the adapter is in my fragment (ChannelListFragment). Can someone lead me to the solution?
ChannelListFragment:
public class ChannelListFragment extends ListFragment {
private static final String TAG = "ChannelListFragment";
public ArrayList<Channel> mChannels;
public ChannelAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().setTitle(R.string.channels_title);
setHasOptionsMenu(true);
try {
mChannels = ChannelStore.get(getActivity()).getChannels();
} catch (XmlPullParserException | IOException | InterruptedException
| ExecutionException | TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
adapter = new ChannelAdapter(mChannels);
setListAdapter(adapter);
}
...
public class ChannelAdapter extends ArrayAdapter<Channel> {
public ChannelAdapter(ArrayList<Channel> channels) {
super(getActivity(), 0, channels);
}
The AsyncTask in ChannelStore:
private class ChannelSetup extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
try {
// download xml feed
}
#Override
protected void onPostExecute(String result) {
try {
// parse xml feed
....
Log.i(TAG, "Adding programmes to channels...");
addProgrammes(mProgrammes);
Log.i(TAG, "Programmes per channel: "
+ listChannelsProgrammes(mChannels));
// need to update listview adapter somehow
}
If in onPostExecute you can access your dataset created by channelstore and your adapter, you can change your dataset and update your adapter by calling notifyDateSetChanged(). another way to do it is use
runOnUiThread(new Runnable() {
public void run() {
// your code to update adapter.
}
});
in every where that you need to access ui thread to update something.
your onPostExecute always runs on UI thread so you have access your fragment adapter. in order to do that you can use
getFragmentManager().getFragmentByTag('your fragment tag').ChannelAdapter.notifyDataSetChanged()

AsyncTask cannot update progress when slowly creating an object in background

I know how to use AsyncTask to download file, create a zip file or so.. as I call publishProgress() in my loop.
I got stuck when doInBackground() has a single slow line, no loops here, just creating an object where its constructor has slow loops.
I'm not sure about the reasonable way of updating progress in such case.
Here's a sample code:
public class Session {
private QQActivity activity;
public int createdParts;
public DailyClass daily;
private void checkDaily() {
if(!isDailyReady){
new SetAsyncQQDaily().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
class SetAsyncQQDaily extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
String sdq = null;
daily = new DailyClass(Session.this); //Very very Slow!
// Do other network http
sdq = new String(Base64.encode(bos.toByteArray(),Base64.DEFAULT));
// Do some work
return sdq;
}
#Override
protected void onPostExecute(String sdq) {
//Never mind
}
#Override
protected void onPreExecute() {
Toast.makeText(activity,"Preparing the daily. Get ready!",Toast.LENGTH_LONG).show();
}
#Override
protected void onProgressUpdate(Void... values) {
//TODO: Update Value of leftBar
activity.leftBar.setProgress((100*createdParts)/Utils.DAILY_PART_COUNT);
}
}
}
In the slow constructor class, I can set-back an integer of the current progress: createdParts, but cannot call publishProgress.
public class DailyClass implements Serializable {
public DailyClass(Session session){
for(int i=1;i<=partCount;i++ ){ //Very slow loop
session.createdParts = i; //TODO: reflect value to progress bar!?
for(int j=0;j<questionsCount;j++){
objects[i-1][j] = createDefined(i);
}
Log.d("Daily","created part"+i);
}
}
//Bla .. !
}
I also though of passing the object of the AsyncTask to the slow constructor in order to call publishProgress() from there, but cannot. As publishProgress() is accessible only from doInBackground()
What's the best practice?

How update UI within AsyncTask

I want download details from web and update the UI within the doInBackground(),
For that I think I must get reference to activity within that method .How can I do it or is there another way to do that? What must be the something parameter? Or can’t update UI real-time?
public class DownloadActivity extends ListActivity {
public class DownloadItems extends AsyncTask<Something,Integer,Long> {
#Override
protected Long doInBackground(DownloadActivity... params) {
Toast.makeText(params[0], getIntent().getExtras().get("location").toString(), Toast.LENGTH_SHORT).show();
return null;
}
}
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
new DownloadItems().execute(Something);
}
}
You can either use a Handler or update your UI in onPostExecute(), which I recommend. Let your Async take care of its background logic and update the UI when that work is finished.
The best way is to simply move anything which affects UI into onPostExecute() because it's there to allow you to update the UI, it's the point of it.
There are other ways but when using AsyncTask there's really no reason not to use this.
public class DownloadActivity extends ListActivity {
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
new DownloadItems(this).execute();
}
public class DownloadItems extends AsyncTask<Something,Integer,Long> {
private Context context;
public DownloadItems(Context c){
context = c;
}
#Override
protected Long doInBackground(DownloadActivity... params) {
// Do something
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Toast.makeText(context, context.getIntent().getExtras().get("location").toString(), Toast.LENGTH_SHORT).show();
}
}
}
You can create a constructor for passing or adding Context as a parameter.
public class DownloadItems extends AsyncTask<Something,Integer,Long> {
Context context;
public DownloadItems(Context cntx){
context = cntx;
}
#Override
protected Long doInBackground(DownloadActivity... params) {
//Toast.makeText(params[0], getIntent().getExtras().get("location").toString(), Toast.LENGTH_SHORT).show();
Toast.makeText(context, "String test", Toast.LENGTH_SHORT).show();
return null;
}
}
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
new DownloadItems(this).execute(Something);
}
By passing the context of the activity you can make any operation that are context related.
You can't execute UI operations in doInBackground(), you must do them in onPostExecute(). In DownloadActivity, you will create an instance of DownloadItems, and pass it the url where you want to download your stuff :
For example :
public class DownloadActivity extends ListActivity {
private void someMethod() {
DownloadItems yourTask = new DownloadItems(getApplicationContext());
yourTask.execute(yourUrl);
}
In the AsyncTask, you will do your download operations in doInBackground() and return the result so it can be handled by onPostExecute() :
public class DownloadItems extends AsyncTask<Something,Integer,Long> {
Context mContext;
public DownloadItems(Context context){
mContext = context;
}
#Override
protected String doInBackground(String... params) {
String theResult;
// download operations using url stored in params[0], and where you set theResult variable (for example...)
return theResult;
}
In onPostExecute(), you deal with the result, for example in your code above, you can call the Toast :
#Override
protected void onPostExecute(String result) {
Toast.makeText("YOUR TAG", result, Toast.LENGTH_SHORT).show();
}
You can call this in doInBackground:
runOnUiThread(new Runnable() {
public void run() {
//Your code
}
});
But isn't right... Please read the AsyncTask for more details, or use the onPostExecute to update UI...

How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?

I have this two classes. My main Activity and the one that extends the AsyncTask, Now in my main Activity I need to get the result from the OnPostExecute() in the AsyncTask. How can I pass or get the result to my main Activity?
Here is the sample codes.
My main Activity.
public class MainActivity extends Activity{
AasyncTask asyncTask = new AasyncTask();
#Override
public void onCreate(Bundle aBundle) {
super.onCreate(aBundle);
//Calling the AsyncTask class to start to execute.
asyncTask.execute(a.targetServer);
//Creating a TextView.
TextView displayUI = asyncTask.dataDisplay;
displayUI = new TextView(this);
this.setContentView(tTextView);
}
}
This is the AsyncTask class
public class AasyncTask extends AsyncTask<String, Void, String> {
TextView dataDisplay; //store the data
String soapAction = "http://sample.com"; //SOAPAction header line.
String targetServer = "https://sampletargeturl.com"; //Target Server.
//SOAP Request.
String soapRequest = "<sample XML request>";
#Override
protected String doInBackground(String... string) {
String responseStorage = null; //storage of the response
try {
//Uses URL and HttpURLConnection for server connection.
URL targetURL = new URL(targetServer);
HttpURLConnection httpCon = (HttpURLConnection) targetURL.openConnection();
httpCon.setDoOutput(true);
httpCon.setDoInput(true);
httpCon.setUseCaches(false);
httpCon.setChunkedStreamingMode(0);
//properties of SOAPAction header
httpCon.addRequestProperty("SOAPAction", soapAction);
httpCon.addRequestProperty("Content-Type", "text/xml; charset=utf-8");
httpCon.addRequestProperty("Content-Length", "" + soapRequest.length());
httpCon.setRequestMethod(HttpPost.METHOD_NAME);
//sending request to the server.
OutputStream outputStream = httpCon.getOutputStream();
Writer writer = new OutputStreamWriter(outputStream);
writer.write(soapRequest);
writer.flush();
writer.close();
//getting the response from the server
InputStream inputStream = httpCon.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
ByteArrayBuffer byteArrayBuffer = new ByteArrayBuffer(50);
int intResponse = httpCon.getResponseCode();
while ((intResponse = bufferedReader.read()) != -1) {
byteArrayBuffer.append(intResponse);
}
responseStorage = new String(byteArrayBuffer.toByteArray());
} catch (Exception aException) {
responseStorage = aException.getMessage();
}
return responseStorage;
}
protected void onPostExecute(String result) {
aTextView.setText(result);
}
}
Easy:
Create interface class, where String output is optional, or can be whatever variables you want to return.
public interface AsyncResponse {
void processFinish(String output);
}
Go to your AsyncTask class, and declare interface AsyncResponse as a field :
public class MyAsyncTask extends AsyncTask<Void, Void, String> {
public AsyncResponse delegate = null;
#Override
protected void onPostExecute(String result) {
delegate.processFinish(result);
}
}
In your main Activity you need to implements interface AsyncResponse.
public class MainActivity implements AsyncResponse{
MyAsyncTask asyncTask =new MyAsyncTask();
#Override
public void onCreate(Bundle savedInstanceState) {
//this to set delegate/listener back to this class
asyncTask.delegate = this;
//execute the async task
asyncTask.execute();
}
//this override the implemented method from asyncTask
#Override
void processFinish(String output){
//Here you will receive the result fired from async class
//of onPostExecute(result) method.
}
}
UPDATE
I didn't know this is such a favourite to many of you. So here's the simple and convenience way to use interface.
still using same interface. FYI, you may combine this into AsyncTask class.
in AsyncTask class :
public class MyAsyncTask extends AsyncTask<Void, Void, String> {
// you may separate this or combined to caller class.
public interface AsyncResponse {
void processFinish(String output);
}
public AsyncResponse delegate = null;
public MyAsyncTask(AsyncResponse delegate){
this.delegate = delegate;
}
#Override
protected void onPostExecute(String result) {
delegate.processFinish(result);
}
}
do this in your Activity class
public class MainActivity extends Activity {
MyAsyncTask asyncTask = new MyAsyncTask(new AsyncResponse(){
#Override
void processFinish(String output){
//Here you will receive the result fired from async class
//of onPostExecute(result) method.
}
}).execute();
}
Or, implementing the interface on the Activity again
public class MainActivity extends Activity
implements AsyncResponse{
#Override
public void onCreate(Bundle savedInstanceState) {
//execute the async task
new MyAsyncTask(this).execute();
}
//this override the implemented method from AsyncResponse
#Override
void processFinish(String output){
//Here you will receive the result fired from async class
//of onPostExecute(result) method.
}
}
As you can see 2 solutions above, the first and third one, it needs to create method processFinish, the other one, the method is inside the caller parameter. The third is more neat because there is no nested anonymous class.
Tip: Change String output, String response, and String result to different matching types in order to get different objects.
There are a few options:
Nest the AsyncTask class within your Activity class. Assuming you don't use the same task in multiple activities, this is the easiest way. All your code stays the same, you just move the existing task class to be a nested class inside your activity's class.
public class MyActivity extends Activity {
// existing Activity code
...
private class MyAsyncTask extends AsyncTask<String, Void, String> {
// existing AsyncTask code
...
}
}
Create a custom constructor for your AsyncTask that takes a reference to your Activity. You would instantiate the task with something like new MyAsyncTask(this).execute(param1, param2).
public class MyAsyncTask extends AsyncTask<String, Void, String> {
private Activity activity;
public MyAsyncTask(Activity activity) {
this.activity = activity;
}
// existing AsyncTask code
...
}
You can try this code in your Main class.
That worked for me, but i have implemented methods in other way
try {
String receivedData = new AsyncTask().execute("http://yourdomain.com/yourscript.php").get();
}
catch (ExecutionException | InterruptedException ei) {
ei.printStackTrace();
}
I felt the below approach is very easy.
I have declared an interface for callback
public interface AsyncResponse {
void processFinish(Object output);
}
Then created asynchronous Task for responding all type of parallel requests
public class MyAsyncTask extends AsyncTask<Object, Object, Object> {
public AsyncResponse delegate = null;//Call back interface
public MyAsyncTask(AsyncResponse asyncResponse) {
delegate = asyncResponse;//Assigning call back interfacethrough constructor
}
#Override
protected Object doInBackground(Object... params) {
//My Background tasks are written here
return {resutl Object}
}
#Override
protected void onPostExecute(Object result) {
delegate.processFinish(result);
}
}
Then Called the asynchronous task when clicking a button in activity Class.
public class MainActivity extends Activity{
#Override
public void onCreate(Bundle savedInstanceState) {
Button mbtnPress = (Button) findViewById(R.id.btnPress);
mbtnPress.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MyAsyncTask asyncTask =new MyAsyncTask(new AsyncResponse() {
#Override
public void processFinish(Object output) {
Log.d("Response From Asynchronous task:", (String) output);
mbtnPress.setText((String) output);
}
});
asyncTask.execute(new Object[] { "Your request to aynchronous task class is giving here.." });
}
});
}
}
Thanks
This answer might be late but I would like to mention few things when your Activity dependent on AsyncTask. That would help you in prevent crashes and memory management. As already mentioned in above answers go with interface, we also say them callbacks. They will work as an informer, but never ever send strong reference of Activity or interface always use weak reference in those cases.
Please refer to below screenshot to findout how that can cause issues.
As you can see if we started AsyncTask with a strong reference then there is no guarantee that our Activity/Fragment will be alive till we get data, so it would be better to use WeakReference in those cases and that will also help in memory management as we will never hold the strong reference of our Activity then it will be eligible for garbage collection after its distortion.
Check below code snippet to find out how to use awesome WeakReference -
MyTaskInformer.java Interface which will work as an informer.
public interface MyTaskInformer {
void onTaskDone(String output);
}
MySmallAsyncTask.java AsyncTask to do long running task, which will use WeakReference.
public class MySmallAsyncTask extends AsyncTask<String, Void, String> {
// ***** Hold weak reference *****
private WeakReference<MyTaskInformer> mCallBack;
public MySmallAsyncTask(MyTaskInformer callback) {
this.mCallBack = new WeakReference<>(callback);
}
#Override
protected String doInBackground(String... params) {
// Here do whatever your task is like reading/writing file
// or read data from your server or any other heavy task
// Let us suppose here you get response, just return it
final String output = "Any out, mine is just demo output";
// Return it from here to post execute
return output;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
// Here you can't guarantee that Activity/Fragment is alive who started this AsyncTask
// Make sure your caller is active
final MyTaskInformer callBack = mCallBack.get();
if(callBack != null) {
callBack.onTaskDone(s);
}
}
}
MainActivity.java This class is used to start my AsyncTask implement interface on this class and override this mandatory method.
public class MainActivity extends Activity implements MyTaskInformer {
private TextView mMyTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMyTextView = (TextView) findViewById(R.id.tv_text_view);
// Start your AsyncTask and pass reference of MyTaskInformer in constructor
new MySmallAsyncTask(this).execute();
}
#Override
public void onTaskDone(String output) {
// Here you will receive output only if your Activity is alive.
// no need to add checks like if(!isFinishing())
mMyTextView.setText(output);
}
}
You can do it in a few lines, just override onPostExecute when you call your AsyncTask. Here is an example for you:
new AasyncTask()
{
#Override public void onPostExecute(String result)
{
// do whatever you want with result
}
}.execute(a.targetServer);
I hope it helped you, happy codding :)
in your Oncreate():
`
myTask.execute("url");
String result = "";
try {
result = myTask.get().toString();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}`
Why do people make it so hard.
This should be sufficient.
Do not implement the onPostExecute on the async task, rather implement it on the Activity:
public class MainActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState) {
//execute the async task
MyAsyncTask task = new MyAsyncTask(){
protected void onPostExecute(String result) {
//Do your thing
}
}
task.execute("Param");
}
}
You can call the get() method of AsyncTask (or the overloaded get(long, TimeUnit)). This method will block until the AsyncTask has completed its work, at which point it will return you the Result.
It would be wise to be doing other work between the creation/start of your async task and calling the get method, otherwise you aren't utilizing the async task very efficiently.
You can write your own listener. It's same as HelmiB's answer but looks more natural:
Create listener interface:
public interface myAsyncTaskCompletedListener {
void onMyAsynTaskCompleted(int responseCode, String result);
}
Then write your asynchronous task:
public class myAsyncTask extends AsyncTask<String, Void, String> {
private myAsyncTaskCompletedListener listener;
private int responseCode = 0;
public myAsyncTask() {
}
public myAsyncTask(myAsyncTaskCompletedListener listener, int responseCode) {
this.listener = listener;
this.responseCode = responseCode;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String result;
String param = (params.length == 0) ? null : params[0];
if (param != null) {
// Do some background jobs, like httprequest...
return result;
}
return null;
}
#Override
protected void onPostExecute(String finalResult) {
super.onPostExecute(finalResult);
if (!isCancelled()) {
if (listener != null) {
listener.onMyAsynTaskCompleted(responseCode, finalResult);
}
}
}
}
Finally implement listener in activity:
public class MainActivity extends AppCompatActivity implements myAsyncTaskCompletedListener {
#Override
public void onMyAsynTaskCompleted(int responseCode, String result) {
switch (responseCode) {
case TASK_CODE_ONE:
// Do something for CODE_ONE
break;
case TASK_CODE_TWO:
// Do something for CODE_TWO
break;
default:
// Show some error code
}
}
And this is how you can call asyncTask:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Some other codes...
new myAsyncTask(this,TASK_CODE_ONE).execute("Data for background job");
// And some another codes...
}
Hi you can make something like this:
Create class which implements AsyncTask
// TASK
public class SomeClass extends AsyncTask<Void, Void, String>>
{
private OnTaskExecutionFinished _task_finished_event;
public interface OnTaskExecutionFinished
{
public void OnTaskFihishedEvent(String Reslut);
}
public void setOnTaskFinishedEvent(OnTaskExecutionFinished _event)
{
if(_event != null)
{
this._task_finished_event = _event;
}
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
#Override
protected String doInBackground(Void... params)
{
// do your background task here ...
return "Done!";
}
#Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
if(this._task_finished_event != null)
{
this._task_finished_event.OnTaskFihishedEvent(result);
}
else
{
Log.d("SomeClass", "task_finished even is null");
}
}
}
Add in Main Activity
// MAIN ACTIVITY
public class MyActivity extends ListActivity
{
...
SomeClass _some_class = new SomeClass();
_someclass.setOnTaskFinishedEvent(new _some_class.OnTaskExecutionFinished()
{
#Override
public void OnTaskFihishedEvent(String result)
{
Toast.makeText(getApplicationContext(),
"Phony thread finished: " + result,
Toast.LENGTH_SHORT).show();
}
});
_some_class.execute();
...
}
Create a static member in your Activity class. Then assign the value during the onPostExecute
For example, if the result of your AsyncTask is a String, create a public static string in your Activity
public static String dataFromAsyncTask;
Then, in the onPostExecute of the AsyncTask, simply make a static call to your main class and set the value.
MainActivity.dataFromAsyncTask = "result blah";
I make it work by using threading and handler/message.
Steps as follow:
Declare a progress Dialog
ProgressDialog loadingdialog;
Create a function to close dialog when operation is finished.
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
loadingdialog.dismiss();
}
};
Code your Execution details:
public void startUpload(String filepath) {
loadingdialog = ProgressDialog.show(MainActivity.this, "Uploading", "Uploading Please Wait", true);
final String _path = filepath;
new Thread() {
public void run() {
try {
UploadFile(_path, getHostName(), getPortNo());
handler.sendEmptyMessage(0);
} catch (Exception e) {
Log.e("threadmessage", e.getMessage());
}
}
}.start();
}
You need to use "protocols" to delegate or provide data to the AsynTask.
Delegates and Data Sources
A delegate is an object that acts on behalf of, or in coordination with, another object when that object encounters an event in a program. (Apple definition)
protocols are interfaces that define some methods to delegate some behaviors.
Here is a complete example!!!
try this:
public class SomAsyncTask extends AsyncTask<String, Integer, JSONObject> {
private CallBack callBack;
public interface CallBack {
void async( JSONObject jsonResult );
void sync( JSONObject jsonResult );
void progress( Integer... status );
void cancel();
}
public SomAsyncTask(CallBack callBack) {
this.callBack = callBack;
}
#Override
protected JSONObject doInBackground(String... strings) {
JSONObject dataJson = null;
//TODO query, get some dataJson
if(this.callBack != null)
this.callBack.async( dataJson );// asynchronize with MAIN LOOP THREAD
return dataJson;
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
if(this.callBack != null)
this.callBack.progress(values);// synchronize with MAIN LOOP THREAD
}
#Override
protected void onPostExecute(JSONObject jsonObject) {
super.onPostExecute(jsonObject);
if(this.callBack != null)
this.callBack.sync(jsonObject);// synchronize with MAIN LOOP THREAD
}
#Override
protected void onCancelled() {
super.onCancelled();
if(this.callBack != null)
this.callBack.cancel();
}
}
And usage example:
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Context _localContext = getContext();
SomeAsyncTask.CallBack someCallBack = new SomeAsyncTask.CallBack() {
#Override
public void async(JSONObject jsonResult) {//async thread
//some async process, e.g. send data to server...
}
#Override
public void sync(JSONObject jsonResult) {//sync thread
//get result...
//get some resource of Activity variable...
Resources resources = _localContext.getResources();
}
#Override
public void progress(Integer... status) {//sync thread
//e.g. change status progress bar...
}
#Override
public void cancel() {
}
};
new SomeAsyncTask( someCallBack )
.execute("someParams0", "someParams1", "someParams2");
}
Probably going overboard a bit but i provided call backs for both the execution code and the results. obviously for thread safety you want to be careful what you access in your execution callback.
The AsyncTask implementation:
public class AsyncDbCall<ExecuteType,ResultType> extends AsyncTask<ExecuteType, Void,
ResultType>
{
public interface ExecuteCallback<E, R>
{
public R execute(E executeInput);
}
public interface PostExecuteCallback<R>
{
public void finish(R result);
}
private PostExecuteCallback<ResultType> _resultCallback = null;
private ExecuteCallback<ExecuteType,ResultType> _executeCallback = null;
AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback, PostExecuteCallback<ResultType> postExecuteCallback)
{
_resultCallback = postExecuteCallback;
_executeCallback = executeCallback;
}
AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback)
{
_executeCallback = executeCallback;
}
#Override
protected ResultType doInBackground(final ExecuteType... params)
{
return _executeCallback.execute(params[0]);
}
#Override
protected void onPostExecute(ResultType result)
{
if(_resultCallback != null)
_resultCallback.finish(result);
}
}
A callback:
AsyncDbCall.ExecuteCallback<Device, Device> updateDeviceCallback = new
AsyncDbCall.ExecuteCallback<Device, Device>()
{
#Override
public Device execute(Device device)
{
deviceDao.updateDevice(device);
return device;
}
};
And finally execution of the async task:
new AsyncDbCall<>(addDeviceCallback, resultCallback).execute(device);
Hope you been through this , if not please read.
https://developer.android.com/reference/android/os/AsyncTask
Depending on the nature of result data, you should choose best possible option you can think of.
It is a great choice to use an Interface
some other options would be..
If the AsyncTask class is defined inside the very class you want to
use the result in.Use a static global variable or get() , use it from
outer class (volatile variable if necessary). but should be aware of the AsyncTask progress or should at least make sure that it have finished the task and result is
available through global variable / get() method. you may use
polling, onProgressUpdate(Progress...), synchronization or interfaces (Which ever suits best for you)
If the Result is compatible to be a sharedPreference entry or it is okay to be saved as a file in the memory you could save it even from
the background task itself and could use the onPostExecute() method
to get notified when the result is available in the memory.
If the string is small enough, and is to be used with start of an
activity. it is possible to use intents (putExtra()) within
onPostExecute() , but remember that static contexts aren't that safe
to deal with.
If possible, you can call a static method from the
onPostExecute() method, with the result being your parameter

Categories

Resources