I am currently building an app that plays music on a wifi speaker. The app can connect to multiple speakers, and each speaker plays different music.
Due to frequent loss in receiving the song playing progress sent by the speakers to the app, I have to run one timer for each speaker that is playing a music in order to keep track of the song progress continuously. So that every time I receive a song progress, I will just update the timer, and then the timer will start counting from the updated song progress.
This is the code that runs a timer.
public class SongTimer
{
Timer mTimer;
int count;
long duration;
int groupAddress;
SongTimerListener listener;
boolean timer;
private Handler mHandler = new Handler();
public interface SongTimerListener
{
public void onPositionCounted(int position);
public void onFinishCounting();
}
public SongTimer(int position, long duration, int groupAddress, SongTimerListener listener)
{
this.listener = listener;
this.count = position;
this.duration = duration;
this.groupAddress = groupAddress;
timer = true;
}
public void startTimer()
{
mTimer = new Timer();
mTimer.schedule(new TimerTask()
{
#Override
public void run()
{
if (timer)
{
if(count<=(duration/1000))
{
mHandler.post(new Runnable()
{
public void run(){
if (DataHolder.PlayProgress.containsKey(DataHolder.tSpeaker.mAddress))
{
long progress = DataHolder.PlayProgress.get(DataHolder.tSpeaker.mAddress);
count=(int)progress;
}
}
});
}
else
{
mHandler.post(new Runnable()
{
public void run()
{
count = 0;
}
});
}
}
else
{
mHandler.post(new Runnable()
{
public void run()
{
mTimer.cancel();
mTimer = null;
if(SongTimer.this.listener != null)
{
SongTimer.this.listener.onFinishCounting();
}
}
});
}
count++;
if(SongTimer.this.listener != null)
{
SongTimer.this.listener.onPositionCounted(count);
}
}
}, 1000, 1000);
}
public void stopTimer()
{
timer = false;
DataHolder.PlayProgress.put(this.groupAddress, (long)count);
}
}
The user chooses a speaker and then one timer will be started when user plays a music with the speaker. When the user switches to another speaker and plays a song with it, a new timer will be started again. All the timers that were started will be stored in a HashMap using the groupAddress as the key for the object, timer.
When user taps pause, timer will be fetch from the HashMap and then terminate it, but the last position counted will be remembered.
When user taps resume time will be started again (new Timer()) and then starts counting from the last position stored.
Here comes the problem:
When multiple timers start to run, they work fine. But when the user taps pause, one timer will be fetch from the HashMap and then terminate it. But unfortunately all timers were terminated at the same time. I checked the Log for the object ID of the timers, they were all different. So I don't understand what is wrong here.
Please help. Many Thanks!
try this one
public class SongTimer{
int count;
long duration;
int groupAddress;
SongTimerListener listener;
boolean timer,run;
View user; //the view who this is going to be attached to
public interface SongTimerListener {
public void onPositionCounted(int position);
public void onFinishCounting();
}
//your constructor
public SongTimer(int position, long duration, int groupAddress,
SongTimerListener listener, View viewToAttach){ //added new parameter
this.listener = listener;
this.count = position;
this.duration = duration;
this.groupAddress = groupAddress;
timer = run = true;
user = viewToAttach;
new Thread(new Runnable() { // your timer
#Override
public void run() {
while(run){
if(!timer)
continue;
//now add your implementation here, (its too late here)
//put your code that you already have here, but minor changes
//if you need to call a Ui method use the user.post(runnable); it
// the same as handler.post(runnable), also with this you have
// reference to your view to which you want to alter, so all you
// to do is do what you want to do easily without actually needing
// your interface call. and all Views that they rely on the music
//mechanism that you talked about will each have an instance of this
//class. your pausing mechanism has already being implemented so
//maintain your old pausing mechanism. Also if you are done and want
// totally stop the thread or kill this class set the boolean run
//variable to false.
}
}).start();
}
hope it helps
Related
I am using facebook graph request for uplaoding video. This api has onProgressCallback method which gives current bytes written and maximum bytes that can be written for a file as follows:
#Override
public void onProgress(final long current, final long max) {
if (isFirstLoad) {
progressBarHorizonatl.setProgress(0);
progressBarHorizonatl.setMax((int) max);
isFirstLoad = false;
}
progressBarHorizontal.setProgress((int) current);
}
this method is called repeatedly while uploading the video but progress bar is not updated. It will get updated at the last call only. Can anyone help me what might be the problem.
Update ProgressBar on UI thread. Try attached code.
#Override
public void onProgress(final long current, final long max) {
if (isFirstLoad) {
progressBarHorizonatl.setProgress(0);
progressBarHorizonatl.setMax((int) max);
isFirstLoad = false;
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Log.d("UI thread", "I am the UI thread");
progressBarHorizontal.setProgress((int) current);
}
});
}
In my program, it is needed to receive user latitude and longitude as soon as GPS is Enabled... I'm using onGpsStatusChanged to constantly check GPS Status and the checking works... The only problem is that it tries to retrieve user location instantly, and it returns latitude 0.0 and longitude 0.0 cause it takes some seconds to get those informations... If I try to retrieve some seconds later using clickListener on a button it works perfectly...
Then I thought: If I could make the device wait some seconds after GPS is Enabled and only then retrieve the coordinates it would work...
But: If I use another Thread or AsyncTask (already tried both), it keeps returning 0.0 for coordinates, cause the real coordinates are cached into the Map's Main Activity Thread...
So, how to make android wait in the main Thread? I've tried 'wait(long)' and the app crashes. I'm trying to solve this for weeks and my time is running out... Some holy soul help me please
you can achieve that by using handler
int time=3000 // in milliseconds
Handler h=new Handler();
h.postDelayed(new Runnable() {
#Override
public void run() {
//here you can do the job
}
},time);
if you want to update the UI from the handler you will end up with an error but you can userunOnUiThread
runOnUiThread(new Runnable() {
#Override
public void run() {
//code to update the ui
}
});
good luck
i not recommend you handler,you can use Interface here.
where you get all values use pass it to your activity and use that one.
Here i have posted example just try to follow and use this way.
You can pass interval here according to your need.
public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 30000
and one more thing you can pass fastest interval that is also help you.
Thanks
I have been creating a simple Waiter class for it. It is really easy to understand and does the job very well. I post it for those who need it. just copy Waiter class and WaitListener interface and use it like I show.
Here is the Class:
import android.os.Handler;
import android.os.Looper;
public class Waiter {
WaitListener waitListener;
int waitTime = 0;
Handler handler;
int waitStep = 1000;
int maxWaitTime = 5000;
boolean condition = false;
public Waiter(Looper looper, final int waitStep, final int maxWaitTime){
handler = new Handler(looper);
this.waitStep = waitStep;
this.maxWaitTime = maxWaitTime;
}
public void start(){
handler.post(new Runnable() {
#Override
public void run() {
waitListener.checkCondition();
if (condition) {
waitListener.onConditionSuccess();
} else {
if (waitTime <= maxWaitTime) {
waitTime += waitStep;
handler.postDelayed(this, waitStep);
} else {
waitListener.onWaitEnd();
}
}
}
});
}
public void setConditionState(boolean condition){
this.condition = condition;
}
public void setWaitListener(WaitListener waitListener){
this.waitListener = waitListener;
}
}
And here is the Interface :
public interface WaitListener {
public void checkCondition();
public void onWaitEnd();
public void onConditionSuccess();
}
You can for example use it like that for a connection check:
ConnectivityManager mConnMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
final int result = mConnMgr.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "enableMMS");
final Waiter waiter = new Waiter(getMainLooper(), 1000, 5000);
waiter.setWaitListener(new WaitListener() {
#Override
public void checkCondition() {
Log.i("Connection", "Checking connection...");
NetworkInfo networkInfo = mConnMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_MMS);
waiter.setConditionState(networkInfo.isConnected());
}
#Override
public void onWaitEnd() {
Log.i("Connection", "No connection for sending");
//DO
}
#Override
public void onConditionSuccess() {
Log.i("Connection", "Connection success, sending...");
//DO
}
});
waiter.start();
I'm making simple android app which should have counter which counts from 60 seconds down to 0 seconds. I have one idea how to do it, but I'm not sure if it is the smartest way to do it. And I'm not sure how to make it work in the code.
Idea:
In the .xml file I have added textView. I would make MyService class that extends Service which will be called by the .java file inside OnCreate function (because I want that counting starts immediately). MyService will change content of textView every second (I will have int counter which will be decreased every second and then text of textView will be changed).
Is there any better way to do it?
Here is MyService class:
public class MyService extends Service {
//for timer:
int counter = 0;
static final int UPDATE_INTERVAL = 1000;
private Timer timer = new Timer();
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
doSomethingRepeatedly();
return START_STICKY;
}
private void doSomethingRepeatedly() {
timer.scheduleAtFixedRate( new TimerTask() {
public void run() {
//code for changing the content
}
}, 0, UPDATE_INTERVAL);
}
#Override
public void onDestroy() {
super.onDestroy();
//za timer
if (timer != null){
timer.cancel();
}
}
}
Do I have to put this code in separate .java file?
I'm not sure how to write code for changing the content of textView, because I'm not sure if I can call id of textView because it is in the separated file?
These would be functions for starting the Services:
public void startService(View view) {
startService(new Intent(getBaseContext(), MyService.class));
}
public void stopService(View view) {
stopService(new Intent(getBaseContext(), MyService.class));
}
Where do I have to put them?
Use a CountDownTimer.
Schedule a countdown until a time in the future, with regular
notifications on intervals along the way. Example of showing a 30
second countdown in a text field:
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
The calls to onTick(long) are synchronized to this object so that one
call to onTick(long) won't ever occur before the previous callback is
complete. This is only relevant when the implementation of
onTick(long) takes an amount of time to execute that is significant
compared to the countdown interval.
I am trying to passthrough the input obtained from the microphone to the speaker (the goal is to be able to perform audio processing in real time in the future). This is the code:
public class MainActivity extends Activity {
AudioManager am = null;
AudioRecord record =null;
AudioTrack track =null;
final int SAMPLE_FREQUENCY = 44100;
final int SIZE_OF_RECORD_ARRAY = 1024; // 1024 ORIGINAL
final int WAV_SAMPLE_MULTIPLICATION_FACTOR = 1;
int i= 0;
boolean isPlaying = true;
class MyThread extends Thread{
#Override
public void run(){
recordAndPlay();
}
}
MyThread newThread;
private void init() {
int min = AudioRecord.getMinBufferSize(SAMPLE_FREQUENCY, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
record = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, SAMPLE_FREQUENCY, AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, min);
int maxJitter = AudioTrack.getMinBufferSize(SAMPLE_FREQUENCY, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
track = new AudioTrack(AudioManager.MODE_IN_COMMUNICATION, SAMPLE_FREQUENCY, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, maxJitter, AudioTrack.MODE_STREAM);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setVolumeControlStream(AudioManager.MODE_IN_COMMUNICATION);
init();
newThread = new MyThread();
newThread.start();
}
#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;
}
private void recordAndPlay() {
short[] lin = new short[SIZE_OF_RECORD_ARRAY];
int num = 0;
am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
am.setMode(AudioManager.MODE_IN_COMMUNICATION);
record.startRecording();
track.play();
while (true) {
num = record.read(lin, 0, SIZE_OF_RECORD_ARRAY);
for(i=0;i<lin.length;i++)
lin[i] *= WAV_SAMPLE_MULTIPLICATION_FACTOR;
track.write(lin, 0, num);
}
}
public void passStop(View view){
Button playBtn = (Button) findViewById(R.id.playBtn);
// /*
if(!isPlaying){
record.startRecording();
track.play();
isPlaying = true;
playBtn.setText("Pause");
}
else{
record.stop();
track.pause();
isPlaying=false;
playBtn.setText("Pass through");
}
// */
}
/*
#SuppressWarnings("deprecation")
#Override
public void onDestroy(){
newThread.stop();
}
*/
#Override
protected void onDestroy() {
android.os.Process.killProcess(android.os.Process.myPid());
// killProcess(android.os.Process.myPid());
}
}
Brief overview:
The while(true) {} infinite loop in recordAndPlay() function continuously reads raw audio samples from the microphone and outputs the raw samples to the speaker. recordAndPlay() is called from a Thread started in the onCreate() function. So it starts sending the input on the microphone to the speaker as soon as the program starts (well actually after a few seconds lag but I think this latency in unavoidable). I also have a button that can pause and resume this pass through. Now if the Thread is not stopped, the pass through continues even when I exit the application or the application looses focus (so even when the phone is on the desktop it keeps doing the passthrough).
#SuppressWarnings("deprecation")
#Override
public void onDestroy(){
newThread.stop();
}
This code causes the app to crash on exit (Why?) so I used
#Override
protected void onDestroy() {
android.os.Process.killProcess(android.os.Process.myPid());
// killProcess(android.os.Process.myPid());
}
that I found somewhere in stackoverflow (I forgot where). It seems to do what I want for now, but I want know if this is the proper way to stop the Thread or not. It does what I need, that is, it stops the passthrough when I exit the application, but I am not sure what exactly the killProcess() function does to my application overall, and if it is the best way to stop a Thread that I started myself.
Also, I can get the same effect if I exit my application (or loose focus to it) while the passthrough is being paused. But I assume this means the Thread is still running which means the infinite loop is also continuously running as well. Is it a good idea to do this, that is, just leave the Thread running, as long as my overall program is behaving as I want it to? What if I have lots of Threads or other background processes running? Can this practice cause memory problems in the future if the app grows too big?
Threads should periodically check for some shouldTerminate flag in their loop, then just set this flag from UI thread and (optionally) wait until thread terminate gracefully. Don't forget volatile or proper field synchronization.
Please remember to call super.onDestroy after releasing your memory or finishing the thread. Otherwise it will throw Exception:
#Override
protected void onDestroy() {
// You code here to finish the thread
super.onDestroy(); // Please call THIS too
}
Hope this helps.
Change your Thread class to something like this:
class MyThread extends Thread {
private volatile boolean finished = false;
#Override
public void run() {
while (!finished) {
// do stuff on thread
}
}
public void stopThread() {
finished = true;
}
}
In your onDestroy method call stopThread().
#Override
protected void onDestroy() {
newThread.stopThread();
super.onDestroy();
}
If you wish, you can also wait for thread to stop, by using this method:
private void joinThread(Thread thread) {
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// to be handled as you wish
}
}
}
Put this method in your activity and call it after newThread.stopThread().
There is already a provided flag for interuption.
Correct your while loop to the following.
And just call interupt(); in onDestroy or wherever.
private class thrd extends Thread {
#Override
public void run() {
super.run();
while (!isInterrupted()) {
//TODO
}
}
}
#Override
protected void onDestroy() {
super.onDestroy();
thrd.interupt();
}
I'm trying to make a countdown timer in android for use in a small android app. The app will countdown from some number of seconds to 0, upon which it will do some action. I'm using the coundowntimer supplied by android.os.countdowntimer. Here is my code:
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.quizlayout);
new CountDownTimer(30000, 1000) {
TextView tx = (TextView) findViewById(R.id.textView2);
public void onTick(long millisUntilFinished) {
tx.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
tx.setText("done!");
}
}.start();
}
However, this countdown timer is really slow. It takes like 3 real-time seconds for the timer to countdown by one second. I wonder what's going on? The code I have above is more or less copied straight from google (CountDownTimer)
Can anyone help me as per why my timer is so slow, and offer a way to speed it up a bit?
(EDIT): I am running this on an emulator, the intel atom x86. I am emulating an android 2.3.3 environment.
According to Android documentation for countdown timer
The calls to onTick(long) are synchronized to this object so that one call to onTick(long) won't ever occur before the previous callback is complete. This is only relevant when the implementation of onTick(long) takes an amount of time to execute that is significant compared to the countdown interval.
Take a look at this example for countdown timer
Countdown timer example
Alternately you can spawn a new thread and just get that thread to sleep for the interval you want and take actions when it wakes or vice versa.
You can also timertask
use a handler that will post the same runnable . this will remove the need for extra threads :
Handler handler=new Handler();
handler.postRunnable(... , 1000) ;
in the runnable , call the postRunnable again for the same handler (and add a condition for when to stop) .
CountDownTimer is not efficient regardless to ui updating performances. For a flawless ui update, it is better to create a custom countdown. I did my own so here it is. It is flawless on my app.
public abstract class CountDown {
int totalTime = 0;
int tickTime = 0;
Thread thread;
boolean canceled = false;
public CountDown(int totalTime,int tickTime){
this.totalTime = totalTime;
this.tickTime = tickTime;
}
public abstract void onTick();
public abstract void onFinish();
public void start(){
thread = new Thread(new Runnable() {
#Override
public void run() {
// Do in thread
canceled = false;
for (int elapsedTime = 0; elapsedTime < totalTime; elapsedTime += tickTime) {
if(!canceled){
onTick();
try {
thread.sleep(tickTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
break;
}
}
if(!canceled){
onFinish();
}
}
});
thread.start();
}
public void cancel(){
canceled = true;
}
}
Remember that every time you have to update your ui, call a runOnUiThread, or else you will have an exception, you are not in a handler and not on ui thread.
Here is how to use it in your code, it is identical to CountDownTimer, so you could just rename lines in your code :
CountDown cDown = new CountDown(10000, 20) {
public void onTick() {
// Do something
}
public void onFinish() {
runOnUiThread(new Runnable() {
#Override
public void run() {
myButton.setImageDrawable(drawable);
}
});
}
};