Update Android Service TextView from Activity/ Static Method - android

Background:
I've created a custom service as:
public class FloatingViewService extends Service {
public static FloatingViewService self;
onCreate() {
self = this;
addView(....)
}
...
...
public void updateText ( String newText) { this.textView.setText(newText) };
}
OnCreate event of this service, it sets a view using WindowManager.addView(...) and also set an instance pointer in self variable for future use.
Now this view is just a textview, that stays on the top of activities, regardless.
What I want to achieve:
I want to send some data from a static method that runs using ExecutorService instance, which should update textview text.
How I use this service:
Inside of an activity, I make a call to a static method that logs some values:
public class MyActivity: Activity
{
public void log() {
LogUtil.log(new Runnable() {
#Override
public void run() {
//log api call
FloatingViewService.self.updateText("New Text");
}
}) ;
}
}
Now you can see that I am making a call to an updateText method present in service, from different thread.
Here is how the LogUtil is:
public class LogUtil {
private static ExecutorService taskExecutorService = ThreadUtils.createTimedExecutorService(TASK_POOL_SIZE, TASK_POOL_IDLE_ALIVE_SECONDS,
TimeUnit.SECONDS, new LowPriorityThreadFactory());
public static log(Runnable runnable) {
taskExecutorService.submit(new Runnable() {
#Override
public void run() {
try {
runnable.run();
} catch (Exception ex) {
../
}
}
});
Now the problem is, it cannot update textview text. I can understand it is due to thread. But I have no clue on how to achieve it - is there any UIthread for service ?

Here is my code for example .. you shuold be able to pick the necesary parts from it. as Selvin said you have to create an Incoming handler on both sides to send information from one thread to the other...
Here is my service code
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import com.pekam.myandroidtheme.*;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
public class MyService extends Service {
private NotificationManager nm;
private Timer timer = new Timer();
private int counter = 0, incrementby = 1;
private static boolean isRunning = false;
ArrayList<Messenger> mClients = new ArrayList<Messenger>(); // Keeps track of all current registered clients.
int mValue = 0; // Holds last value set by a client.
static final int MSG_REGISTER_CLIENT = 1;
static final int MSG_UNREGISTER_CLIENT = 2;
static final int MSG_SET_INT_VALUE = 3;
static final int MSG_SET_STRING_VALUE = 4;
final Messenger mMessenger = new Messenger(new IncomingHandler()); // Target we publish for clients to send messages to IncomingHandler.
#Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
class IncomingHandler extends Handler { // Handler of incoming messages from clients.
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_CLIENT:
mClients.add(msg.replyTo);
break;
case MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
break;
case MSG_SET_INT_VALUE:
incrementby = msg.arg1;
break;
default:
super.handleMessage(msg);
}
}
}
private void sendMessageToUI(int intvaluetosend) {
for (int i=mClients.size()-1; i>=0; i--) {
try {
// Send data as an Integer
mClients.get(i).send(Message.obtain(null, MSG_SET_INT_VALUE, intvaluetosend, 0));
//Send data as a String
Bundle b = new Bundle();
b.putString("str1", "ab" + intvaluetosend + "cd");
Message msg = Message.obtain(null, MSG_SET_STRING_VALUE);
msg.setData(b);
mClients.get(i).send(msg);
} catch (RemoteException e) {
// The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop.
mClients.remove(i);
}
}
}
#Override
public void onCreate() {
super.onCreate();
Log.i("MyService", "Service Started.");
showNotification();
timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 0, 100L);
isRunning = true;
}
private void showNotification() {
nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.service_started);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.ic_launcher, text, System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, TabBarActivity.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, getText(R.string.service_label), text, contentIntent);
// Send the notification.
// We use a layout id because it is a unique number. We use it later to cancel.
nm.notify(R.string.service_started, notification);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("MyService", "Received start id " + startId + ": " + intent);
return START_STICKY; // run until explicitly stopped.
}
public static boolean isRunning()
{
return isRunning;
}
private void onTimerTick() {
Log.i("TimerTick", "Timer doing work." + counter);
try {
counter += incrementby;
sendMessageToUI(counter);
} catch (Throwable t) { //you should always ultimately catch all exceptions in timer tasks.
Log.e("TimerTick", "Timer Tick Failed.", t);
}
}
#Override
public void onDestroy() {
super.onDestroy();
if (timer != null) {timer.cancel();}
counter=0;
nm.cancel(R.string.service_started); // Cancel the persistent notification.
Log.i("MyService", "Service Stopped.");
isRunning = false;
}
}
here is my android form app code
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import com.pekam.myandroidtheme.*;
public class MyServiceControllerActivity extends Activity {
Button btnStart, btnStop, btnBind, btnUnbind, btnUpby1, btnUpby10;
TextView textStatus, textIntValue, textStrValue;
Messenger mService = null;
boolean mIsBound;
final Messenger mMessenger = new Messenger(new IncomingHandler());
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyService.MSG_SET_INT_VALUE:
textIntValue.setText("Int Message: " + msg.arg1);
break;
case MyService.MSG_SET_STRING_VALUE:
String str1 = msg.getData().getString("str1");
textStrValue.setText("Str Message: " + str1);
break;
default:
super.handleMessage(msg);
}
}
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger(service);
textStatus.setText("Attached.");
try {
Message msg = Message.obtain(null, MyService.MSG_REGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
// In this case the service has crashed before we could even do anything with it
}
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been unexpectedly disconnected - process crashed.
mService = null;
textStatus.setText("Disconnected.");
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.exampleservice);
btnStart = (Button)findViewById(R.id.btnStart);
btnStop = (Button)findViewById(R.id.btnStop);
btnBind = (Button)findViewById(R.id.btnBind);
btnUnbind = (Button)findViewById(R.id.btnUnbind);
textStatus = (TextView)findViewById(R.id.textStatus);
textIntValue = (TextView)findViewById(R.id.textIntValue);
textStrValue = (TextView)findViewById(R.id.textStrValue);
btnUpby1 = (Button)findViewById(R.id.btnUpby1);
btnUpby10 = (Button)findViewById(R.id.btnUpby10);
btnStart.setOnClickListener(btnStartListener);
btnStop.setOnClickListener(btnStopListener);
btnBind.setOnClickListener(btnBindListener);
btnUnbind.setOnClickListener(btnUnbindListener);
btnUpby1.setOnClickListener(btnUpby1Listener);
btnUpby10.setOnClickListener(btnUpby10Listener);
restoreMe(savedInstanceState);
CheckIfServiceIsRunning();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("textStatus", textStatus.getText().toString());
outState.putString("textIntValue", textIntValue.getText().toString());
outState.putString("textStrValue", textStrValue.getText().toString());
}
private void restoreMe(Bundle state) {
if (state!=null) {
textStatus.setText(state.getString("textStatus"));
textIntValue.setText(state.getString("textIntValue"));
textStrValue.setText(state.getString("textStrValue"));
}
}
private void CheckIfServiceIsRunning() {
//If the service is running when the activity starts, we want to automatically bind to it.
if (MyService.isRunning()) {
doBindService();
}
}
private OnClickListener btnStartListener = new OnClickListener() {
public void onClick(View v){
startService(new Intent(MyServiceControllerActivity.this, MyService.class));
}
};
private OnClickListener btnStopListener = new OnClickListener() {
public void onClick(View v){
doUnbindService();
stopService(new Intent(MyServiceControllerActivity.this, MyService.class));
}
};
private OnClickListener btnBindListener = new OnClickListener() {
public void onClick(View v){
doBindService();
}
};
private OnClickListener btnUnbindListener = new OnClickListener() {
public void onClick(View v){
doUnbindService();
}
};
private OnClickListener btnUpby1Listener = new OnClickListener() {
public void onClick(View v){
sendMessageToService(1);
}
};
private OnClickListener btnUpby10Listener = new OnClickListener() {
public void onClick(View v){
sendMessageToService(10);
}
};
private void sendMessageToService(int intvaluetosend) {
if (mIsBound) {
if (mService != null) {
try {
Message msg = Message.obtain(null, MyService.MSG_SET_INT_VALUE, intvaluetosend, 0);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
}
}
}
}
void doBindService() {
bindService(new Intent(this, MyService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
textStatus.setText("Binding.");
}
void doUnbindService() {
if (mIsBound) {
// If we have received the service, and hence registered with it, then now is the time to unregister.
if (mService != null) {
try {
Message msg = Message.obtain(null, MyService.MSG_UNREGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
// There is nothing special we need to do if the service has crashed.
}
}
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
textStatus.setText("Unbinding.");
}
}
#Override
protected void onDestroy() {
super.onDestroy();
try {
doUnbindService();
} catch (Throwable t) {
Log.e("TabBarActivity", "Failed to unbind from the service", t);
}
}
}

You need to stay on UIThread to update UI. A solution may be:
Create a static reference of activity. Remember to set it on resume method of activity and to unset it on pause method.
On the service side you can invoke a method of activiy to update UI.
Translating those operations in pseudocode. The activity will become :
public class MainActivity extends Activity {
public static MainActivity reference;
...
public onResume() {
reference=this;
}
public onPause() {
reference=null;
}
public void needToUpdateText(final String text)
{
runOnUiThread(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread with text "+text);
});
}
}
}
And the service class:
public class FloatingViewService extends Service {
...
public void updateText ( String newText)
{
if (MainActivity.reference!=null)
{
MainActivity.reference.needUpdateText(newText);
}
};
}

