I'm searching some pages from facebook and then downloading their pictures.
i want to view them immediately in my list and update the adapter everytime i download a new picture. i'm using the same method in one other activity and it works, but here i'm using a dialog and it freeze my UI till everything is finished, even if i'm doing it in background. why?
private synchronized void getUserLikesImages() {AsyncTask<Void, Void, Bitmap> task = new AsyncTask<Void, Void, Bitmap>() {
#Override
public Bitmap doInBackground(Void... params) {
for(...){
//download one picture...
FacebookeventsActivity.this.runOnUiThread(new Runnable() {
public void run() {
pagesILikeArrayAdapter.notifyDataSetChanged();
}
});
}
};
task.execute();
}
it works, but the UI is frozen till the end of the operations... i think it might be because my list is in a dialog and i'm running it on UIThread, but i don't know how to fix it.
#Override
public Bitmap doInBackground(Void... params) {
for(...){
//download one picture...
}
};
#Override
onPostExecute()
{
pagesILikeArrayAdapter.notifyDataSetChanged();
}
Just add onPostExecute() and notify adapter from that.. Or just Add onProgreesUpdate() method and use publishProgress() from doInBackGround()
notify adapter periodically from that..
Related
I retrieve Object from internet but when pass it directly to the BaseAdapter the Scrolling ListView is very slow and not smoothly.
In the following I had asked this question:
List view crashes when scrolling "The application may be doing too much work on its main thread."
I want to ask how can create AsyncTask to retrieve data and pass it to the adapter
to make it faster and scrolling smoothly.
Do as this example
to execute task
new LongOperation().execute("");
and the task is like this.
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
for(int i=0;i<5;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed"); // txt.setText(result);
//might want to change "executed" for the returned string passed into onPostExecute() but that is upto you
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
DoinBackground method is where you are doing your downloading data from server. and on postexecute assign that data to base adapter. and mind one thing is that you can't update views from DoinBackground method. you can have to use UIThread for changing Views.
Hope it Helps!!!
The best way is to download data in AsyncTask before you create your adapter and set it to ListView.
But nevertheless if you need to download data when your ListView is already created, then you, as #Arman Stranger said before you need to implement all work functions inside doInbackgound().
F.e. when you have downloaded picture you should resize it to smaller size and execute notifyDataSetChanged() to redraw your listview.
There's a "download" button in each listview item. While the button is clicked, it will start a worker thread to down files. And at the same time, the button changed to progressbar and showing the progress rate.
So please show me some proper ways.
Use an AsyncTask since it has special methods for communicating with the main (UI) thread despite being asynchronous.
Here is an example:
http://android-er.blogspot.com/2010/11/progressbar-running-in-asynctask.html
Something like this:
public class DownloadTask extends AsyncTask<Void, Void, Boolean> {
protected void onPreExecute() {
ProgressDialog() progress = new ProgressDialog(context);
progress.setMessage("Loading ...");
progress.show();
}
protected Boolean doInBackground(Void... arg0) {
// Do work
return true;
}
protected void onPostExecute(Boolean result) {
progress.dismiss();
}
}
This should be nested in your activity class and executed like this:
new DownloadTask().execute();
You will likely need to adjust the asynctask to fit your needs but this will get you started.
I have a button, and when I clicked on it, I load other Activity, onCreate of this I call a method that fills a spinner with data from a Web Service.
Well, When I click at this button the screen stay "frozen" and then shows the Activity. So, I thought that it could be a good thing shows a progress dialog for user, and after gets the return of the Web Service, ends the progress dialog.
I tried use Handler, and now I'm trying to use AsyncTask, but, geting NullPointerException, because my program is filling spinner before web service get called.
private void fillSpinner(){
//runWebService();
new CallWebServiceAsyncTask().execute(null);
mAdapter = new PlanesAdapter(this, allPlanes);
mList.setAdapter(mAdapter);
}
class CallWebServiceAsyncTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(PlanesActivity.this);
progressDialog.setMessage("Loading...");
progressDialog.show();
}
#Override
protected Void doInBackground(Void... v) {
runWebService();
return null;
}
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
}
}
because my program is filling spinner before web service get called.
you should fill data after getting data in onPostExecute Method
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
mAdapter = new PlanesAdapter(this, allPlanes);
mList.setAdapter(mAdapter);
}
What #SamirMangroliya suggested is correct but you even need to know where you are going wrong. When you call an AsyncTask you are asking the application to do some actions in the background which will take place in the non-UI thread. Now when you call execute() on your AsyncTask object the application code written in the function doInBackground(Void... v) runs in background and your control returns to the next statement following the call to execute() [new CallWebServiceAsyncTask().execute(null)], which in your case is the action of filling the adapter values. These values are yet to be received from the webservice. The only place where you can be sure that your background action is completed is the function onPostExecute(Void result) where as suggested you can create your adapter.
The goal:
Using Google App Engine server and Android client, I'm trying to put on the Google map at the Android client Users overlays. Every 30 seconds I'm polling the server and getting Vector that contains users and adding it to the map.
Current status:
I'm dong all that using in one new thread, So after running the app I got:
weird behaviors(delayed overlays, multiple overlays) and after that crushed with ConcurrentModificationException.
After reading a bit i figured out that I need to work with AsyncTask.
Correct me if I'm wrong,But I understand that everything done in the Activity at at onCreate is "running" in UIhread so I need to put the "Logic" (All the Network handling) in doInBackground and all the UI Handling like putting overlays on the map in onPostExecute.
My Question are:
1) In the current status I'm doing:
new Thread()
{
#Override
public void run()
{
super.run();
while(true)
{
SystemClock.sleep(30000);
Vector responseFromServer = getUsersVectorFromServer();
putNewOnlineUserOnTheMap();
}
}
}.start();
What is the right way to convert this To AsyncTask?
Do I poll the server still using new thread in the doInBackground or there is right way to do this?
2) Is there a specific list of what counts as UI to put in onPostExecute or any concepts list?
In my case I guess that in need to put putNewOnlineUserOnTheMap() in onPostExecute.
Thanks.
Something similar to the following:
class UpdateTask extends AsyncTask<Void, Vector, Void>{
#Override
protected Void doInBackground(Void... params) {
// this is running in a background thread.
while (!isCancelled()) {
SystemClock.sleep(30000);
Vector responseFromServer = getUsersVectorFromServer();
// send the result back to the UI thread
// onProgressUpdate will be called then
publishProgress(responseFromServer);
}
return null;
}
#Override
protected void onProgressUpdate(Vector... values) {
// this is executed on the UI thread where we can safely touch UI stuff
putNewOnlineUserOnTheMap(values[0]);
}
}
You can't use the result of the task since the task is finished then. But you can use the progress publishing mechanism to get periodic results. If you use it like that and do the modification on the UI thread you should not get ConcurrentModificationException because you do the modifications on the one thread that can safely modify the UI.
One thing to note here: create new instances of your Vector in the background thread and then use it to update the UI. But don't touch the same object afterwards in the backgroundthread. That way you don't need any synchronization since after the background thread sends it away it is only the UI thread that touches it. (and you could use a simple ArrayList instead of a Vector)
AsyncTask uses generics and varargs.The parameters that are passed to the asyntask are . TypeOfVariableArgumentsParameters is passed into the doInBackground(), ProgressParam is used for progress information and ResultParam must be returned from doInBackground() and is passed to onPostExecute() as parameter.
example:--
protected class ParsingTask extends AsyncTask> {
private ProgressDialog loadingDialog = new ProgressDialog(JsonParserActivity.this);
protected void onPreExecute() {
loadingDialog.setMessage("loading app store..");
loadingDialog.show();
}
#Override
protected ArrayList<Items> doInBackground( Context... params ) {
// do ur process here.
return result;
}
if (!this.isCancelled()) {
}
return result;
}
#Override
protected void onProgressUpdate(String... s) {
super.onProgressUpdate(s);
Toast.makeText(getApplicationContext(), s[0], Toast.LENGTH_SHORT).show();
}
#Override
protected void onPostExecute( ArrayList<Items> response ) {
//if u r dealing with list view and adapters set the adapter here at the onPostExecute()
loadingDialog.dismiss();
}
#Override
protected void onCancelled() {
super.onCancelled();
Toast.makeText(getApplicationContext(), "The operation was cancelled", 1).show();
}
}
You can use AsyncTask like below. Hope this will help you..
Class YourClass{
void YourClass(){
NetworkTask nT = new NetworkTasK();
nT.execute();
}
}
protected class NetworkTask extends AsyncTask<Void, String, Boolean>
{
#Override
protected Boolean doInBackground(Void... params)
{
try
{
String response;
while(keepreceiving)
{
response = in.readLine();//Prog Counter stops here until getting i/p.
if(response != null)
yourFunctionForResponse(response);
}
}
catch (Exception ex)
{
}
return null;
}
private void yourFunctionForResponse(String response){
//things to do....
}
}
You may also try runOnUiThread(Runnable action) along with this to implement your work.
I am trying to retrieve JPGs from an MJPG Stream using an async task. I first thought, i could let the task continuously be running and just letting the buffered JPGs pop up in the onProgressUpdate() method. But this doesn't seem to work, because the method only displays integers, no drawables...what I tried:
private class StreamTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
image = readMJPGStream();
return null;
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
imView.setImageDrawable(image); // << doesn't work
}
}
Do you have any ideas? What approach should I try?
Thank you very much in advance!
Huck
When you start a AsyncTask, the doInBackground is called, but it is only run once. I'm not sure what readMJPGStream does, but assuming it blocks until an image is retrieved, its certainly possible that onProgressUpdate gets called several times while your image is still null, then once image get set to something valid and doInbackground quickly exits, there are no further calls to OnProgressUpdate.
You should probably put the call to imView.setImageDrawable in onPostExecute to make sure it gets called when the image has been downloaded. You may also need to call invalidate() on your image view to ensure it gets redrawn. Additionally, if you intend to loop and continue downloading images, you'll need to devise a mechanism of triggering updates. In reality, the issue you're having is because you want 'on demand' get on the UI Thread, but you're dependent on calls to onProgressUpdate. You'd have much better luck using a Handler and your own Runnable/Thread because then when an image download completes, you can post to the UI thread (using the Handler) without having to wait for the onProgressUpdate.
I now got it running this way:
public class StreamActivity extends Activity implements Runnable{
// ...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imView = (ImageView) findViewById(R.id.imView);
Thread thread = new Thread(this);
thread.start();
}
#Override
public void run() {
while (connected){
image = readMJPGStream();
handler.sendEmptyMessage(0);
}
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
imView.setImageDrawable(image);
}
};
public Drawable readMJPGStream() {
//...
return image;
}
}
The only problem is that my while loop is not fast enough. Any ideas are very much appreciated!
Huck