I have a set of methods and each method takes time to do its task.
For instance,
After Method setRules() is executed,
The progress level should increase to 30.
After Method getLogs() is executed,
The progress level should increase to 60.
After Method getChartView() is executed,
The progress level should increase to 100.
But the ProgressBar increases till 30 and not goes beyond that although my all the methods are executing.
Code -
public class DialogPopup extends DialogFragment
{
private static int myProgress=0;
private ProgressBar progressBar;
private int progressStatus=0;
private Handler myHandler=new Handler();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
super.onCreateView(inflater, container, savedInstanceState);
view = inflater.inflate(R.layout.main,container, false);
progressBar = (ProgressBar) view.findViewById(R.id.progressBar1);
beginYourTask();
return view;
}
public void beginYourTask()
{
myProgress=0;
progressBar=(ProgressBar)view.findViewById(R.id.myProgress);
progressBar.setMax(100);
//progressBar.setVisibility(View.VISIBLE);
/*Do some work in background thread*/
new Thread(new Runnable()
{
#Override
public void run()
{
progressStatus=setRules();
myHandler.post(new Runnable()
{
public void run()
{
progressBar.setProgress(progressStatus);
}
});
progressStatus=getLogs();
myHandler.post(new Runnable()
{
public void run()
{
progressBar.setProgress(progressStatus);
}
});
progressStatus=getChartView();
myHandler.post(new Runnable()
{
public void run()
{
progressBar.setProgress(progressStatus);
}
});
/*Hides the Progress bar*/
myHandler.post(new Runnable()
{
#Override
public void run()
{
progressBar.setVisibility(View.GONE);
progressStatus=0;
myProgress=0;
}
});
}
private int setRules()
{
//Code here takes time
//set progress to 30
return 30;
}
private int getLogs()
{
//Code here takes time
//set progress to 60
return 60;
}
private int getChartView()
{
//Code here takes time
//set progress to 100
return 100;
}
}).start();
}
NOTE:
I took the help to create such Progress Bar from the tutorial -android-progress-bar-horizontal.
Use an AsyncTask for this kind of thing:
public void beginYourTask()
{
new AsyncTask<Void, Integer, Void>(){
#Override
public Void doInBackground(Void...params){
publishProgress(setRules());
publishProgress(getLogs());
publishProgress(getChartView());
return null;
}
#Override
public void onProgressUpdate(Integer... progress) {
progressBar.setProgress(progress[0]);
}
#Override
public void onPostExecute(Void result){
progressBar.setVisibility(View.GONE);
}
}.execute();
}
That's the idea, there may be typos.
The tutorial from your link hasn't been updated for a while and normally you don't want to use a Thread in this situation because AsyncTask is designed to save you from all the thread problems you would encounter while using Thread
Read the documentation on this and you'll know when to use a Thread or an AsyncTask
Related
I have a fragment that stems off the main activity. I am trying to have a textbox update with the users GPS location as they move around. I currently have it so every time you resume the fragment it updates, but I would like it to happen automatically every 10 seconds or so.
I am currently attempting to use runOnUiThread, which didn't cause my app to crash but didn't seem to do anything.
Within the fragment:
#Override
public void onViewCreated(#NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
TextView newText = getView().findViewById(R.id.wText);
newText.setText(getStringCoordinates);
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
newText.setText(getStringCoordinates);
}
});
}
Try using a handler, something like this should work
private Handler myHandler;
private static final int DELAY = 10000;
#Override
protected void onResume() {
super.onResume();
myHandler = new Handler(Looper.getMainLooper());
checkAgain();
}
private void checkAgain() {
myHandler.postDelayed(()-> checkGps(),DELAY);
}
private void checkGps() {
//do stuff here
checkAgain();
}
#Override
protected void onStop() {
super.onStop();
myHandler.removeCallbacksAndMessages(null);
myHandler = null;
}
basically it sends a message to the main thread every 10 seconds to check gps
the code may be wrong cause I'm writing it off the top of my head, but it should give you a good start
Maybe this is working
public class c_Thread_Update_Fragment extends Thread {
int i =0;
c_Thread_Update_Fragment(FragmentManager fm, ViewPager vp)
{
this.fragmentManager =fm;
this.mViewpager =vp;
}
#Override
public void run() {
while(true)
{
f.getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
yourfragmentclass.updateData(i);
}
});
i++;
sleep(1000);
}
}
public static void setFragment(Fragment f){
f =f;
}
}
Implement a public static void update (xxx){} in yourfragmentclass
Use setFragment(f) in your Fragment adapterclass and pass the current fragment.
I am currently implementing my own custom progress dialog, where I call show and hide once a result comes in/error occurs. However, I want to implement a custom method that says if the progress dialog has not hidden after 10 seconds no matter what, hide it and put up an alert.
This is my custom progress dialog with my method that works but not entirely.
public class CustomProgressDialog extends ProgressDialog {
private AnimationDrawable animation;
private CountDownTimer cTimer = null;
private Context mContext;
public CustomProgressDialog(Context context) {
super(context);
mContext = context;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.custom_progress_dialog);
ImageView la = (ImageView) findViewById(R.id.animation);
la.setBackgroundResource(R.drawable.custom_progress_dialog_animation);
animation = (AnimationDrawable) la.getBackground();
}
#Override
public void show() {
super.show();
animation.start();
startTimer();
}
#Override
public void dismiss() {
super.dismiss();
animation.stop();
if(cTimer != null) {
cTimer.cancel();
}
}
//timer added just in case progress dialog does not stop on its own
private void startTimer() {
cTimer = new CountDownTimer(10000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
dismiss();
AlertDialogManager alert = new AlertDialogManager();
alert.showAlertDialog(mContext, mContext.getString(R.string.loadingErr), mContext.getString(R.string.loadingErrTxt), 3);
}
}.start();
}
#Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
animation.stop();
cTimer.cancel();
}
}
This is how I implement it in the activity/fragment:
private void showProgressDialog() {
customProgressDialog = new CustomProgressDialog(this);
customProgressDialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
customProgressDialog.show();
//so it cannot be closed by user first one lets back button cancel it
//customProgressDialog.setCanceledOnTouchOutside(false);
customProgressDialog.setCancelable(false);
}
private void hideProgressDialog() {
if(customProgressDialog != null) {
//customProgressDialog.hide();
}
}
UPDATE: This is a second option I tried it still does not stop the alert from popping up which makes me think the timer is still going even on cancel.
This is the activity:
private void autoProgressShutdown() {
Runnable progressRunnable = new Runnable() {
#Override
public void run() {
customProgressDialog.cancel();
callAlert();
}
};
Handler pdCanceller = new Handler();
pdCanceller.postDelayed(progressRunnable, 10000);
}
private void callAlert() {
AlertDialogManager alert = new AlertDialogManager();
alert.showAlertDialog(this, getString(R.string.loadingErr), getString(R.string.loadingErrTxt), 3);
}
private void showProgressDialog() {
customProgressDialog = new CustomProgressDialog(this);
customProgressDialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
customProgressDialog.show();
//so it cannot be closed by user first one lets back button cancel it
//customProgressDialog.setCanceledOnTouchOutside(false);
customProgressDialog.setCancelable(false);
autoProgressShutdown();
}
private void hideProgressDialog() {
customProgressDialog.cancel();
if(customProgressDialog != null) {
customProgressDialog.hide();
}
}
In the custom dialog edited the file to remove all the timer stuff and added this:
#Override
public void setOnCancelListener(OnCancelListener listener) {
super.setOnCancelListener(listener);
dismiss();
}
Possible Issues:
-not sure if memory leak issues since I am not destroying it
Definite Issues:
-if the Progress dialog is hidden the alert still pops up after 10 seconds which means either cancel did not get called
-Also, if I switch screens not sure if the cancel is enough to destroy the timer
You can use Handler#postDelayed to make something happen later on a given thread, and you can use Handler#removeCallbacksAndMessages to cancel pending tasks. If you call it with null, it just cancels anything pending on the handler if you've got some stuff that you need to prevent in the posted task.
Here's your dialog, but properly self-terminating:
class SuicideDialog extends Dialog{
private Handler mAutoTerminationHandler;
#Override
public void onShow(){
mAutoTerminationHandler = new Handler();
}
#Override
public void show(){
super.show();
mAutoTerminationHandler.postDelayed(new Runnable(){
dismiss();
}, 666L);
}
#Override
public void dismiss(){
mAutoTerminationHandler.removeCallbacksAndMessages(null);
super.dismiss();
}
}
Or, you can put the lifecycle listening into its own class:
class ShownTaskListener implements OnShowListener, OnDismissListener {
private Handler mHandler;
#Override
public ShownTaskListener(Handler handler, Runnable showTask){
mHandler = handler;
mShowTask = showTask;
}
// from OnShowListener
#Override
public void onShow(){
mHandler.postDelayed(mShowTask, 666L);
}
// from OnDismissListener
#Override
public void onDismiss(){
// get rid of all pending actions in the Handler
mHandler.removeCallbacksAndMessages(null);
}
}
And then, you can use it to self-dismiss any Dialog by attaching this listener with Dialog#setOnShowListener and Dialog#setOnDismissListener.
friends I am developing an application which is playing small mp3 soundtracks (podcasts). Now my code which I am showing below is working on Android 3.2 as it should. But on Android 4.1.2 the SeekBar is not being updated by the handler instance. I have read about a bug in the SeekBar causing this issue but it should be fixed since Android 3.2. Any help or advice would be appreciated. Here is my code:
public class PodcastDetailFragment extends BaseFragment {
private MediaPlayer mediaPlayer = null;
private Button playPauseButton = null;
private SeekBar seekBar = null;
private TextView timeView = null;
private int totalDuration = 0;
private Bundle data;
private Handler handler=new Handler();
private Runnable runnable = new Runnable() {
public void run() {
int progress = mediaPlayer.getCurrentPosition();
seekBar.setProgress(progress);
int hours = ((progress/1000)/60)/60;
int minutes = ((progress/1000)/60)%60;
int seconds = ((progress/1000)%60)%60;
String hoursString = (hours<10)?"0":"";
String minutesString = (minutes<10)?"0":"";
String secondsString = (seconds<10)?"0":"";
timeView.setText(hoursString+hours+":"+minutesString+minutes+":"+secondsString+seconds);
handler.postDelayed(this, 100);
}
};
public static PodcastDetailFragment newInstance(Bundle bundle) {
PodcastDetailFragment f = new PodcastDetailFragment();
f.setArguments(bundle);
return f;
}
/**
* When creating, retrieve this instance's number from its arguments.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
data = getArguments();
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
getView().findViewById(R.id.preparing_track_progress_bar).setVisibility(View.VISIBLE);
super.onActivityCreated(savedInstanceState);
}
#Override
public void onPause() {
super.onPause();
if (mediaPlayer != null) {
LogUtils.d("Podcast MediaPlayer", "stop() inside the onPause() was called");
mediaPlayer.stop();
}
}
#Override
public void onDestroy() {
LogUtils.d("Podcast MediaPlayer", "release() was called");
mediaPlayer.release();
super.onDestroy();
}
/**
* The Fragment's UI is just a simple text view showing its instance number.
*/
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.podcasts_details, container, false);
TextView dv = (TextView) v.findViewById(R.id.durationView);
dv.setText(data.getString("duration"));
timeView = (TextView) v.findViewById(R.id.timeView);
timeView.setText("00:00:00");
playPauseButton = (Button) v.findViewById(R.id.playPauseButtonView);
playPauseButton.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
playPauseButton.setText(getResources().getString(
R.string.play));
} else {
mediaPlayer.start();
playPauseButton.setText(getResources().getString(
R.string.pause));
}
}
});
seekBar = (SeekBar) v.findViewById(R.id.seekBarView);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public void onStopTrackingTouch(SeekBar seekBar) {
}
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
if (fromUser) {
mediaPlayer.seekTo(progress);
}
}
});
mediaPlayer =new MediaPlayer();
mediaPlayer
.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
totalDuration = mp.getDuration();
seekBar.setMax(totalDuration);
playPauseButton.setEnabled(true);
try{
getView().findViewById(R.id.preparing_track_progress_bar).setVisibility(View.INVISIBLE);
}catch(Exception ex){
ex.printStackTrace();
}
handler.postDelayed(runnable, 100);
}
});
mediaPlayer.setDataSource(Uri.parse(data.getString("podcast_url")).toString());
playPauseButton.setEnabled(false);
mediaPlayer.prepareAsync();
return v;
}
}
You should either use an AsyncTask or a Service (in case the music will play in background) instead of a Worker Thread with a Handler. The AsyncTask is extremely useful with it's onProgressUpdate method, you can use it to update the Bar based on the progress of the audio file.
Here's a basic example of an AsyncTask and how you should use it:
private class TestAsyncTask extends AsyncTask<Void, Integer, Void> {
#Override
protected Void doInBackground(Void... arg0) {
for(int i=0; i<songDuration; i++){
doSomething();
publishProgress(i);
}
return null;
}
#Override
protected void onProgressUpdate(Integer... progress) {
//UPDATE BAR
}
#Override
protected void onPostExecute(Void result) {
//DO SOMETHING WHEN FINISHED PLAYING
}
}
Anyway, here's the official doc: http://developer.android.com/reference/android/os/AsyncTask.html
I have solved this problem. The SeekBar was ok. It was just the issue that the lenght of a track is only given when you download the whole track. So to show the progress on a SeekBar properly you need to know the length of a track. So you take the length of a track and then call seekBar.setMax(lenghtOfTrack) and the progress is updated as it should by the method setProgress(progress).
I am trying to execute the method doSomeWork(); after the ProgressDialog dismisses in my method printing();which seems to be overlapped by the other method and the dialog is not showed up. If I comment method doSomeWork(); the dialog is displayed correctly until the thread is finished.
Here is my method printing();
public void printing()
{
final ProgressDialog printingDialog = ProgressDialog.show(this, "Printing...", "Please wait", true, false);
new Thread(new Runnable() {
#Override
public void run()
{
//something big executing here
}
}).start();
}
He is my method doSomework():
public void doSomeWork(){
Thread receiptPrint = new Thread(new Runnable() {
#Override
public void run() {
//something here
runOnUiThread(new Runnable() {
#Override
public void run() {
//another dialog here
}
});
}
});
}
Here you can see the how I am calling those two methods:
private OnClickListener onClickPrint = new OnClickListener() {
public void onClick(final View v) {
Log.d("Button","Clicked on Print Order Button");
printing();
doSomeWork();
Does anyone know how could I execute doSomeWork() only when printing(); will be completely finished?
This is one of the purposes of an AsyncTask. It would look similar to this:
public void onClick(final View v) {
new AsyncTask<Void, Void, Void>() {
#Override
protected void onPreExecute() {
//Show your progress dialog in here
super.onPreExecute();
}
#Override
protected Void doInBackground( Void... params ) {
printing();
return null;
}
#Override
protected void onPostExecute( Void result ) {
//Dismiss your progress dialog here
doSomeWork();
}
}.execute();
}
Instead of using thread you can use asynchronous task. Show the progress dialog in the preexecute method call the printing method inside the background method after completing printing operation call the doSomeWork() inside the postexecute method.
You can use Handler for that in android. for example consider the following piece of code. you can dismiss the dialogs inside handlers. may it work for you.
private void printing(){
Thread receiptPrint = new Thread(new Runnable() {
#Override
public void run() {
retrieveEmails();
runOnUiThread(new Runnable() {
#Override
public void run() {
try{
//here your code executes
//after code executes do following:
uiHandler.sendEmptyMessage(0);
}catch(Exception ex){
errorHandler.sendEmptyMessage(0);
}
}
});
}
});
receiptPrint.start();
}
final Handler uiHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
//here execute doSomeWork()
}
};
final Handler errorHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
//do other stuff
}
};
This question already has answers here:
Updating Android UI using threads
(4 answers)
Android toast message from a separate thread class
(1 answer)
Closed 9 years ago.
I'm having some trouble trying to update automaticaly a view in my android activity.
The application display some message like a chat. Im using a ListView to put the message with a ArrayAdapter.
I use this metod to update the ListView
public void loadMessages() {
ArrayList<String> messages = this.dbHelper.getMessages();
conversationArrayAdapter.clear();
conversationArrayAdapter.addAll(messages);
conversationArrayAdapter.notifyDataSetChanged();
}
My idea is to put a thread that call that metod, but when i try to do this i have the following error.
Only the original thread that created a view hierarchy can touch its view.
because you are trying to access or update UI elements from Thread . to avoid this error you will meed to use runOnUiThread for updating UI from Thread as :
Your_Current_Activity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// Update UI here
loadMessages();
}
});
and second solution is use AsyncTask instead of thread
Use this code.
public class MainActivity extends Activity
{
private Timer autoUpdate;
#Override
public void onResume()
{
super.onResume();
autoUpdate = new Timer();
autoUpdate.schedule(new TimerTask()
{
#Override
public void run()
{
runOnUiThread(new Runnable()
{
public void run()
{
updateScore();
}
});
}
}, 0, 5000); // updates each 5 seconds
}
#Override
public void onPause()
{
autoUpdate.cancel();
super.onPause();
}
#Override
public void onCreate(Bundle savedInstanceState)
{
// initialize view layout
super.onCreate(savedInstanceState);
setContentView(R.layout.cleanermain);
super.onResume();
}
private void updateScore()
{
// decide output
// update cricket score
}
}
UI should be updated only from the UI (Main) thread.
Here is a solution using AsyncTask.
public void asyncCallWithSchedule() {
final Handler handler = new Handler();
Timer timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
try {
new SearchAsync().execute(txtSearch.getText().toString());
}
});
}
};
timer.schedule(doAsynchronousTask, 0, 2000);
}
}
AsyncTask class:
private class SearchAsync extends
AsyncTask < String, Object, List < Users >> {
#Override
protected List < Users > doInBackground(String...params) {
// Call DB here
return null;
}
#Override
protected void onPostExecute(List < Users > result) {
super.onPostExecute(result);
// Update UI here
}
}
Simple:
public void loadMessages() {
ArrayList<String> messages = this.dbHelper.getMessages();
conversationArrayAdapter.clear();
conversationArrayAdapter.addAll(messages);
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
conversationArrayAdapter.notifyDataSetChanged();
}
});
}