Related

How to pause/play background music in MainActivity in Android?

I'm calling the service MusicaFundo in Splashscreen.class and want to pause/play it in MainActivity.class.
I'm trying with a sendBroadcast but the service is not receiving the intent, I have created the BroadcastReceiver, MyServiceReceiver, inside MusicaFundo.class, is it wrong to do like this?
MainActivity.class
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
boolean musicaTocar = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent svc = new Intent (this, MusicaFundo.class);
TextView titulo = findViewById(R.id.titulo);
final ImageView som = findViewById(R.id.som);
som.setBackgroundResource(R.drawable.volumeup);
final ImageView jogomem = findViewById(R.id.jogomem);
jogomem.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Animation diminuir = (Animation) AnimationUtils.loadAnimation(MainActivity.this, R.anim.diminuir);
jogomem.startAnimation(diminuir);
Intent jogomemoria = new Intent(MainActivity.this, JogoMemoria.class);
startActivity(jogomemoria);
}
});
Animation deslocarD = (Animation) AnimationUtils.loadAnimation(this, android.R.anim.slide_in_left);
titulo.startAnimation(deslocarD);
som.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!musicaTocar){
som.setBackgroundResource(R.drawable.volumemut);
playMusica();
musicaTocar = true;
}
else {
if (musicaTocar){
som.setBackgroundResource(R.drawable.volumeup);
pausarMusica();
musicaTocar = false;
}
}
}
});
}
private void pausarMusica() {
Intent pausar = new Intent();
pausar.setAction("pausar");
sendBroadcast(pausar);
}
private void playMusica() {
Intent tocar = new Intent();
tocar.setAction("tocarmusica");
sendBroadcast(tocar);
}
Inside MusicaFundo.class
public class MusicaFundo extends Service {
private MediaPlayer player;
public int posatual = 0;
private static final String TAG = "MusicaFundo";
public static Object getName() {
return null;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate(){
player = MediaPlayer.create(this, R.raw.musicafundo);
player.setLooping(true);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
player.seekTo(posatual);
player.start();
return START_STICKY;
}
public boolean onUnbind(Intent intent){
return false;
}
#Override
public void onDestroy() {
super.onDestroy();
if (player != null) {
if (player.isPlaying()) {
player.stop();
}
player.release();
}
}
public void resumeMusic(){
if (player != null) {
if (player.isPlaying() == false) {
player.seekTo(posatual);
player.start();
}
}
}
public void onPause(){
if (player != null) {
if (player.isPlaying()) {
posatual = player.getCurrentPosition();
player.pause();
}
}
}
public class MyServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String pausa = intent.getAction();
if(pausa.equals("pausar")){
onPause();
Log.d(TAG, "onReceive: " + pausa);
}
else if(pausa.equals("tocarmusica")){
resumeMusic();
Log.d(TAG, "onReceive: " + pausa);
}
}
}
Want to receive intent so it compares the string to pause or play.
Not sure if the code is just not complete in the question but you need to call registerReceiver in your service for the receiver to actually receive broadcasts.
Also, if this is mostly communication within the same process, I suggest using LocarBroadcastManager as it is more efficient and secure.

