For the last week, I have been using Android Studio to write code that achieves the following goals:
Wait for the user to be within a certain distance of the start waypoint
Once at start waypoint, begin a timer that logs gps data and current time
Stops timer when the end waypoint is crossed
At the moment, I have the start and end waypoints hard coded but I seem to run into an error that I have been trying to trace with the step through function on my IDE but can't seem to find it. Below is the code I have been using:
void StartTimer (View view){
//Location l = null;
boolean hasLoc = false; //are we at the start?
float speed = 0;
float topSpeed = 0;
while(hasLoc == false && cancel == false){
float d = l.distanceTo(t);
if(d < 2.0)
hasLoc = true;
//if(!l.equals(lm.getLastKnownLocation("")))
String msg = "Latitude: " + l.getLatitude() + "\nLongitude: "+ l.getLongitude();
Toast.makeText(getBaseContext(), msg, Toast.LENGTH_LONG).show();
}
hasLoc = false;
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
// Actions to do after 10 seconds
buzzer();
}
}, 10000);
while(l.distanceTo(tf) > 2.0 && cancel == false){
float cSpeed = l.getSpeed();
if(cSpeed>topSpeed)
topSpeed = cSpeed;
String msg = "Current Speed: "+cSpeed+"Top Speed: "+topSpeed;
Toast.makeText(getBaseContext(), msg, Toast.LENGTH_LONG).show();
}
cancel = false;
}
When I run the code, the phone I test it one will run it but it won't respond, which leads me to believe there is an unsatisfied loop that I have not considered.
Any suggestions would be helpful, thank you in advance for advice!
Your while loops are clogging up the CPU's execution which is what is causing it to not respond. Instead you should place your code inside a thread and call Thread.sleep(1000); inside the thread, this way the the while loop is paused for 1 second after every execution of the code inside it.
Something like this:
new Thread(new Runnable() {
#Override
public void run() {
while (hasLoc == false && cancel == false) {
float d = l.distanceTo(t);
if (d < 2.0)
hasLoc = true;
String msg = "Latitude: " + l.getLatitude() + "\nLongitude: " + l.getLongitude();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getBaseContext(), msg, Toast.LENGTH_LONG).show();
}
});
}
hasLoc = false;
new Handler().postDelayed(new Runnable() {
public void run() {
// Actions to do after 10 seconds
buzzer();
}
}, 10000);
while (l.distanceTo(tf) > 2.0 && cancel == false) {
float cSpeed = l.getSpeed();
if (cSpeed > topSpeed)
topSpeed = cSpeed;
String msg = "Current Speed: " + cSpeed + "Top Speed: " + topSpeed;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getBaseContext(), msg, Toast.LENGTH_LONG).show();
}
});
}
cancel = false;
}
}).start();
Related
I have a single activity game while playing (after login and character selection). My sound pool for SFX works great, but my background music randomly stops playing. I tried to add in setOnErrorListener, but never saw anything there. I am wondering if the thread is being garbage collected?
When you are in different towns or wilderness the music changes and that is checked here: !currentPlayingMusicFilename.equals(shortFilename). If you stay in the same music area, randomly the music stops looping.
I have read so many posts on here and google and can't find the "proper" way to play game background music. I've tried soundpool, but they are over 1MB, saw many things saying not to do service, and having an issue with this approach. Any help is greatly appreciated.
I am leaving in the "SFX" portion in case that code can help anyone and provide a full picture.
public static void playSoundOrMusic(final String shortFilename, final String type, double distanceFactor) {
String fullFilename = "";
if (type.equals("SFX")){
fullFilename = "res/sounds/sfx/" + shortFilename;
} else if (type.equals("MUSIC")){
if (mp3MUSICPlayer != null && mp3MUSICPlayer.isPlaying() && !currentPlayingMusicFilename.equals(shortFilename)){
mp3MUSICPlayer.stop();
}
fullFilename = "res/sounds/music/" + shortFilename;
}
float volumeManipulation = 1.0f;
if (type.equals("SFX")){
int sfxVolume = MyCommandReceiver.GetSharedPreferences().getInt(MyCommandReceiver.GetStringById(R.string.pref_general_sfx_volume_key), 100);
sfxVolume *= distanceFactor;
volumeManipulation = (float) (sfxVolume / 100.0);
//volumeManipulation = (float) (1 - (Math.log(MAX_VOLUME - sfxVolume) / Math.log(MAX_VOLUME)));
LoggerWrite("v", TAG, "sfxVolume: " + volumeManipulation);
} else if (type.equals("MUSIC")){
int musicVolume = MyCommandReceiver.GetSharedPreferences().getInt(MyCommandReceiver.GetStringById(R.string.pref_general_music_volume_key), 100);
volumeManipulation = (float) (musicVolume / 100.0);
//volumeManipulation = (float) (1 - (Math.log(MAX_VOLUME - musicVolume) / Math.log(MAX_VOLUME)));
LoggerWrite("v", TAG, "musicVolume: " + volumeManipulation);
}
final float finalVolume = volumeManipulation;
if (MyCommandReceiver.GetActiveActivity() == null){ //if not yet in Activity
return;
}
try {
Uri myUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/KisnardOnline/" + fullFilename));
if (type.equals("SFX")){
if (!soundPoolIds.containsKey(Environment.getExternalStorageDirectory() + "/KisnardOnline/" + fullFilename)){ //not yet in soundpool
int soundId = soundPool.load(Environment.getExternalStorageDirectory() + "/KisnardOnline/" + fullFilename, 1);
soundPoolIds.put(Environment.getExternalStorageDirectory() + "/KisnardOnline/" + fullFilename, soundId);
//play it manually one time
mp3SFXPlayer = new MediaPlayer();
mp3SFXPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp3SFXPlayer.setVolume(finalVolume, finalVolume);
mp3SFXPlayer.setDataSource(MyCommandReceiver.GetActiveActivity(), myUri);
new Thread(new Runnable() {
#Override
public void run() {
try {
mp3SFXPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp3SFXPlayer.start();
}
});
mp3SFXPlayer.prepare();
} catch (Exception ex) {
GameActivity.LoggerWrite("e", TAG, "Sound(sfx) playing issue" + ex);
}
}
}).start();
} else { //already in soundpool - play it
soundPool.play(soundPoolIds.get(Environment.getExternalStorageDirectory() + "/KisnardOnline/" + fullFilename), finalVolume, finalVolume, 0, 0, 1);
}
} else if (type.equals("MUSIC")){
if (!currentPlayingMusicFilename.equals(shortFilename)){
mp3MUSICPlayer = new MediaPlayer();
mp3MUSICPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp3MUSICPlayer.setVolume(finalVolume, finalVolume);
mp3MUSICPlayer.setDataSource(MyCommandReceiver.GetActiveActivity(), myUri);
}
}
} catch (Exception e) {
GameActivity.LoggerWrite("e", TAG, "Sound file issue" + e);
}
if (type.equals("MUSIC") && !currentPlayingMusicFilename.equals(shortFilename)){
new Thread(new Runnable() {
#Override
public void run() {
try {
mp3MUSICPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
currentPlayingMusicFilename = shortFilename;
mp3MUSICPlayer.start();
}
});
mp3MUSICPlayer.prepare();
mp3MUSICPlayer.setLooping(true);
} catch (Exception ex) {
GameActivity.LoggerWrite("e", TAG, "Sound(music) playing issue" + ex);
}
}
}).start();
}
}
Here is how I solved this as it does not seem there is an answer out there to why it dies randomly.
if (type.equals("MUSIC") && (!currentPlayingMusicFilename.equals(shortFilename) || !mp3MUSICPlayer.isPlaying())){
new Thread(new Runnable() {
...
I have a For loop in which I call a method to upload images to the server , the problem that i am facing that at a certain limit the server will force stop the opened socket so i have to upload every image at once
for (int i = 0; i < paths.size(); i++) {
transferData(paths.get(i), i);
}
and the transferData Function I am using the transfer Utility aws s3 function
TransferUtility transferUtility =
TransferUtility.builder()
.context(this)
.awsConfiguration(AWSMobileClient.getInstance().getConfiguration())
.s3Client(amazonS3Client)
.defaultBucket("name")
.build();
TransferObserver uploadObserver = transferUtility.upload("name", name, new File(path), CannedAccessControlList.PublicRead);
uploadObserver.setTransferListener(new TransferListener() {
#Override
public void onStateChanged(int id, TransferState state) {
Log.d(TAG, "onStateChanged: " + id + ", " + state);
if (TransferState.COMPLETED == state) {
}
}
#Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
float percentDonef = ((float) bytesCurrent / (float) bytesTotal) * 100;
int percentage = (int) percentDonef;
Log.d(TAG, "onProgressChanged: " + percentage);
}
#Override
public void onError(int id, Exception ex) {
Log.e(TAG, "Error during upload: " + id, ex);
try {
showToast(ex.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
ex.printStackTrace();
}
});
How to wait for the method to finish execution then continue the loop
to wait loop use this code :
CountDownLatch latch=new CountDownLatch(1);
for (int i = 0; i < paths.size(); i++) {
transferData(paths.get(i), i);
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
and put this at the end of your method that finished upload image or failed
latch.countDown();
when your method rich to latch.countDown(); your loop will be continue
notice that you must put your loop in another thread except main thread
So hi everyone, this is my first post in stackoverflow,
and i get stucked in 1 problem,
the problem is:
how can I add a delay inside for loop
I did lots of research and none of it works
So I decided to ask myself.
Here is my code
Handler handler1 = new Handler();
for (langId = 1; langId <= 3; langId++) {
handler1.postDelayed(new Runnable() {
#Override
public void run() {
if (langId == 1) {
Toast.makeText(KCRdestActivity.this, "1", Toast.LENGTH_LONG).show();
delayTime += 2000;
}
if (langId == 2) {
Toast.makeText(KCRdestActivity.this, "2", Toast.LENGTH_LONG).show();
delayTime += 2000;
}
if (langId == 3) {
Toast.makeText(KCRdestActivity.this, "3", Toast.LENGTH_LONG).show();
delayTime += 2000;
}
}
}, delayTime);
}
So the result I want is:
"1" -> 2000ms -> "2" -> 2000ms -> "3"
Any ideas?
I tried Thread.sleep(2000), it works, but it freeze the app, I need to do extra things during the process.
Edit
Problem solved, this is the working code, also my final goal
playBtn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final Handler handler1 = new Handler();
langId = 1;
max = 1;
delayTime = 0;
selectedMP = 1;
if (((RadioButton) findViewById(R.id.noneDepart)).isChecked()) max = 3;
else max = 6;
handler1.post(new Runnable() {
#Override
public void run() {
if (((RadioButton) findViewById(R.id.noneDepart)).isChecked()) {
String destdir = "KCR/Depart/" + Utils.getDestID(selectedDest) + "_";
if (viaRAC.isChecked()) destdir = destdir + "via_rac_";
destdir = destdir + langId + ".mp3";
if (selectedMP == 1) {
try {
afd = getAssets().openFd(destdir);
mp1.reset();
mp1.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mp1.prepare();
mp1.start();
//Utils.RunOnUiThread(KCRdestActivity.this, mp1, sb1);
((Button) findViewById(R.id.Play1)).setText("❙❙");
selectedMP = 2;
delayTime = mp1.getDuration() - 130;
Toast.makeText(KCRdestActivity.this, delayTime + "##" + destdir, Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
}
} else {
try {
afd = getAssets().openFd(destdir);
mp2.reset();
mp2.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mp2.prepare();
mp2.start();
//Utils.RunOnUiThread(KCRdestActivity.this, mp1, sb1);
((Button) findViewById(R.id.Play1)).setText("❙❙");
selectedMP = 1;
delayTime = mp2.getDuration() - 130;
Toast.makeText(KCRdestActivity.this, delayTime + "##" + destdir, Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (langId > 3) {
return;
}
langId++;
handler1.postDelayed(this, delayTime);
}
});
}
});
Handler handler1 = new Handler();
int langId = 1;
handler1.postDelayed(new Runnable() {
#Override
public void run() {
if (langId > 3) {
return;
}
if (langId == 1) {
Toast.makeText(KCRdestActivity.this, "1", Toast.LENGTH_LONG).show();
delayTime = 2000;
}
if (langId == 2) {
Toast.makeText(KCRdestActivity.this, "2", Toast.LENGTH_LONG).show();
delayTime = 2000;
}
if (langId == 3) {
Toast.makeText(KCRdestActivity.this, "3", Toast.LENGTH_LONG).show();
delayTime = 2000;
}
langId++;
handler1.postDelayed(this, delayTyme);
}
}
There's no need to write that much lines of code, try this:
Handler handler1 = new Handler();
int langId = 1;
handler1.post(new Runnable() {
#Override
public void run() {
if (langId > 3) {
return;
}
Toast.makeText(KCRdestActivity.this, String.valueOf(langId++), Toast.LENGTH_LONG).show();
handler1.postDelayed(this, 2000); // If delay time is constant!
}
});
you can use asyntask along with Thread.sleep(2000) in the doInBackground method
try this..
MainActivity.....
long Delay = 2000;
oncreate().........
Timer Run = new Timer();
TimerTask Show = new TimerTask() {
#Override
public void run() {
do something.........
}
};
Run.schedule(Show, Delay);
}
You need to move your code out of run method and put into for loop directly. Put only toast inside run method.
1. Implement a timer task and schedule it after every 2seconds
int value = 1;
Timer timer = new Timer();
TimerTask task = new TimerTask() {
#Override
public void run() {
Toast.makeText(KCRdestActivity.this, value, Toast.LENGTH_LONG).show();
value++;
}
};
timer.schedule(task, 2000);
OR
2. Change your code to
Try
for (langId = 1; langId <= 3; langId++) {
delayTime += 2000;
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Toast.makeText(KCRdestActivity.this, String.valueOf(langId), Toast.LENGTH_LONG).show();
}
}, delayTime);
}
You can use an AsyncTask for this.
public class MyAsyncTask extends AsyncTask<Void, Integer, Void> {
#Override
protected Void doInBackground(Void... params) {
for (int langId = 1; langId <= 3; langId++) {
publishProgress(langId);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Toast.makeText(KCRdestActivity.this, String.valueOf(values[0]), Toast.LENGTH_LONG).show();
}
}
use this method
declare global these classes
private int TIME_STAMP_INTERVAL = 2000;
private Runnable runnable = null;
private int count=0;
final Handler handler = new Handler();
then add this in method which u call
runnable = new Runnable() {
#Override
public void run() {
Toast.makeText(context, ""count++, Toast.LENGTH_SHORT).show();
handler.postDelayed(runnable, TIME_STAMP_INTERVAL);
}
};
handler.post(runnable);
A quick and dirty way to achieve this using Thread.sleep(2000):
public static void main(String[] args) {
Runnable forLoop = () -> {
for (int i = 1; i <= 3; i++) {
System.out.print(i); // Do your stuff
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
new Thread(forLoop).start();
}
Output:
1 -> 2000ms -> 2 -> 2000ms -> 3
I need to calculate time between two time. System.currentTimeMillis() returns same value everytime when it called in Thread.
My code is:
#Override
protected void onCreate(Bundle savedInstanceState) {
// Other codes..
start_sec = Math.round(System.currentTimeMillis()/1000);
fin = false;
runThread();
// Other codes..
}
private void runThread() {
new Thread() {
public void run() {
while (i++ < 61) {
if (!running) return;
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
if(!fin){
int len = Math.round(System.currentTimeMillis()/1000) - start_sec;
Log.d("current time: ",String.valueOf( Math.round(System.currentTimeMillis()/1000)));
Log.d("difference is: ", String.valueOf(len));
if(len < 0 && len > 58){
fin=true;
}
timerec.getLayoutParams().width = metrics.widthPixels *(60- len)/60;
timerec.requestLayout();
}
else{
end_game();
running= true;
}
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
Here is the logs:
...
D/current time:: 1492337024
D/difference is:: 0
D/current time:: 1492337024
D/difference is:: 0
....
It returs same "time". What is the solution?
take time as long. and don't divide it by 1000. the time difference is fraction of seconds.that's why it is showing the same time as you are rounding it.
the difference between two cycle in a while loop is so much less than a second and when your calculating the difference by seconds (you divide current millisecond with 1000) it makes the same second and the difference is 0 seconds.
try to print difference in milliseconds (without dividing).
Try this:
#Override
protected void onCreate(Bundle savedInstanceState) {
// Other codes..
start_sec = System.currentTimeMillis();
fin = false;
runThread();
// Other codes..
}
private void runThread() {
new Thread() {
public void run() {
while (i++ < 61) {
if (!running) return;
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
if(!fin){
int len = System.currentTimeMillis() - start_sec;
Log.d("current time: ",String.valueOf( System.currentTimeMillis()));
Log.d("difference is: ", String.valueOf(len));
if(len < 0 && len > 58){
fin=true;
}
timerec.getLayoutParams().width = metrics.widthPixels *(60- len)/60;
timerec.requestLayout();
}
else{
end_game();
running= true;
}
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
Math.round() causes the problem.
long len = System.currentTimeMillis()/1000 - start_sec;
Log.d("current time: ",String.valueOf(System.currentTimeMillis()/1000));
Log.d("difference is: ", String.valueOf(len));
This code works altought dividing.
Im a beginner android developer, so bear with me:
Im getting this error: "CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views"
Anyways, i have a media player with two threads, the first one updates a circular progress bar and the second one updates a text view that i want to use to show the time in the mp3 file. The first thread gives me no errors and runs perfectly fine. (I implemented this before the textview update)
The second thread however gives me the error in the title. I've looked into handlers asynctasks and runonuithread but I can't figure out how to utilize any of them since im using a while loop that's constantly updating it.
Also, why is only the second one giving me an error?
new Thread(new Runnable() {
#Override
public void run() {
ProgressBar myProgress = (ProgressBar) findViewById(R.id.circle_progress_bar);
int currentPosition = 0;
int total = mediaPlayer.getDuration();
myProgress.setMax(total);
while (mediaPlayer != null && currentPosition < total) {
try {
Thread.sleep(1000);
currentPosition = mediaPlayer.getCurrentPosition();
} catch (InterruptedException e) {
return;
} catch (Exception e) {
return;
}
myProgress.setProgress(currentPosition);
}
}
}).start();
new Thread(new Runnable() {
#Override
public void run() {
TextView currentTime = (TextView) findViewById(R.id.textView9);
int currentPosition = 0;
int total = mediaPlayer.getDuration();
while (mediaPlayer != null && currentPosition < total) {
try {
Thread.sleep(1000);
currentPosition = mediaPlayer.getCurrentPosition();
} catch (InterruptedException e) {
return;
} catch (Exception e) {
return;
}
currentTime.setText(getTimeString(currentPosition));
}
}
}).start();
And here's the code for getTimeString:
private String getTimeString(long millis) {
StringBuffer buf = new StringBuffer();
int hours = (int) (millis / (1000*60*60));
int minutes = (int) (( millis % (1000*60*60) ) / (1000*60));
int seconds = (int) (( ( millis % (1000*60*60) ) % (1000*60) ) / 1000);
buf
.append(String.format("%02d", hours))
.append(":")
.append(String.format("%02d", minutes))
.append(":")
.append(String.format("%02d", seconds));
return buf.toString();
}
do
myProgress.setMax(total);
in
runOnUIThread(new Runnable () {
#Override
public void run () {
myProgress.setMax(total);
}
});
Explanation
Views in android are only work/change/created on UI threads only. Other worker thread donot modify UI elements in Android, because Android is single threaded application.
You can also use AsyncTask which have onPreExecute() and onPostExecute() methods which run on UI thread to post updates to UI
As ρяσѕρєя K say, you can't update view in non-ui thread(Main Thread), so you can use a handler to finish this work
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// TODO : change currentTime and myProgress as a class number //
TextView currentTime = (TextView) findViewById(R.id.textView9);
ProgressBar myProgress = (ProgressBar) findViewById(R.id.circle_progress_bar);
if (msg.what == 0) {
currentTime.setText(getTimeString(msg.arg1));
} else if (msg.what == 1) {
myProgress.setProgress(msg.arg1);
}
}
};
Then in you two thread, replace
// myProgress.setProgress(currentPosition);
handler.obtainMessage(1, currentPosition, 0).sendToTarget();
// currentTime.setText(getTimeString(currentPosition));
// param1 -> msg.what, param2 -> msg.arg1, parm3 -> msg.arg2
handler.obtainMessage(0, currentPosition, 0).sendToTarget();
Do you Ui work in run On Ui thread :
example:
new Thread(new Runnable() {
#Override
public void run() {
int currentPosition = 0;
int total = mediaPlayer.getDuration();
while (mediaPlayer != null && currentPosition < total) {
try {
Thread.sleep(1000);
currentPosition = mediaPlayer.getCurrentPosition();
} catch (InterruptedException e) {
return;
} catch (Exception e) {
return;
}
runOnUIThread(new Runnable () {
#Override
public void run () {
ProgressBar myProgress = (ProgressBar) findViewById(R.id.circle_progress_bar);
myProgress.setMax(total);
myProgress.setProgress(currentPosition);
}
});
}
}
}).start();