java android , delay inside onclick button includes gui changes - java

I am trying to simulate an sending msg progress .
The main idea is to colour the members who message sent to them, promote the status bar etc.. (gui changes ) all this with delay for each loop iteration.
The main problem is that everything is going inside the onClick listener and runing thread inside it wont help ): cause gui is changing only after delay is completed.
Any one may advice me how to do this simulation ?
send.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
for(int i=0; i<phoneNumbers.size(); i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
members.get(i).setBackgroundColor(Color.GREEN);
members.get(i).invalidate();
mProgressDialog.setProgress(i+1);
sentCount.setText(getString(R.string.msgSentCount) + (i+1));
if(i==12){
scroolView.animate().translationYBy(-50);}
}
}
});
Thanks you very much !

If I unserstood you right - fake progress + waiting time. First of all handlers a perferct to delay an output:
//Fake Progress
progress = new ProgressDialog(this);
open(this);
// Delay output
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
setData();
}
}, 6000);
in the function setData(), do the task you wanna run after
and progress bar for fake:
public void open(Activity activity) {
progress.setMessage("Fakeprogress, Data Mining...");
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progress.setIndeterminate(false);
progress.setCancelable(false);
progress.setMax(100);
progress.setProgress(10);
progress.show();
final int totalProgressTime = 100;
final Thread t = new Thread() {
#Override
public void run() {
int jumpTime = 0;
while (jumpTime < totalProgressTime) {
try {
sleep(60);
//System.out.println("********" + jumpTime);
jumpTime += 1;
progress.setProgress(0);
progress.setProgress(jumpTime);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
progress.dismiss();
}
};
t.start();
}

Finaly got it works with recursion !!!!
public static int counter=0;
public void runMother(final Handler handler)
{
if(counter==3)return;
handler.postDelayed(new Runnable() {
#Override
public void run() {
members.get(counter).setBackgroundColor(Color.GREEN);
counter++;
runMother(handler);
}
}, 1000*counter);

Related

Display values in ArrayList one by one in textView

I am trying to display values inside ArrayList on single line textView one by one after some interval. How to achieve this without blocking the main thread?
I have written code which is able to do this with Thread.sleep but, after a few seconds of running, activity is getting crashed. I have used For Loop & Thread.sleep to iterate every ArrayList value after some interval.
When activity crashes, I am getting IndexOutOfBondException after a few seconds of running.
public void errorRepeater() {
Thread t = new Thread() {
#Override
public void run() {
// !isInterrupted()
while (!isInterrupted()) {
for (xz = 0; xz < errorList.size(); xz++) {
try {
Thread.sleep(2000); //1000ms = 1 sec
runOnUiThread(new Runnable() {
#Override
public void run() {
String sErrorList = errorList.get(xz);
String sErrorListOkBox = errorListOkBox.get(xz);
Log.i("MQTT sErrorList", sErrorList);
TextView tvC1HPLP = findViewById(R.id.errormsg);
tvC1HPLP.setText(sErrorList);
TextView tvok = findViewById(R.id.ok);
tvok.setText(sErrorListOkBox);
rl.setBackgroundResource(R.drawable.errorred);
tvC1HPLP.setTextColor(Color.RED);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
t.start();
}
textView should display values inside ArrayList one by one without crashing activity.
Just for reference, you can try something like this.
// You can define those both textview globally.
TextView tvC1HPLP = findViewById(R.id.errormsg);
TextView tvok = findViewById(R.id.ok);
Handler mHandler = new Handler();
final Runnable runnable = new Runnable() {
int count = 0;
#Override
public void run() {
String sErrorList = errorList.get(count%errorList.size);
String sErrorListOkBox = errorListOkBox.get(count%errorListOkBox.size);
tvC1HPLP.setText(sErrorList);
tvok.setText(sErrorListOkBox);
rl.setBackgroundResource(R.drawable.errorred);
tvC1HPLP.setTextColor(Color.RED);
count++;
mHandler.postDelayed(this, 4000); // four second in ms
}
};
mHandler.postDelayed(runnable, 1000);

CallBack from MediaPlayer

I have a MediaPlayer and an audio file, which I need to play, also I have an ArrayList with the certain seconds of this audio file, on this seconds while audio is playing, I need to switch pages in the ViewPager. How to get a CallBack from the MediaPlayer in these certain moments of the time? or maybe you will recommend some other way how is possible to do it.
What I have right now is the method, where I use CountDownTimer, which change pages in ViewPager, but it works wrong and it doesn't take into the account fact that an audio track can be stop and then resume.
public void startPlayingLabels() {
mPlayer = new MediaPlayer();
try {
String mFileName = CameraFragment.mAudioFolder + "/" + ViewActivity.parentName + ".3gp";
mPlayer.setDataSource(mFileName);
mPlayer.prepare();
mPlayer.start();
for (int i=0; i<zeroLabelPosition.size()-1; i++) {
final int finalI = i;
new CountDownTimer(Integer.parseInt(String.valueOf(Integer.parseInt((String) zeroTime.get(finalI + 1)) - Integer.parseInt((String) zeroTime.get(finalI)))), 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
mPager.setCurrentItem(Integer.parseInt(String.valueOf(zeroLabelPosition.get(finalI))));
}
}.start();
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
Android madiaplayer does not have any timeline update, thats why you can write your own, or you can use something like this.
CountDownTimer timer;
int timeStampIterator;
int[] timeStamp = new int[5]; // your own time stamps when view must be switched
void play() {
mPlayer.start();
timer = new CountDownTimer(mPlayer.getDuration() - mPlayer.getCurrentPosition(), 1000) {
#Override
public void onTick(long millisUntilFinished) {
int timeSpends = mPlayer.getDuration() - mPlayer.getCurrentPosition();
if (timeSpends == timeStamp[timeStampIterator]) {
//switchToNExtSlide();
timeStampIterator++;
}
}
#Override
public void onFinish() {
}
}.start();
}
void pause() {
mPlayer.pause();
timer.cancel();
timer = null;
}
void stop() {
mPlayer.stop();
timer.cancel();
timer = null;
timeStampIterator = 0;
}
you can also use handler for it like following
Handler handler = new Handler();
Runnable notification = new Runnable() {
public void run() {
startPlayProgressUpdater();// change hear page for view pager, because it call after every 1 second
}
};
handler.postDelayed(notification, 1000);

updating notification text every second with handler

i've a strange issue. i want to update the text of a notification every second so i wrote this code
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
batteryTemperature = getBatteryTemperature();
new Handler().postDelayed(this, 1000);
}
}, 1000);
if(batteryTemperature != 0) {
builder.setContentText("BatteryLevel"+batteryTemperature);
} else {
builder.setContentText("The batteryTemperature value is 0");
}
With a Log i saw that in the Handler the batteryTemperature value is different from 0 but out of the Handler it return 0. Why? How can i set the correct value in the notification?
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
batteryTemperature = getBatteryTemperature();
handler.postDelayed(this, 1000);
}
}, 1000);
Do not create a Handler every time the Runnable is called. You need to executed this snippet, every time the runnable is executed
if(batteryTemperature != 0) {
builder.setContentText("BatteryLevel"+batteryTemperature);
} else {
builder.setContentText("The batteryTemperature value is 0");
}
Try this (UI thread safe):
TimerTask task = new TimerTask()
{
private final Handler mHandler = new Handler(Looper.getMainLooper());
#Override
public void run()
{
mHandler.post(new Runnable()
{
#Override
public void run()
{
batteryTemperature = getBatteryTemperature();
if (batteryTemperature != 0)
{
builder.setContentText("BatteryLevel" + batteryTemperature);
}
else
{
builder.setContentText("The batteryTemperature value is 0");
}
}
});
}
};
Timer timer = new Timer();
timer.scheduleAtFixedRate(task, 0, 1000);
There are two things you're asking: 1) how do I update my notification and 2) why is the value always 0?
Let me answer the second one first, try this code instead:
private MyHandler myHandler = new MyHandler();
...
// get the ball rolling...
myHandler.sendEmptyMessageDelayed(MyHandler.UPDATE, 1000);
...
private class MyHandler extends Handler {
private int UPDATE = 0;
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE:
updateBatteryTemperatureNotification(getBatteryTemperature());
sendEmptyMessageDelayed(MyHandler.UPDATE, 1000);
break;
case STOP:
removeMessages(UPDATE);
break;
}
super.handleMessage(msg);
}
}
Is it safe to assume you know how to update the Notification when you have the data correct?

Avoiding threads restarting when changing activity

Right now, when I change the activity, my thread seams to go to sleep or something. And when I come back to the main activity, there are two threads running, doing the same things. I'm not sure if this is the case, but it seems like it's something equal.
...
public class MainActivity extends Activity {
public static double cowCount = 195;
public static double income = 0.100;
static boolean twiceCow = false, Threadrunning = false;
...
public void inc() {
new Thread(new income()).start();
}
class income implements Runnable {
#Override
public void run() {
for (int i = 0; i < 20;) {
final int value = i;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
#Override
public void run() {
cowCount = cowCount + income;
refresh();
}
});
}
}
}
This is how my thread looks like.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new Handler();
checkThread();
}
private void checkThread() {
if (Threadrunning == false)
inc();
Threadrunning = true;
}
public void inc() {
new Thread(new income()).start();
}
...
public void refresh () {
TextView myTextView = (TextView)findViewById(R.id.myText);
myTextView.setText("You Have " + String.valueOf((nf.format(cowCount)) + " Cows!"));
}
I don't really understand what I've done wrong.
Please review this post: http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
Consider your activity re-start as the same thing as a config change.
This pattern, i.e. using a retained Fragment as a container for your thread, and proxying UI updates via callbacks to your activity, is a pattern that will work much better for you.
In your case you'd need only a single TaskCallback for your UI refresh(), e.g. onRefreshCowCount(int cows);

How to stop Runnable in Android that's looping using postDelayed()?

I need to stop a Runnable from running when an image is clicked in my Android app. I'm running this Runnable repeatedly using ImageView.postDelayed():
r = new Runnable() {
public void run() {
imgview.setImageResource(imageArray[i]);
i++;
if (i >= imageArray.length) {
i = 0;
}
imgview.postDelayed(r, 20); // set to go off again in 3 seconds.
// imgview.setOnClickListener(this);
}
};
imgview.postDelayed(r, 20); // set first time for 3 seconds
But under certain conditions I want to stop it from running, after it's already started. Here's the full code for my activity:
public class MainActivity extends Activity {
int i = 0;
ImageView imgview, imgview2;
Handler handler = new Handler();
Runnable r;
MediaPlayer mMediaPlayer;
int[] imageArray = { R.drawable.f1, R.drawable.f2, R.drawable.f3,
R.drawable.f4, R.drawable.f5, R.drawable.f6, R.drawable.f7,
R.drawable.f8, R.drawable.f9, R.drawable.f10, R.drawable.f11,
R.drawable.f12, R.drawable.f13, R.drawable.f14, R.drawable.f15,
R.drawable.f16, R.drawable.f17, R.drawable.f18, R.drawable.f19,
R.drawable.f20, R.drawable.f21, R.drawable.f22, R.drawable.f23,
R.drawable.f24, R.drawable.f25, R.drawable.f26, R.drawable.f27,
R.drawable.f28 };
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tapp_activity);
imgview = (ImageView) findViewById(R.id.imageView1);
mMediaPlayer = new MediaPlayer();
mMediaPlayer = MediaPlayer.create(MainActivity.this, R.raw.water);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
imgview2 = (ImageView) findViewById(R.id.imageView2);
imgview2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(i==0)
{
mMediaPlayer.setLooping(true);
mMediaPlayer.start();
i=1;
r = new Runnable() {
public void run() {
imgview.setImageResource(imageArray[i]);
i++;
if (i >= imageArray.length) {
i = 0;
}
imgview.postDelayed(r, 20); // set to go off again in 3 seconds.
// imgview.setOnClickListener(this);
}
};
imgview.postDelayed(r, 20); // set first time for 3 seconds
}
else
{
i=0;
mMediaPlayer.stop();
imgview.setBackgroundResource(R.drawable.tapstill);
}
}
});
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
mMediaPlayer.stop();
}
}
What can I change in my code so that my Runnable stops running in the else condition of my onClick() method?
You might try removing the callback.
imgview.removeCallbacks(r);
In order for this to work, though. you'd have to ensure that r is the same Runnable as the one you posted. You could do this by creating it once, possibly in onCreate. Since the Runnable doesn't have any dependency on the ClickListener anyway, this shouldn't be a problem.
You might also need to do some synchronization in order to prevent the case where you're removing a currently running callback, though, now that i think about it. The volatile boolean running idea is probably less complex overall.
You can control your run() method with a boolean flag:
boolean running = true;
...
r = new Runnable()
{
public void run()
{
if(running)
{
imgview.setImageResource(imageArray[i]);
i++;
if (i >= imageArray.length) {
i = 0;
}
imgview.postDelayed(r, 20);
}
};
}
If you set running = false later on, your thread will be idle and that's what you want.
You can do it by
Thread.stop();

Categories