Play a .wav file and then Android Text To Speech in a loop

Requirement is to play a chime sound an phrase after that using Android Text to Speech.
for (final Integer orderId : voiceoverIds) {
alertChimePlayer = MediaPlayer.create(getApplicationContext(), R.raw.orderalert);
alertChimePlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
String orderSpeechText = "Number " + orderId;
textToSpeech.speak(orderSpeechText, TextToSpeech.QUEUE_ADD, null, "ORDER_NO_" + orderId);
textToSpeech.playSilentUtterance(2000, TextToSpeech.QUEUE_ADD, "PAUSE_NO_" + orderId);
System.out.println(">>>>>>>>>>>>>>>>>>> orderSpeechText : " + orderSpeechText);
}
});
alertChimePlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
alertChimePlayer.start();
}
});
}
But this only works one time. How to handle this properly?
Good question. Stayed up all night on this. The problem is that in the loop, those chimes just get rapidly sent to the media player all at the same time. Media Player cant really handle that properly.
Here is my solution. I am using SoundPool to play the chime because it is better at playing short sounds in repetition.
I am also using a timer thread to trigger the "Chime + spoken text-to-speech (tts)" sequences. The tts onUtteranceProgressListener is used to play the tts after the chime sound.
Here is the tested code. What you will hear is:
chime "number 1" (3 second delay)
chime "number 2" (3 second delay)
... continues until terminated
import android.app.Activity;
import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.SoundPool;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.util.Log;
import java.util.Locale;
public class MainActivity extends Activity implements TextToSpeech.OnInitListener {
AudioAttributes aa;
SoundPool sp;
private TextToSpeech tts;
int MAX_STREAMS = 5;
int REPEAT = 0;
int DELAY = 3000;
int orderId = 0;
// Clock thread
Thread m_clockThread;
boolean m_bClockThreadStop;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("TTS", "Starting...");
// Set up the sound pool sound
AudioAttributes aa = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_MEDIA)
.build();
sp = new SoundPool.Builder()
.setMaxStreams(8)
.setAudioAttributes(aa)
.build();
// Start the tts
tts = new TextToSpeech(MainActivity.this,MainActivity.this);
tts.setLanguage(Locale.US);
}
#Override
public void onInit(int status) {
Log.e("TTS", "Enter onInit...");
if (status == TextToSpeech.SUCCESS) {
int result = tts.setLanguage(Locale.US);
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
Log.e("TTS", "This Language is not supported");
} else {
Log.e("TTS", "onInit Success");
// create and run clock thread
createAndRunClockThread(this);
}
} else {
Log.e("TTS", "onInit Fail");
}
}
public void createAndRunClockThread(final Activity act) {
m_bClockThreadStop=false;
m_clockThread = new Thread(new Runnable() {
public void run() {
while(!m_bClockThreadStop) {
try {
act.runOnUiThread(new Runnable() {
public void run() {
playChime();
}
});
Thread.sleep(DELAY);
}
catch(InterruptedException e) {
Log.e("TTS", "ClockThread fail");
}
}
}
});
m_clockThread.start();
}
private void playChime() {
Log.e("TTS", "Entering startChimes...");
sp.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
#Override
public void onLoadComplete(final SoundPool soundPool, final int soundId, int status) {
final int priority = 0;
final int repeat = 0;
final float rate = 1.f; // Frequency Rate can be from .5 to 2.0
// Set volume
AudioManager mgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
float streamVolumeCurrent = mgr.getStreamVolume(AudioManager.STREAM_MUSIC);
float streamVolumeMax = mgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
final float volume = streamVolumeCurrent / streamVolumeMax;
// Play a chime followed by the tts
tts.speak("Number " + orderId, TextToSpeech.QUEUE_ADD, null, "ID" + orderId);
tts.setOnUtteranceProgressListener(new UtteranceProgressListener() {
#Override
public void onStart(String utteranceId) {
// Speaking started.
sp.play(soundId, volume, volume, priority, repeat, rate);
}
#Override
public void onDone(String utteranceId) {
// Speaking stopped.
orderId = orderId + 1;
}
#Override
public void onError(String utteranceId) {
// There was an error.
}
});
}
});
sp.load(this, R.raw.beep, 1);
}
}
Thanks for the answer #Mark W. But I was thinking of solution that doesn't involve explicit delays/sleeps.
So I was implementing this Service Class.
public class OrderNoticeService extends Service implements TextToSpeech.OnInitListener {
private List<OrderSpeechAsyncTask> orderSpeechAsyncTasks = new ArrayList<>();
private TextToSpeech textToSpeech;
private Context context;
public void addToOrderNoticeQueue(int orderId) {
String orderSpeechText = String.format(getResources().getString(R.string.order_voice_over_default_text), Integer.toString(orderId));
orderSpeechAsyncTasks.add(new OrderSpeechAsyncTask(getApplicationContext(), R.raw.orderalert, orderSpeechText, textToSpeech, new AsyncTaskCallback() {
#Override
public void onTaskCompleted(Object response) {
}
}));
if (orderSpeechAsyncTasks.size() > 1) {
final OrderSpeechAsyncTask orderSpeechAsyncTask = orderSpeechAsyncTasks.get(orderSpeechAsyncTasks.size() - 1);
OrderSpeechAsyncTask orderSpeechAsyncTaskPrior = orderSpeechAsyncTasks.get(orderSpeechAsyncTasks.size() - 2);
orderSpeechAsyncTaskPrior.setAsyncTaskCallback(new AsyncTaskCallback() {
#Override
public void onTaskCompleted(Object response) {
try {
orderSpeechAsyncTask.execute();
System.out.println("Execution!");
} catch (Exception e) {
}
}
});
}
}
#Override
public void onCreate() {
textToSpeech = new TextToSpeech(this, this);
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
context = this;
return Service.START_STICKY;
}
private static final String TAG = "OrderNoticeService";
#Nullable
#Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "OrderNoticeService onBind");
return mBinder;
}
#Override
public void onDestroy() {
if (textToSpeech != null) {
textToSpeech.stop();
textToSpeech.shutdown();
}
Log.i(TAG, "OrderNoticeService onDestroy");
}
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
OrderNoticeVoiceOverThread orderNoticeVoiceOverThread = new OrderNoticeVoiceOverThread(context, orderSpeechAsyncTasks);
orderNoticeVoiceOverThread.start();
} else {
System.out.println("Text To Speech not supported!");
}
}
private class OrderNoticeVoiceOverThread extends Thread {
private Context context;
private List<OrderSpeechAsyncTask> orderSpeechAsyncTasks;
private boolean anyTaskRunning = false;
public OrderNoticeVoiceOverThread(Context context, List<OrderSpeechAsyncTask> orderSpeechAsyncTasks) {
this.context = context;
this.orderSpeechAsyncTasks = orderSpeechAsyncTasks;
}
public void run() {
while (true) {
for (OrderSpeechAsyncTask orderSpeechAsyncTask : new ArrayList<OrderSpeechAsyncTask>(orderSpeechAsyncTasks)) {
if (orderSpeechAsyncTask != null && orderSpeechAsyncTask.getStatus().equals(AsyncTask.Status.RUNNING)) {
anyTaskRunning = true;
break;
}
}
if (!anyTaskRunning) {
for (OrderSpeechAsyncTask orderSpeechAsyncTask : new ArrayList<OrderSpeechAsyncTask>(orderSpeechAsyncTasks)) {
if (orderSpeechAsyncTask != null && orderSpeechAsyncTask.getStatus().equals(AsyncTask.Status.PENDING)) {
orderSpeechAsyncTask.execute();
anyTaskRunning = false;
break;
}
}
}
}
}
}
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
public OrderNoticeService getService() {
return OrderNoticeService.this;
}
}
}
And the OrderSpeechAsyncTask as follows.
public class OrderSpeechAsyncTask extends AsyncTask<Void, Void, Void> {
private static final String LOG_TAG = OrderSpeechAsyncTask.class.getSimpleName();
private MediaPlayer mediaPlayer;
private int soundId;
private Context context;
private String orderSpeechText;
private AsyncTaskCallback asyncTaskCallback;
private TextToSpeech textToSpeech;
public OrderSpeechAsyncTask(final Context context, int soundId, String orderSpeechText, TextToSpeech textToSpeech, AsyncTaskCallback asyncTaskCallback) {
this.context = context;
this.soundId = soundId;
this.orderSpeechText = orderSpeechText;
this.textToSpeech = textToSpeech;
this.asyncTaskCallback = asyncTaskCallback;
}
public AsyncTaskCallback getAsyncTaskCallback() {
return asyncTaskCallback;
}
public void setAsyncTaskCallback(AsyncTaskCallback asyncTaskCallback) {
this.asyncTaskCallback = asyncTaskCallback;
}
#Override
protected Void doInBackground(Void... params) {
mediaPlayer = MediaPlayer.create(context, soundId);
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mediaPlayer.release();
textToSpeech.speak(orderSpeechText, TextToSpeech.QUEUE_ADD, null, "ORDER_NO_" + orderSpeechText);
textToSpeech.playSilentUtterance(2000, TextToSpeech.QUEUE_ADD, "PAUSE_NO_" + orderSpeechText);
textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
#Override
public void onStart(String utteranceId) {
}
#Override
public void onDone(String utteranceId) {
asyncTaskCallback.onTaskCompleted(null);
}
#Override
public void onError(String utteranceId) {
}
});
}
});
mediaPlayer.start();
return null;
}
}
This so far handles the following;
Playing the sound and the text in the list
Adding an item to the queue whilst the existing list is still being read
To do;
This doesn't handle any new item that gets added to the list once the existing items are done being read.

