I am a beginner in android. I am trying to control a progressbar with AsyncTask in a class that extends android's inbuilt messenger class. I am getting an Exception but, can't understand the fault in my code.
public class MyMessenger extends Service {
private ProgressDialog downloadProgressDialog;
static final int v1=1,v2=2;
ProgressBar bar;
class MyHandler extends Handler
{
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case v1:
Toast.makeText(getApplicationContext(), "message = 1 in handler of messenger", Toast.LENGTH_LONG).show();
break;
case v2:
new sync().execute();
break;
}
}
}
Messenger messenger=new Messenger(new MyHandler());
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
//Toast.makeText(getApplicationContext(), "binding...", Toast.LENGTH_LONG).show();
return messenger.getBinder();
}
public class sync extends AsyncTask<Void, Integer, Void>
{
int progress=0;
#Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
// super.onProgressUpdate(values);
downloadProgressDialog.setProgress(values[0]);
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
while (progress<100) {
progress++;
publishProgress(progress);
SystemClock.sleep(1000);
}
return null;
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
downloadProgressDialog = new ProgressDialog(getApplicationContext());
downloadProgressDialog.setMessage("Downloading file...");
downloadProgressDialog.setMax(100);
downloadProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
downloadProgressDialog.setCancelable(false);
downloadProgressDialog.show();
}
}
}
Since you are unable to findViewById in service , do the same in your activity that starts the service and make bar as a public static variable.bar is null because you have not initialsed it by findViewById
public static ProgressBar bar = (ProgressBar) findViewById(R.id.progressbar);//in activity
Code in async task
//async task
#Override
protected void onProgressUpdate(Integer... values) {
if(!MyActivityName.bar=null)
MyActivityName.bar.setProgress(values[0]);
super.onProgressUpdate(values);
}
Hope this works.
You never initialize bar, so it is null when you use it at bar.setProgress(values[0]).
because you didn't initialize your progress bar. initialize like below:
bar = (ProgressBar) findViewById(R.id.progressbar);
EDIT:
Then you have to use Progressdialog rather than progress bar like below:
private ProgressDialog downloadProgressDialog;
protected void onPreExecute() {
super.onPreExecute();
downloadProgressDialog = new ProgressDialog(context);
downloadProgressDialog.setMessage("Downloading file...");
downloadProgressDialog.setMax(100);
downloadProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
downloadProgressDialog.setCancelable(false);
downloadProgressDialog.show();
}
and then use dialog object in your progressupdate method.
EDIT:
Via Binder you can send callbacks to your Activity, which means that you can update UI like progress dialog.
Add according method to your Binder (let's name it onProgress)
From your AsyncTask call method of this Binder
In order to know about progress updates consider using Observer pattern (in other words - your Activity should listen for updates of your Binder, or more specifically - of calling Binder.onProgress method)
You can not to show progress dialog , You have extend service class that is used to run thread in background. just use only doinbackground() method, remove progress dialog method
.
Related
I have created an AsyncTask. I want to pair with a bluetooth device, and only after pairing it should go to next activity. My code is
public class YourTask extends AsyncTask<String, Void, Void>
{
public BluetoothDevice d;
#Override
protected Void doInBackground(String... urls)
{
//pairDevice(d);
return null;
}
public void onPreExecute()
{
pairDevice(d);
}
#Override
protected void onPostExecute(Void result)
{
Context context = getApplicationContext();
int duration = Toast.LENGTH_SHORT;
CharSequence text = "Pairing";
Toast toast = Toast.makeText(context, text, duration);
toast.show();
startActivity(new Intent(NewDeviceActivity.this,DevicesActivity.class));
finish();
}
}
void pairDevice(BluetoothDevice device) {
try {
Method m = device.getClass()
.getMethod("createBond", (Class[]) null);
m.invoke(device, (Object[]) null);
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
The onPostExecute function gets executed even before pairDevice function has finished. Please help
The onPostExecute() method gets triggered after the tasks in doInBackground() have been completed. In your example you are not executing any tasks in doInBackground(), resulting in onPostExecute() to be called immediately. Move your method pairDevice(BluetoothDevice device) into the doInBackground() method and it should work.
Background Long operations should be done only in doInBackground method. This is the actual flow.
#Override
public void onPreExecute()
{
// this executes before Background operation starts
// here you can start showing ProgressBar to let the users know that it's still doing the work and you can dismiss in onPostExecute
}
#Override
protected Void doInBackground(String... urls)
{
// here you should do the long operation
return null;
}
#Override
protected void onPostExecute(Void result)
{
// here you can update the UI or move to other activity after long task has been done
}
The problem is, you are trying to run Background operation in onPreExecute.
public void onPreExecute()
{
pairDevice(d);
}
Just move the pairDevice(d) method to doInBackground method which is not correct.
I was sitting 5 hours on one code with AyncTask which was not running properly. I just created another simple Activity (because in last one onPostExecute() wasn't working) and now this simple Activity is also not starting the AsyncTask. Can anyone see what I'm doing wrong?
public class ServerStatus extends Activity {
Context context;
private ProgressDialog pd;
int a;
TextView test;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.server_status);
context=this;
test=(TextView) findViewById(R.id.welcomemessage);
new Download().execute();
}
public class Download extends AsyncTask<Void, Void, Void>{
protected Void onPreExecute(Void... arg0) {
pd = new ProgressDialog(context);
pd.setTitle("Processing...");
pd.setMessage("Please wait.");
pd.setCancelable(false);
pd.setIndeterminate(true);
pd.show();
return null;
}
#Override
protected Void doInBackground(Void... arg0) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
a++;
return null;
}
protected Void onPostExecute(Void... arg0) {
if (pd!=null)
pd.dismiss();
test.setText(a);
return null;
}
}
}
Also, does NavigationDrawer block UI thread? Because I can't even update TextView when I implement it.
The methods aren't correct. You should add the #Override annotation to them so it will yell at you when doing it wrong.
onPreExecute() doesn't take any params so it should be
#Override
protected Void onPreExecute() {
also change the param type of `onPostExecute() to
#Override
protected Void onPostExecute(Void arg0) {
Remove the "..." See Varargs for an explanation.
Docs
Post explaining AsyncTask and getting values
those params in the class declaration are for doInBackground(), onProgressUpdate(), and onPostExecute()
As far as the NavDrawer, I'm not sure what issue you are having with that.
You need to change your code in onPreExecute
pd = new ProgressDialog(context);
to
pd = new ProgressDialog(getActivity());
I am trying to re-initiate the entire function of download and uppdate service when an AsyncTask in my activity is being called but I am not sure if I am doing something wrong. Currently, I have a refresh button that initiates the AsyncTask:
Refresh function that initiates AsyncTask:
final ImageView refreshBtn= (ImageView) findViewById(R.id.spin_refresh);
Log.i("RootActivity:setupHeader","******ImageView refreshBtn******");
//Listening to Button Click by User
refreshBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i("RootActivity:setupHeader","******OnClick,Call RefreshTask******");
//CALL ON THE CLASS OF REFRESHTASK ASYNCTASK
RefreshTask refreshtask = new RefreshTask();
refreshtask.execute();
}
});
Once my refresh function is called, it will call onto the refreshtask within my activity:
public class RefreshTask extends AsyncTask <Void,Integer,Long> implements Observer{
// SET THE PARAMETERS FOR REFRESHTASK IN ASYNCTASK: PRE-EXECUTION, PROGRESS UPDATES & POST-EXECUTION
private Context context=null;
private DownloadService callback =null;
protected boolean exitAsync = false;
public static Hashtable<String, Download> downloadList;
final public static String PATH = "/sdcard/DCIM/100MEDIA/";
private static final Long START_STICKY = null;
Intent intent;
ListView lv;
RelativeLayout rl;
protected String dSResponse = null;
public void UIThreadProgress(Context context, DownloadService callback) {
this.context = context;
this.DownloadService = DownloadService;
}
//PROCESS IN CALLING THE DOWNLIST WHILE IN BACKGROUND
protected Long doInBackground(Void...params){
// TODO Auto-generated method stub
Log.i("----------RefreshAsyncTask----------", "doInBackground");
try {
// ====================DownloadService
Thread.sleep(10000);
while (this.callback.condition())
Intent i= new Intent(context.this, UpdateService.class);
Intent I= new Intent(context.this,DownloadService.class);
// potentially add data to the intent
context.this.startService(i);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}while (!exitAsync);
return START_STICKY;
}
#Override
public void update(Observable observable, Object data) {
// TODO Auto-generated method stub
//UpdateServiceStatus
}
//HANDLES EVENTS ON THE UI-POST-EXECUTE
#Override
protected void onPostExecute(Long result){
super.onPostExecute(result);
lv.findViewById(R.id.spin_refresh).setVisibility(View.VISIBLE);
Log.i("----------RefreshAsyncTask----------", "onPostExecute");
//GIVE FEEDBACK ON THE USER INTERFACE
Toast.makeText(context, "Your document has been refreshed and contains the updated documents!", Toast.LENGTH_LONG).show();
// After the process in doInBackground has been completed
}
}
Please help, I am trying to re-instantiate the download and update service when AsyncTask is being called.
I can't understand why you start a service inside a thread. You should start a thread in a service instead. Check Local Service sample in this link:
http://developer.android.com/reference/android/app/Service.html
In your onClickListener just unbind service and bind it again. It will refresh your service. In onCreate method of your service start your download or update in a thread.
Note: It is better to use another thread mechanism for network service. AsyncTask is good for short-lived operations.
#Override
protected void onPostExecute(Long result){
super.onPostExecute(result);
lv.findViewById(R.id.spin_refresh).setVisibility(View.VISIBLE);
Log.i("----------RefreshAsyncTask----------", "onPostExecute");
//GIVE FEEDBACK ON THE USER INTERFACE
Toast.makeText(context, "Your document has been refreshed and contains the updated documents!", Toast.LENGTH_LONG).show();
RefreshTask refreshtask = new RefreshTask();
refreshtask.execute();
// After the process in doInBackground has been completed
}
In my acivity, i need to run two background service.
main background service:
class loadingTask extends AsyncTask<Void, Void,Void> {
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
pd = ProgressDialog.show(context, "", "Chargement en cours..", true, false);
super.onPreExecute();
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
pd.dismiss();
}
...
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
getxml = Util.CallWebService("");
return null;
}
}
Second background service.
class mloadingTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
SAXHelper sh = null;
try {
sh = new SAXHelper(urls[0]);
} catch (MalformedURLException e) {
e.printStackTrace();
}
sh.parseContent("");
return "";
}
protected void onPostExecute(String s) {
pd.dismiss();
}
}
In my onCreate() method I want to call the first background and when it finished loading the second background service starts. Part of my background service is as follows.
AsyncTask<Void, Void,Void> loadTask = new loadingTask().execute();
if(loadTask.getStatus()==AsyncTask.Status.FINISHED){
new mloadingTask().execute(getxml);
System.out.println("getxml: "+getxml);
}
However the second background service doesn't seem to start. i am not getting the a print also. I think I miss a step or android doesn't allow more than one background service in the same activity. A help please.
AsyncTask<Void, Void,Void> loadTask = new loadingTask().execute();
if(loadTask.getStatus()==AsyncTask.Status.FINISHED){
new mloadingTask().execute(getxml);
System.out.println("getxml: "+getxml);
}
there is a 99% chance that the if() block will never pass.
You first execute the first asyncTask named loadTask and RIGHT after check if it finished.
Small chance that it actually finishes by then.
The easy approach:
Use only one async task. You want to finish asyncTask 1 and then fire asyncTask 2, its exactly the same as having only one asyncTask doing both operations.
class loadingTask extends AsyncTask<Void, Void,Void> {
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
pd = ProgressDialog.show(context, "", "Chargement en cours..", true, false);
super.onPreExecute();
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
pd.dismiss();
}
...
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
getxml = Util.CallWebService("");
SAXHelper sh = null;
try {
sh = new SAXHelper(urls[0]);
} catch (MalformedURLException e) {
e.printStackTrace();
}
sh.parseContent("");
return null;
}
}
The difficult approach:
How I solve this kind of thing is(our situation is different, but it should do)
Create an interface, with one method. for example:
public interface OnDataChangedListner {
void dataChanged(Class listener);
}
Then somewhere (i use my repository classes)
write a method to add and remove entires to a list of OnDataChangedListener interfaces
private ArrayList<OnDataChangedListner> mOnDataChangedListners;
public void addOnDataChangedListner(OnDataChangedListner onDataChangedListner){
synchronized (mOnDataChangedListners){
mOnDataChangedListners.add(onDataChangedListner);
}
}
public void removeOnDataChangedListner(OnDataChangedListner onyDataChangedListner){
if (mOnDataChangedListners != null){
synchronized (mOnDataChangedListners){
for (Iterator<OnDataChangedListner> it = mOnDataChangedListners.iterator(); it.hasNext();) {
OnDataChangedListner listener = it.next();
if (listener .equals(onDataChangedListner))
it.remove();
}
}
}
}
This might be overkill. But this example should help you with updating the UI while your tasks are running. A free extra! :))
With the above code in place, create an onDataChanged() method in the same class where u defined the add and remove listener methods.
In that code call a handler
// Need handler for callbacks to the UI thread
final static Handler mHandler = new Handler();
// Create runnable for posting
final Runnable mNotifyDataChanged = new Runnable() {
public void run() {
if (mOnDataChangedListners != null){
synchronized (mOnDataChangedListners){
for (Iterator<OnDataChangedListner> it = mOnDataChangedListners.iterator(); it.hasNext();) {
OnDataChangedListner listener = it.next();
if (listener != null)
listener.dataChanged(this.getClass());
else
it.remove();
}
}
}
}
};
/**
* will notify registerred delegates on the main (UI) thread
*/
public void notifyDataChanged(){
mHandler.post(mNotifyDataChanged);
}
Ok, so I ended up giving out an entire sample.
Where you place this code is upto you. But when you call notifyDataChanged() it will fire the handler, which in turn will loop trough all current registered listeners for this class
then in turn it will call the listeners datachanged method.
To make this all work, all you have to do is have a class implement the interface
call addOnDataChangedListener(this);
and implement the method provided in the interface.
Note that this is deffinetly not the easiest way to do things.
I don't know what the easiest way to do what you want is. I never have been in that situation before.
but you can execute the second task in the implemented method. Should work..
AsyncTask is Asynchronous as its name suggest. You need to call your 2nd AsyncTask in onPostExecute of your 1st AsyncTask
OR
Loop and wait till AsyncTask is finished in your activity, but it may take more time and you can get Application Not Responding message.
As soon as you call execute() method, control comes to next statement which loadTask.getStatus(). As task is just started, loadTask.getStatus() will not return FINISH and your 2nd task is never getting executed.
In my application when i click on Button it sometimes shows the progressdialog and sometimes not show the progressdialog on click of button.
Asynchronous Task code is:
public class LoadData extends AsyncTask<Void, Void, Void>
{
ProgressDialog pd;
#Override
protected void onPreExecute()
{
pd = ProgressDialog.show(MainActivity.this, "", "Loading...");
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
// TODO Auto-generated method stub
LoadActivities(); // function to load data from url
}
});
return null;
}
#Override
protected void onPostExecute(Void unused)
{
pd.dismiss();
}
}
and on button click event call this as:
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
new LoadMoreData().execute(null);
}
});
the wrong think you are doing is that in doInBackground you use runOnUiThreade . just remove that from your code . It solves your problem.
never use any thread in doInBackground.
Why you have taken run method again in doInBackground, doInBackground method performs computation on a background thread, so no need to take runOnUiThread
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
// TODO Auto-generated method stub
LoadActivities(); // function to load data from url
}
});
Just write
protected Boolean doInBackground(final String... args) {
try {
LoadActivities();
return true;
} catch (Exception e) {
Log.e("tag", "error", e);
return false;
}
}
And also change new LoadMoreData().execute(); don't write null
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
new LoadMoreData().execute();
}});
Nirali's answer seems correct, just to make further explaination and some edits.
Progress Dialog will be shown by the time doInBackground method returns value. and in your code it just create another thread, and completes execution, so to display progress dialog by the time LoadActivities exectues, execute this statement in the same thread doInBackground executes, so change to following:
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
MainActivity.this.runOnUiThread(new Runnable() {
LoadActivities(); // function to load data from url
return null;
}