I have written progress bar when I consume WCF part. I have to know after get response it need to dismiss.
ProgressThread progThread;
ProgressDialog progDialog;
int typeBar; // Determines type progress bar: 0 = spinner, 1 = horizontal
int delay = 40; // manually define thedelay
int maxBarValue = 200; // manually define the maximum value
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case 0:
typeBar = 0;
showDialog(typeBar);
return true;
case 1:
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
protected Dialog onCreateDialog(int id) {
// Spinner
progDialog = new ProgressDialog(this);
progDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progDialog.setMessage("Loading...");
progThread = new ProgressThread(handler);
progThread.start();
return progDialog;
}
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
int total = msg.getData().getInt("total");
progDialog.setProgress(total);
if (total <= 0){
dismissDialog(typeBar);
progThread.setState(ProgressThread.DONE);
}
}
};
This is thread class
private class ProgressThread extends Thread {
final static int DONE = 0;
final static int RUNNING = 1;
Handler mHandler;
int mState;
int total;
ProgressThread(Handler h) {
mHandler = h;
}
#Override
public void run() {
mState = RUNNING;
total = maxBarValue;
while (mState == RUNNING) {
try {
loadDownloadData();
Thread.sleep(delay);
} catch (InterruptedException e) {
Log.e("ERROR", "Thread was Interrupted");
}
Message msg = mHandler.obtainMessage();
Bundle b = new Bundle();
b.putInt("total", total);
msg.setData(b);
mHandler.sendMessage(msg);
total--;
}
}
public void setState(int state) {
mState = state;
}
}
WCF call method is loadDownloadData(); , Where want to call & how we can define the time frame for sleep, after getting response only it need to dismis this progress bar...
Please help me
Thanks in advance.
What exactly should your method do?
At the moment it looks like you are calling some method in loop and after that you sleep a thread. If your loadDownloadData calls the WCF it will be called in each cycle? If it doesn't start asynchronous processing it will wait until the method completes and only after that it will continue to sleeping the thread.
If you want to have progress bar for downloading content over WCF you cannot use such approach. First the whole WCF call must run asynchronously. Next you need to know amount of downloaded data upfront and you need to read data continuously - only that will allow you to control real progress bar. Normal HTTP processing will write all data to the server, pass them to the network, load all data to the buffer on the client and after that your method return the result - from client API such operation is atomic (= you cannot measure progress). This is usually avoided by chunked data where server pushes data in chunks and client is able to read these chunks like a stream. In WCF it is performed by streaming transfer mode.
At the moment you should simply use some unlimited spinner and wait for operation to complete.
Related
my app does heavy task so I want to show a progress bar to user and run the task in background, so user can understand that its loading.
when the background task completes hide the progress bar.
But progress bar should not take same time to reach its max, it should be dependent on users input or processing.
Use AsyncTask. AsyncTask is one of the easiest ways to implement parallelism in Android without having to deal with more complex methods like Threads. Though it offers a basic level of parallelism with the UI thread, it should not be used for longer operations (of, say, not more than 2 seconds).
AsyncTask has four methods do the task:
onPreExecute()
doInBackground()
onProgressUpdate()
onPostExecute()
Check link for more details.
You can create something like this, the process ends in 30 seconds. I hope it will be useful to you
private ProgressDialog progressDialog;
public void init() {
progressDialog = new ProgressDialog(context);
progressDialog.setCancelable(false);
progressDialog.setMessage("please wait");
progressDialog.show();
new Thread(new Runnable() {
#Override
public void run() {
while (time < 30) {
try {
Thread.sleep(1000);
Message message = new Message();
message.what = UPDATE_PROGRESS;
handler.sendMessage(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Message message = new Message();
message.what = END_PROGRESS;
handler.sendMessage(message);
}
}).start();
}
private static final int UPDATE_PROGRESS = 1;
private static final int END_PROGRESS = 2;
private int time;
private Handler handler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_PROGRESS:
progressDialog.setMessage("Time: " + time++);
break;
case END_PROGRESS:
progressDialog.dismiss();
break;
default:
break;
}
return true;
}
});
UPDATE
This is the thread and handler example. But you can also create an asynctask
I am using this code to play a sound
final MediaPlayer mp = MediaPlayer.create(this, R.raw.sound);
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
It works fine on its own, however there was a problem after I added an animation that extends ImageView, which refreshes(by calling handler.postDelayed) the image resource at an interval about 30ms to create animation. The problem is that when the animation starts, it terminates the the playing of the sound. Here is the code for the Runnable that refreshes the ImageView.
private Runnable runnable = new Runnable () {
public void run() {
String name = "frame_" + frameCount;
frameCount ++;
int resId = mContext.getResources().getIdentifier(name, "drawable", mContext.getPackageName());
imageView.setImageResource(resId);
if(frameCount < totalFrameCount) {
mHandler.postDelayed(runnable, interval);
}
}
};
I also tried to use a thread that calls the anmiationView.postInvalidate to do the animation, however it has the same problem. Please help. Thanks
Edit:
It looks like the problem is due to WHEN the animation is called. Previously I called it in the onActivityResult of the activity. Looks like this is not the right place to call. Now I put the animation view in a popupWindow and play it there, it works properly. Not sure exactly why.
in handler's comments :
"A Handler allows you to send and process {#link Message} and Runnable
objects associated with a thread's {#link MessageQueue}. Each Handler
instance is associated with a single thread and that thread's message
queue. When you create a new Handler, it is bound to the thread /
message queue of the thread that is creating it -- from that point on,
it will deliver messages and runnables to that message queue and execute
them as they come out of the message queue."
so, the problem may be caused by both of animation and media playing operations are in
the same message queue own by which thread create the handler (let's say the main thread).
if the animation loops for ever, then the media player will hardly get any chance to run.
you could take it a try with HandlerThread, the thread will contain a new looper for the
handler created from it, all the runnables added to that handler will be running in another
individual thread.
the animation thread and the media play thread should be running in the different threads not
scheduling in the same one.
hope, it helps.
the HandlerThread usage and some discuss looks like this :
How to create a Looper thread, then send it a message immediately?
maybe it is caused by your miss arranged codes, i take it a try on my nexus 4 with android version 4.4.2, even no any cache tech, the animation and music works like a charm...
here is the major codes :
public class MainActivity extends Activity implements View.OnClickListener {
protected static final String TAG = "test002" ;
protected static final int UPDATE_ANI = 0x0701;
protected static final int UPDATE_END = 0x0702;
protected static final int[] ANI_IMG_IDS = {R.raw.img1, R.raw.img2, R.raw.img3, R.raw.img4,
R.raw.img5, R.raw.img6, R.raw.img7};
protected static final int[] BTN_IDS = {R.id.btnStart, R.id.btnStop};
protected android.os.Handler aniHandler = null; // async update
protected boolean isAniRunning = false ;
protected int aniImgIndex = 0 ;
protected ImageView aniImgView = null ;
protected MediaPlayer mediaPly = null ;
// animation timer
class AniUpdateRunnable implements Runnable {
public void run() {
Message msg = null ;
while (!Thread.currentThread().isInterrupted() && isAniRunning) {
msg = new Message();
msg.what = UPDATE_ANI;
aniHandler.sendMessage(msg);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break ;
}
}
msg = new Message() ;
msg.what = UPDATE_END ;
aniHandler.sendMessage(msg) ;
}
}
protected void prepareMediaPlayer(MediaPlayer mp, int resource_id) {
AssetFileDescriptor afd = getResources().openRawResourceFd(resource_id);
try {
mp.reset();
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength());
afd.close();
mp.prepare();
} catch (IllegalArgumentException e) {
Log.d(TAG, "IlleagalArgumentException happened - " + e.toString()) ;
} catch(IllegalStateException e) {
Log.d(TAG, "IllegalStateException happened - " + e.toString()) ;
} catch(IOException e) {
Log.d(TAG, "IOException happened - " + e.toString()) ;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// init : buttons onclick callback
{
Button btn;
int i;
for (i = 0; i < BTN_IDS.length; i++) {
btn = (Button) findViewById(BTN_IDS[i]);
btn.setOnClickListener(this);
}
}
// init : update animation handler callback
{
aniHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_ANI:
updateAniImages();
break ;
case UPDATE_END:
updateAniEnd();
break ;
default:
break;
}
}
};
}
// init : prepare image view
{
aniImgView = (ImageView)findViewById(R.id.imgAni) ;
mediaPly = MediaPlayer.create(this, R.raw.happyny) ;
mediaPly.setLooping(true);
}
}
protected void updateAniImages() {
if(aniImgIndex >= ANI_IMG_IDS.length) {
aniImgIndex = 0 ;
}
InputStream is = getResources().openRawResource(ANI_IMG_IDS[aniImgIndex]) ;
Bitmap bmp = (Bitmap) BitmapFactory.decodeStream(is) ;
aniImgView.setImageBitmap(bmp);
aniImgIndex++ ;
}
protected void updateAniEnd() {
aniImgIndex = 0 ;
aniImgView.setImageBitmap(null);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnStart:
isAniRunning = true ;
// no re-enter protectiion, should not be used in real project
new Thread(new AniUpdateRunnable()).start();
mediaPly.start();
break;
case R.id.btnStop:
isAniRunning = false ;
mediaPly.stop();
prepareMediaPlayer(mediaPly, R.raw.happyny);
break;
default:
break;
}
}
}
the major project codes and test apk should be find here :
apk installer
source code
In my app i manage to determine is there connection or not, but i want that application itself try to reconnect 5 times, and every time to increase the interval between to reconnects m i did some code, but its not working, he give me response immediate.
Here is my reconnect class:
public class ReestablishConnection {
Application APP = new Application();
boolean status;
int reconnectInterval = 1000;
int i;
public boolean reconnect(String URL){
Thread timer = new Thread(){
public void run(){
for(i=1;i<6;i++){
if(APP.testConnection(APP.defaultUrl()) == 0){
status = false;
}else if(APP.testConnection(APP.defaultUrl()) == 1){
status = true;
}
try {
sleep(reconnectInterval * i);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
return status;
}
}
You create a new thread, which sleeps for a while, but the method which spawned it (reconnect) will return immediately. You should be using a Handler with postDelayed().
Take a look at the answer here:
How to run a Runnable thread in Android?
Sleep is used too often. The correct design is to implement a listener for when a connection is available and respond to listener callback in your UI.
I have a Async Task that does not add the percentage while it is going through the task. It always stays at 0% 0/100
Here is my code
private class getAppInfo extends AsyncTask<String, String, String> {
/** The system calls this to perform work in a worker thread and
* delivers it the parameters given to AsyncTask.execute() */
ProgressDialog dialog;
#Override
protected void onPreExecute() {
if(showLoading == true){
dialog = new ProgressDialog(SelfHelp.this);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setMessage("Loading");
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.setMax(100);
dialog.setProgress(100);
dialog.show();
}
}
#Override
protected String doInBackground(String... urls) {
String xml = null;
int count = 0;
try {
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(urls[0]);
HttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
xml = EntityUtils.toString(httpEntity);
while(count != 100){
publishProgress(""+count);
count += 5;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Document doc = parser.GetDomElement(xml);
NodeList nl = doc.getElementsByTagName("topic");
getChildElements(nl);
return xml;
}
#Override
protected void onProgressUpdate(String... progress) {
Log.v("count",progress[0]);
dialog.setProgress(Integer.parseInt(progress[0]));
}
/** The system calls this to perform work in the UI thread and delivers
* the result from doInBackground() */
#Override
protected void onPostExecute(String result) {
//dialog.setProgress(100);
menuList.setAdapter(setListItems(menuItems));
menuList.setTextFilterEnabled(true);
if(showLoading == true){
dialog.dismiss();
showLoading = false;
}
}
It does go into onProgressUpdate and the count goes up by 5 but the progress bar does not change. How can I have it increment by 5 and show the progress properly?
Your issue is related to setIndeterminate(true): You should set it to false if you want to have progress update. if you setIndeterminate(true) then the ProgressDialog will work as the classic Windows Hourglass
You can try following code, It is showing progress in % ratio, here is the code,
public class ProgressBarExampleActivity extends Activity
{
ProgressThread progThread;
ProgressDialog progDialog;
Button button1, button2;
int typeBar; // Determines type progress bar: 0 = spinner, 1 = horizontal
int delay = 1000; // Milliseconds of delay in the update loop
int maxBarValue = 30; // Maximum value of horizontal progress bar
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// // Process button to start spinner progress dialog with anonymous inner class
// button1 = (Button) findViewById(R.id.Button01);
// button1.setOnClickListener(new OnClickListener()
// {
// public void onClick(View v)
// {
// typeBar = 0;
// showDialog(typeBar);
// }
// });
// Process button to start horizontal progress bar dialog with anonymous inner class
button2 = (Button) findViewById(R.id.Button02);
button2.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
typeBar = 1;
showDialog(typeBar);
}
});
}
// Method to create a progress bar dialog of either spinner or horizontal type
#Override
protected Dialog onCreateDialog(int id)
{
switch(id)
{
// case 0: // Spinner
// progDialog = new ProgressDialog(this);
// progDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
// progDialog.setMessage("Loading...");
// progThread = new ProgressThread(handler);
// progThread.start();
// return progDialog;
case 1: // Horizontal
progDialog = new ProgressDialog(this);
progDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progDialog.setMax(maxBarValue);
progDialog.setMessage("Dollars in checking account:");
progThread = new ProgressThread(handler);
progThread.start();
return progDialog;
default:
return null;
}
}
// Handler on the main (UI) thread that will receive messages from the
// second thread and update the progress.
final Handler handler = new Handler()
{
public void handleMessage(Message msg)
{
// Get the current value of the variable total from the message data
// and update the progress bar.
int total = msg.getData().getInt("total");
progDialog.setProgress(total);
// if (total >= maxBarValue)
if (total <= 0 )
{
dismissDialog(typeBar);
progThread.setState(ProgressThread.DONE);
}
}
};
// Inner class that performs progress calculations on a second thread. Implement
// the thread by subclassing Thread and overriding its run() method. Also provide
// a setState(state) method to stop the thread gracefully.
private class ProgressThread extends Thread
{
// Class constants defining state of the thread
final static int DONE = 0;
final static int RUNNING = 1;
Handler mHandler;
int mState;
int total;
// Constructor with an argument that specifies Handler on main thread
// to which messages will be sent by this thread.
ProgressThread(Handler h)
{
mHandler = h;
}
// Override the run() method that will be invoked automatically when
// the Thread starts. Do the work required to update the progress bar on this
// thread but send a message to the Handler on the main UI thread to actually
// change the visual representation of the progress. In this example we count
// the index total down to zero, so the horizontal progress bar will start full and
// count down.
#Override
public void run()
{
mState = RUNNING;
total = maxBarValue;
while (mState == RUNNING)
{
// The method Thread.sleep throws an InterruptedException if Thread.interrupt()
// were to be issued while thread is sleeping; the exception must be caught.
try
{
// Control speed of update (but precision of delay not guaranteed)
Thread.sleep(delay);
} catch (InterruptedException e) {
Log.e("ERROR", "Thread was Interrupted");
}
// Send message (with current value of total as data) to Handler on UI thread
// so that it can update the progress bar.
Message msg = mHandler.obtainMessage();
Bundle b = new Bundle();
b.putInt("total", total);
msg.setData(b);
mHandler.sendMessage(msg);
total--; // Count down
}
}
// Set current state of thread (use state=ProgressThread.DONE to stop thread)
public void setState(int state)
{
mState = state;
}
}
}
See the output,
I will mention another aproach, because I came across this solution when I was looking for some practical way how to communicate from my Service running AsyncTask back to main UI. Lucifer's solution is not modular for Services, if you need to use your Service in more then 1 class (that was my case), you won't be able to access variable handler and as far as I know you can't even send Handler as Intent to Service (you can send it to AsyncTask tho). Solution is broadcasting.
sendBroadcast(new Intent(WORK_DONE));
in AsyncTask and
private BroadcastReceiver receiver = new BroadcastReceiver() {
public void onReceive(Context c, Intent i) { //update your UI here }
}
registerReceiver(receiver, new IntentFilter(WORK_DONE));
in your activity.
I don't like all those inner classes android developers use. I understand it's easier to create inner class and access outer class variables, but once you need to use the class again your doomed and you have to edit the code! I am realy new to Android, maybe I am wrong and you actually don't need to reuse those classes. Never did a bigger project so I have no idea but it just doesn't feel right, since on college, they tried hard to teach us how to programm reusable code.
I have researched this and not found a clear answer that has a combination of progress bar + status bar + Service? My issue is that the way file upload is implemented, (that being the only way it can because the server supports it like this), I cannot keep track of number of bytes being written. Hence, I cannot increment the progress bar correctly to reflect the accurate file upload status.
The current implementation increments the progress bar, does the upload and removes the progress bar once it reaches 100. BUT that progress is not accurate reflection of the upload. The upload happens much earlier yet the bar keeps ON. I would rather have the progress showing while this request/response is occurring.
Following is my code snippet:
public class UploadFileService extends IntentService {
public UploadFileService() {
super("UploadFileService");
}
#Override
protected void onHandleIntent(Intent intent) {
fName = intent.getExtras().getString(Constants.EXTRA_K_FILENAME);
path = intent.getExtras().getString(Constants.EXTRA_K_FILEPATH);
attribute = intent.getExtras().getString(Constants.EXTRA_K_ATTRIBUTE);
//Start thread to doFilepUpload
uploadthread = new UploadThread(fName, path, attribute);
uploadthread.start();
}
// Define the Handler that receives messages from the thread and update the progress
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
Integer total = msg.arg1;
notification.contentView.setProgressBar(R.id.status_progress, 100, total, false);
nm.notify(NOTIFICATION_ID, notification);
if ( total.equals(100) && getResponse() != null ){
// inform the progress bar of updates in progress
uploadthread.setState(UploadThread.STATE_DONE);
Intent broadcastIntent = prepareBroadcast();
// remove the notification (we're done)
nm.cancel(NOTIFICATION_ID);
sendBroadcast(broadcastIntent);
}
}
};
public class UploadThread extends Thread {
private String name;
private String path;
private String attribute;
final static int STATE_DONE = 0;
final static int STATE_RUNNING = 1;
int mState;
int total;
public UploadThread(String fName, String path, String attribute) {
// TODO Auto-generated constructor stub
this.name = fName;
this.path = path;
this.attribute = attribute;
}
#Override
public void run() {
// TODO Auto-generated method stub
setResponse(doFileUpload(name, path, attribute));
if( getResponse() != null){
// house keeping for the application
if(response.result.equalsIgnoreCase("success")){
saveFileName = response.data.savedFileName;
responseMessage = response.message;
}else if (response.result.equalsIgnoreCase("error") ||
response == null ){
responseMessage = response.message;
saveFileName = null;
originalName = fName;
}
}
mState = STATE_RUNNING;
total = 0;
while (mState == STATE_RUNNING && total <=100) {
try {
Log.d(TAG, "^^ Thread.sleep");
Thread.sleep(1000);
} catch (InterruptedException e) {
Logger.e("ERROR", "Thread Interrupted");
}
Message msg = handler.obtainMessage();
msg.arg1 = total;
handler.sendMessage(msg);
total++;
}
}
/* sets the current state for the thread,
* used to stop the thread */
public void setState(int state) {
mState = state;
}
}
Does anyone have suggestions/ideas on how I can update progress bar to show correct upload progress?
File Upload process:
paramString = p.getName()+"="+URLEncoder.encode(p.getValue(), HTTP.UTF_8);
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "unsupported encoding -->
name="+p.getName()+"; value="+p.getValue(), e);
throw e;
}
if (combinedParams.length() > 1) {
combinedParams += "&" + paramString;
} else {
combinedParams += paramString;
}
}
}
request = new HttpPost(url + combinedParams);
MultipartEntity entity = new MultipartEntity();
// add headers
for (NameValuePair h : headers) {
request.addHeader(h.getName(), h.getValue());
}
// add cookies
for(NameValuePair c : cookies) {
request.addHeader(H_COOKIE,
c.getName()+"="+c.getValue());
}
entity.addPart(uploadFile.getName(), new FileBody(uploadFile));
request.setEntity(entity)
I found a work-around to this problem. It is not an ideal solution but due to the fact that counting of bytes is not possible I resorted to this route. In the upload Service that I created, I have 2 different threads. Thread #1, does the upload and Thread #2, maintains the progress bar in the notification area. Thread #2 depends on #1. While #1 is alive, thread #2 increments by 1 and sleeps 1sec and with each progress increment, the sleep interval increases by 0.2secs. If the upload completes at lets say 45%, the progress bar jumps to 100%.