Trouble running background service Android

I have some simple code intended to start a background service that updates a static integer from my MainActivity every second. I also have a button that when clicked, updates a TextView with the value of that static integer. However, every time I start the service, it only increments the value once and stops, instead of continuously incrementing it until I press stop service.
This is my code:
public class MainActivity extends AppCompatActivity {
public static int count;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
count = 0;
}
public void pressButton(View view) {
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText("" + count);
}
public void startService(View view) {
startService(new Intent(getBaseContext(), MyService.class));
}
public void stopService(View view) {
stopService(new Intent(getBaseContext(), MyService.class));
}
}
And my service:
public class MyService extends Service {
public MyService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
MainActivity.count++;
}
}, 1000);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
I can't figure out what seems to be the problem.
public class DownloadService extends IntentService {
String pdfName = "";
public DownloadService() {
super("DownloadService");
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
showNotificationProgress();
if (intent != null) {
pdfName = intent.getStringExtra("pdfName");
}
downloadPDF ( ) // Implement this method
}
public void writeBytesToFile(boolean status, String encodedString) {
if (status && !TextUtils.isEmpty(encodedString)) {
byte[] decodedArry = decodeBase64String(encodedString);
String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + File.separator + pdfName;
File fileOut = new File(path);
// if file doesnt exists, then create it
if (!fileOut.exists()) {
try {
//noinspection ResultOfMethodCallIgnored
fileOut.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try (FileOutputStream fileOuputStream = new FileOutputStream(fileOut)) {
fileOuputStream.write(decodedArry);
completed = true;
} catch (IOException e) {
completed = false;
e.printStackTrace();
} finally {
if (completed) {
//do something
}
}
} else {
hideNotificationProgress();
}
}
private static byte[] decodeBase64String(String encodedString) {
return Base64.decode(encodedString, Base64.DEFAULT);
}
public static void hideNotificationProgress() {
mNotifyManager.cancel(1);
}
private void showNotificationProgress() {
final int id = 1;
mNotifyManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
mBuilder.setContentTitle("PDF Download")
.setContentText("Download in progress")
.setSmallIcon(android.R.drawable.stat_sys_download);
// Start a lengthy operation in a background thread
new Thread(
new Runnable() {
#Override
public void run() {
// Do the "lengthy" operation 20 times
// Sets the progress indicator to a max value, the
// current completion percentage, and "determinate"
// state
mBuilder.setProgress(0, 0, true);
// Issues the notification
mNotifyManager.notify(id, mBuilder.build());
// Sleeps the thread, simulating an operation
// that takes time
try {
// Sleep for 5 seconds
Thread.sleep(1000);
} catch (InterruptedException ignored) {
}
}
}
// Starts the thread by calling the run() method in its Runnable
).start();
}
}
Why don't you try Intent Service like this.
And start this service as below
Intent intent = new Intent(AActivity, DownloadService.class);
intent.putExtra("pdfName", pdfName);
holdingActivity.startService(intent);
This code shows how to update the UI in an Android Activity from a background Service.
BroadcastTest.java
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class BroadcastTest extends Activity {
private static final String TAG = "BroadcastTest";
private Intent intent;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
intent = new Intent(this, BroadcastService.class);
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateUI(intent);
}
};
#Override
public void onResume() {
super.onResume();
startService(intent);
registerReceiver(broadcastReceiver, new IntentFilter(BroadcastService.BROADCAST_ACTION));
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(broadcastReceiver);
stopService(intent);
}
private void updateUI(Intent intent) {
String counter = intent.getStringExtra("counter");
String time = intent.getStringExtra("time");
Log.d(TAG, counter);
Log.d(TAG, time);
TextView txtDateTime = (TextView) findViewById(R.id.txtDateTime);
TextView txtCounter = (TextView) findViewById(R.id.txtCounter);
txtDateTime.setText(time);
txtCounter.setText(counter);
}
}
BroadcastService.java
import java.util.Date;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
public class BroadcastService extends Service {
private static final String TAG = "BroadcastService";
public static final String BROADCAST_ACTION = "com.websmithing.broadcasttest.displayevent";
private final Handler handler = new Handler();
Intent intent;
int counter = 0;
#Override
public void onCreate() {
super.onCreate();
intent = new Intent(BROADCAST_ACTION);
}
#Override
public void onStart(Intent intent, int startId) {
handler.removeCallbacks(sendUpdatesToUI);
handler.postDelayed(sendUpdatesToUI, 1000); // 1 second
}
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
DisplayLoggingInfo();
handler.postDelayed(this, 10000); // 10 seconds
}
};
private void DisplayLoggingInfo() {
Log.d(TAG, "entered DisplayLoggingInfo");
intent.putExtra("time", new Date().toLocaleString());
intent.putExtra("counter", String.valueOf(++counter));
sendBroadcast(intent);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
handler.removeCallbacks(sendUpdatesToUI);
super.onDestroy();
}
}
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TableLayout android:id="#+id/tableGPS"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="7px"
android:stretchColumns="1">
<TableRow
android:layout_margin="1dip">
<TextView android:layout_gravity="right"
android:text="Time:"
android:layout_marginRight="7px"
android:layout_width="60px" />
<TextView android:id="#+id/txtDateTime"
android:gravity="left"
android:layout_span="2" />
</TableRow>
<TableRow
android:layout_margin="1px">
<TextView android:layout_gravity="right"
android:text="Counter:"
android:layout_marginRight="7px"
android:layout_width="60px" />
<TextView android:id="#+id/txtCounter"
android:gravity="left" />
</TableRow>
</TableLayout>
</LinearLayout>
Post delay only runs one time. You need to schedule a reoccurring task or just create a Runnable that will recall the task over and over.
final Handler mHandler = new Handler();
Runnable runner = new Runnable() {
#Override
public void run() {
MainActivity.count++;
mHandler.postDelayed(runner, 1000);
}
}
mHandler.postDelayed(runner, 1000);

Android : Custom adapter fails to reload list view on activity resume

I am trying to display received messages using custom adapter on list view , until now everything is working fine , but when I press back and come back and launch this activity again , only message send works but received messages cannot be displayed on the list view.
Steps I have done so far :
Use debugger to find out if message is not empty, messages are
received and not empty.
Use debugger inside receives() function , it turns out on first
launch of activity looper.loop() function gives control back to
main thread but next time on activity resume this loops doesn't
seem to end (may be this is cause of error) .
p.s: On first launch of this activity I can display received messages , but when I go back and resume activity , receives() fails , I am clueless here , any small hint in right direction is welcome, thanks for time.
public class hotListener extends ListActivity {
private XMPPConnection connection;
private IBinder binder;
private Handler mHandler = new Handler();
private ArrayList<String> messages = new ArrayList<String>();
ArrayList<ChatMessage> messagex= new ArrayList<ChatMessage>();;
ChattingAdapter adaptex;
Intent mIntent ;
private ListView listview;
EditText sender_message ;
String msg;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listener);
//messagex.add(new ChatMessage("Hello", false));
adaptex = new ChattingAdapter(getApplicationContext(),messagex);
setListAdapter(adaptex);
Button send_button = (Button) findViewById(R.id.chat_send_message);
sender_message = (EditText) findViewById(R.id.chat_input);
send_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
msg = sender_message.getText().toString();
sender_message.setText("");
if(!(msg.length()==0)){
messagex.add(new ChatMessage(msg, true));
//addNewMessage(new ChatMessage(msg, true));
adaptex.notifyDataSetChanged();
getListView().setSelection(messagex.size()-1);
}
}
});
if(!isMyServiceRunning()){
System.out.println("seems like service not running");
startService(new Intent(this,xService.class));
System.out.print(" now started ");
}
}
#Override
protected void onStart(){
super.onStart();
Boolean kuch = bindService(new Intent(this,xService.class), mConnection,Context.BIND_AUTO_CREATE);
//System.out.println(kuch);
//System.out.println("bind done");
}
private void receives(XMPPConnection connection2) {
//ChatManager chatmanager = connection.getChatManager();
connection2.getChatManager().addChatListener(new ChatManagerListener() {
#Override
public void chatCreated(Chat arg0, boolean arg1) {
arg0.addMessageListener(new MessageListener() {
#Override
public void processMessage(Chat chat, Message message) {
final String from = message.getFrom();
final String body = message.getBody();
mHandler.post(new Runnable() {
ChatMessage kudi = new ChatMessage(body, false);
#Override
public void run() {
//setListAdapter(1);
messagex.add(kudi);
adaptex.notifyDataSetChanged();
getListView().setSelection(messagex.size()-1);
Toast.makeText(hotListener.this,body,Toast.LENGTH_SHORT).show(); }
});
//System.out.println(String.format("Received message "+body +" from "+ from));
}
});
}
});
}
private boolean isMyServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for(RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)){
if(xService.class.getName().equals(service.service.getClassName())){
return true;
}
}
//System.out.print("false");
return false;
}
#Override
protected void onResume() {
bindService(new Intent(this, xService.class), mConnection, Context.BIND_AUTO_CREATE);
setListAdapter(adaptex);
adaptex.notifyDataSetChanged();
super.onResume();
}
#Override
protected void onPause() {
unbindService(mConnection);
super.onPause();
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
connection = null;
service = null;
}
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
//System.out.println("binding in hot listener");
service = ((xService.MyBinder)binder).getService();
connection = service.getConnection();
receives(connection);
Log.wtf("Service","connected");
}
};
void addNewMessage(ChatMessage m)
{
System.out.println("1");
messagex.add(m);
System.out.println("2");
adaptex.notifyDataSetChanged();
System.out.println("3");
getListView().setSelection(messagex.size()-1);
}
}
My adapter :
import java.util.ArrayList;
import android.content.Context;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
public class ChattingAdapter extends BaseAdapter{
private Context mContext;
private ArrayList<ChatMessage> mMessages;
public ChattingAdapter(Context context, ArrayList<ChatMessage> messages) {
super();
this.mContext = context;
this.mMessages = messages;
}
#Override
public int getCount() {
return mMessages.size();
}
#Override
public Object getItem(int position) {
return mMessages.get(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ChatMessage message = (ChatMessage) this.getItem(position);
ViewHolder holder;
if(convertView == null)
{
holder = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(R.layout.listitem, parent, false);
holder.message = (TextView) convertView.findViewById(R.id.text1);
convertView.setTag(holder);
}
else
holder = (ViewHolder) convertView.getTag();
holder.message.setText(message.getMessage());
LayoutParams lp = (LayoutParams) holder.message.getLayoutParams();
//Check whether message is mine to show green background and align to right
if(message.isMine())
{ holder.message.setBackgroundResource(R.drawable.msgbox_new_selected_go_up);
lp.gravity = Gravity.RIGHT;
}
//If not mine then it is from sender to show orange background and align to left
else
{
holder.message.setBackgroundResource(R.drawable.msgbox_other_go_up);
lp.gravity = Gravity.LEFT;
}
holder.message.setLayoutParams(lp);
//holder.message.setTextColor(R.color.textColor);
return convertView;
}
private static class ViewHolder
{
TextView message;
}
#Override
public long getItemId(int position) {
//Unimplemented, because we aren't using Sqlite.
return position;
}
}

Android comprehensive failproof music service across multiple activities

I know this question has been asked many times before and might seem to be a conglomeration of several questions, but I feel that it is relevant and important to many developers; I need to create a background music Service that can run across multiple activities for my Android game that ends when the application is terminated and pauses in all of the following circumstances:
A certain Activity that has its own music is started. (Resume when this Activity finishes. This happens to be an AndEngine activity.)
The home screen is pressed and the app is backgrounded, or the application is terminated. Resumes when the app returns to the foreground. Requires use of onUserLeaveHint(). Another helpful link.
The phone receives a call and interrupts the app. Resumes when the call has been dealt with. Requires use of TelephonyManager similar to this.
The screen is locked. (Resumes after screen has been unlocked.) Requires use of ACTION_USER_PRESENT, which seems to be very problematic.
Basically the music pauses whenever the app is not being shown or when the special activity from #1 is being shown to the user.
Above is all of what I need and the information I have pieced together. My current code basically resembles this.
I find it curious that AndEngine manages to have none of these issues with their music, so maybe looking in the source code would help someone looking for an answer. I'm using the last functional GLES1 version from Google Code.
I have taken a look at the following links as well on creating a good music Service:
Stopping Background Service Music
http://www.codeproject.com/Articles/258176/Adding-Background-Music-to-Android-App
Android background music service
Playing BG Music Across Activities in Android
http://www.rbgrn.net/content/307-light-racer-20-days-61-64-completion
I would like the solution Service to:
Minimize the use of BroadcastReceivers and Android Manifest additions/permissions if possible
Self contained and error checking
Other Notes
Currently all the activities that require the background music all extend a common special class.
The music needs to loop but only runs a single track.
Thanks to everyone ahead of time! Best of luck!
Edit - Here are code snippets, feel free to improve or ignore:
Media Player Wrapper
import android.content.SharedPreferences;
import android.media.MediaPlayer;
import android.preference.PreferenceManager;
import android.util.Log;
public class CarefulMediaPlayer {
final SharedPreferences sp;
final MediaPlayer mp;
private boolean isPlaying = false;
public CarefulMediaPlayer(final MediaPlayer mp, final MusicService ms) {
sp = PreferenceManager.getDefaultSharedPreferences(ms.getApplicationContext());
this.mp = mp;
}
public void start() {
if (sp.getBoolean("com.embed.candy.music", true) && !isPlaying) {
mp.start();
isPlaying = true;
}
}
public void pause() {
if (isPlaying) {
mp.pause();
isPlaying = false;
}
}
public void stop() {
isPlaying = false;
try {
mp.stop();
mp.release();
} catch (final Exception e) {}
}
}
Music Service
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
public class MusicService extends Service {
static CarefulMediaPlayer mPlayer = null;
#Override
public IBinder onBind(final Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
final MediaPlayer mp = MediaPlayer.create(this, R.raw.title_music);
mp.setLooping(true);
mPlayer = new CarefulMediaPlayer(mp,this);
}
#Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
mPlayer.start();
return 1;
}
#Override
public void onStart(final Intent intent, final int startId) {
}
public IBinder onUnBind(final Intent arg0) {
return null;
}
public static void onStop() {
mPlayer.stop();
}
public static void onPause() {
if (mPlayer!=null) {
mPlayer.pause();
}
}
public static void onResume() {
if (mPlayer!=null) {
mPlayer.start();
}
}
#Override
public void onDestroy() {
mPlayer.stop();
mPlayer = null;
}
#Override
public void onLowMemory() {
}
}
Improved Base Activity Class
import android.app.Activity;
import android.content.Intent;
import android.os.PowerManager;
import android.telephony.TelephonyManager;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
public abstract class BetterActivity extends Activity {
private boolean isHome = true;
#Override
protected void onResume() {
System.gc();
super.onResume();
MusicService.onResume();
isHome = true;
}
#Override
protected void onPause() {
if (((TelephonyManager)getSystemService(TELEPHONY_SERVICE)).getCallState()==TelephonyManager.CALL_STATE_RINGING
|| !((PowerManager)getSystemService(POWER_SERVICE)).isScreenOn()) {
MusicService.onPause();
}
super.onPause();
System.gc();
}
#Override
public boolean onKeyDown (final int keyCode, final KeyEvent ke) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
isHome = false;
default:
return super.onKeyDown(keyCode, ke);
}
}
#Override
public void startActivity(final Intent i) {
isHome = false;
super.startActivity(i);
}
#Override
protected void onUserLeaveHint() {
if (isHome) {
MusicService.onPause();
}
super.onUserLeaveHint();
}
}
First here is some code. Below I'll give you an explanation.
public class MusicService extends Service {
// service binder
private final IBinder mBinder = new LocalBinder();
// music player controling game music
private static CarefulMediaPlayer mPlayer = null;
#Override
public void onCreate() {
// load music file and create player
MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.title_music);
mediaPlayer.setLooping(true);
mPlayer = new CarefulMediaPlayer(mediaPlayer, this);
}
#Override
public void onDestroy() {
super.onDestroy();
}
// =========================
// Player methods
// =========================
public void musicStart() {
mPlayer.start();
}
public void musicStop() {
mPlayer.stop();
}
public void musicPause() {
mPlayer.pause();
}
/**
* Class for clients to access. Because we know this service always runs in
* the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
MusicService getService() {
return MusicService.this;
}
}
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
}
Activity:
public class StartupActivity extends Activity {
// bounded service
private static MusicService mBoundService;
// whetere service is bounded or not
private boolean mIsBound;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_startup);
doBindService();
// HOW TO WORK WITH THE SERVICE:
// call the following methods whenever
// you want to interact with you
// music player
// ===================================
// call this e.g. in onPause() of your Activities
StartupActivity.getService().musicPause();
// call this e.g. in onStop() of your Activities
StartupActivity.getService().musicStop();
// call this e.g. in onResume() of your Activities
StartupActivity.getService().musicStart();
}
#Override
public void onDestroy() {
super.onDestroy();
doUnbindService();
}
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
setService(((MusicService.LocalBinder) service).getService());
}
#Override
public void onServiceDisconnected(ComponentName className) {
setService(null);
}
};
private void doBindService() {
Intent service = new Intent(getBaseContext(), MusicService.class);
// start service and bound it
startService(service);
bindService(new Intent(this, MusicService.class), mServiceConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
private void doUnbindService() {
if (mIsBound) {
// Detach existing connection.
unbindService(mServiceConnection);
mIsBound = false;
}
}
public static MusicService getService() {
return mBoundService;
}
private static void setService(MusicService mBoundService) {
StartupActivity.mBoundService = mBoundService;
}
}
First of all you got a Service which runs in background. This service creates the mediaPlayer object as you did. With the localBinder you can bind the Service in your Activity(ies) and access it like a normal Java-Object.
The Activity I've posted bindes the Service. In it's onCreate() method you can find a way how to interact with your mediaPlayer.
You can bind any Activity to your Service.
Another Solution:
public class CarefulMediaPlayer {
final SharedPreferences sp;
final MediaPlayer mp;
private boolean isPlaying = false;
private static CarefulMediaPlayer instance;
public CarefulMediaPlayer(final MediaPlayer mp, final MusicService ms) {
sp = PreferenceManager.getDefaultSharedPreferences(ms.getApplicationContext());
this.mp = mp;
instance = this;
}
public static CarefulMediaPlayer getInstance() {
return instance;
}
public void start() {
if (sp.getBoolean("com.embed.candy.music", true) && !isPlaying) {
mp.start();
isPlaying = true;
}
}
public void pause() {
if (isPlaying) {
mp.pause();
isPlaying = false;
}
}
public void stop() {
isPlaying = false;
try {
mp.stop();
mp.release();
} catch (final Exception e) {}
}
}
Then you can pause, play and stop the music by calling CarefulMediaPlayer.getInstance().play();
I did it this way and I'm pleased with the result:
1st create the service:
public class LocalService extends Service
{
// This is the object that receives interactions from clients. See RemoteService for a more complete example.
private final IBinder mBinder = new LocalBinder();
private MediaPlayer player;
/**
* Class for clients to access. Because we know this service always runs in
* the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder
{
LocalService getService()
{
return LocalService.this;
}
}
#Override
public void onCreate()
{
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
// We want this service to continue running until it is explicitly stopped, so return sticky.
return START_STICKY;
}
#Override
public void onDestroy()
{
destroy();
}
#Override
public IBinder onBind(Intent intent)
{
return mBinder;
}
public void play(int res)
{
try
{
player = MediaPlayer.create(this, res);
player.setLooping(true);
player.setVolume(0.1f, 0.1f);
player.start();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void pause()
{
if(null != player && player.isPlaying())
{
player.pause();
player.seekTo(0);
}
}
public void resume()
{
try
{
if(null != player && !player.isPlaying())
{
player.start();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void destroy()
{
if(null != player)
{
if(player.isPlaying())
{
player.stop();
}
player.release();
player = null;
}
}
}
2nd, create a base activity and extend all your activities in witch you wish to play the background music from it:
public class ActivityBase extends Activity
{
private Context context = ActivityBase.this;
private final int [] background_sound = { R.raw.azilum_2, R.raw.bg_sound_5 };
private LocalService mBoundService;
private boolean mIsBound = false;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
doBindService();
}
#Override
protected void onStart()
{
super.onStart();
try
{
if(null != mBoundService)
{
Random rand = new Random();
int what = background_sound[rand.nextInt(background_sound.length)];
mBoundService.play(what);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
#Override
protected void onStop()
{
super.onStop();
basePause();
}
protected void baseResume()
{
try
{
if(null != mBoundService)
{
mBoundService.resume();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
protected void basePause()
{
try
{
if(null != mBoundService)
{
mBoundService.pause();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
private ServiceConnection mConnection = new ServiceConnection()
{
public void onServiceConnected(ComponentName className, IBinder service)
{
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. Because we have bound to a explicit
// service that we know is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
mBoundService = ((LocalService.LocalBinder) service).getService();
if(null != mBoundService)
{
Random rand = new Random();
int what = background_sound[rand.nextInt(background_sound.length)];
mBoundService.play(what);
}
}
public void onServiceDisconnected(ComponentName className)
{
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
// Because it is running in our same process, we should never
// see this happen.
mBoundService = null;
if(null != mBoundService)
{
mBoundService.destroy();
}
}
};
private void doBindService()
{
// Establish a connection with the service. We use an explicit
// class name because we want a specific service implementation that
// we know will be running in our own process (and thus won't be
// supporting component replacement by other applications).
Intent i = new Intent(getApplicationContext(), LocalService.class);
bindService(i, mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
private void doUnbindService()
{
if (mIsBound)
{
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
}
#Override
protected void onDestroy()
{
super.onDestroy();
doUnbindService();
}
}
And that's it, now you have background sound in all the activities that are extended from ActivityBase.
You can even control the pause / resume functionality by calling basePause() / baseResume().
Don't forget to declare the service in manifest:
<service android:name="com.gga.screaming.speech.LocalService" />
In the startup activity we are binding and Starting Service seperately. This is wrong since service will keep running after activity exits as we haven't called stopService() anywhere. So The part ' startService(service) ' should be removed as bind service is already "Auto-Creating" the service too.
Please correct me if anyone got opposite results
startService(service);// remove this part
bindService(new Intent(this, MusicService.class), mServiceConnection, Context.BIND_AUTO_CREATE);

Categories

Resources