Heres my problem:
I am implementing a music player (PlayerActivity.java / xml) which is bound to a service (PlayerService.java) that basically is just an instance of a musicplayer so that it can run in the background. When lefting the app or changing the activity and the restarting the activity i want to bind to the still running service without stopping or restarting it. I have tried using only bindService() but that made me face the problem: somehow without calling startService() before bindService the Service doesn't get initialized or it takes a few milliseconds so that the functions only get null when accessing service functions.
Here is my service class:
public class playerService extends Service {
public boolean running = false;
public MediaPlayer mediaPlayer;
public boolean isPrepared = false;
private String url;
public class serviceBinder extends Binder {
public playerService getService() {
return playerService.this;
}
}
public boolean isRunning(){
return running;
}
private IBinder mBinder = new serviceBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.w("Service", "started");
mediaPlayer = new MediaPlayer();
running = true;
Log.e("!!!", running + "");
return START_STICKY;
}
public void pause() {
mediaPlayer.pause();
}
public void resume() {
mediaPlayer.start();
}
public void setupPlayer() {
try {
if (mediaPlayer != null) {
mediaPlayer.reset();
}
} catch (Exception e) {
Log.e("MediaPlayer", e.getMessage());
}
try {
mediaPlayer.setDataSource(url);
mediaPlayer.prepareAsync();
} catch (Exception e) {
Log.e("MediaPlayerToo", e.getMessage());
}
}
public void reset(){
mediaPlayer.reset();
}
public void updateUrl(String url){
this.url = url;
}
public void start(){
mediaPlayer.start();
}
public int getCurrentPosition(){
return mediaPlayer.getCurrentPosition();
}
public int getDuration(){
return mediaPlayer.getDuration();
}
#Override
public void onDestroy() {
super.onDestroy();
mediaPlayer.stop();
mediaPlayer.reset();
}
}
I experimented with waiting until the Service has started with a boolean. But when i add any kind of code
after
mService = binder.getService();
startService(intent);
it seems to not get created at all.
Here is also my onServiceConnected class
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
playerService.serviceBinder binder = (playerService.serviceBinder) service;
Intent intent = new Intent(getApplicationContext(), playerService.class);
mService = binder.getService();
startService(intent);
//... <- adding code here will result in the Service not starting?!!
}
I know that my problem is quite confusing, but this was the best i could come up explaining it. I would be really glad if you had any idea because this problem stops me from deployment. Thank you very much!!
Related
I want to start 2 services at the start of an activity but only the first one starts and the second fails at bindService(). There is no error just when I want to do something with the service it gives me a nullpointer. I also tried to wait to do something but the service never starts.
The 2 services are pretty similar and I just want to know what is wrong with the implementation. I tried to debug and bindservice() function at startSoundmanagerService return 0, what is maybe the root of the problem but I don't know why.
public class SimulationActivity extends AppCompatActivity {
BluetoothService BService;
boolean mBound = false;
SoundManager SService;
boolean sBound = false;
#Override
protected void onStart() {
super.onStart();
if (bluetoothAdapter.isEnabled()) {
setStatusText("Bluetooth on");
}
else {
setStatusText("Bluetooth off");
}
if(!mBound) {
startServer();
}
conStatImageView.setImageResource(R.drawable.connection_off);
if(!sBound){
startSoundManagerService();
}
#Override
protected void onStop() {
super.onStop();
if(mBound) {
unbindService(bConnection);
mBound = false;
}
if(sBound){
unbindService(sConnection);
sBound = false;
}
}
private ServiceConnection bConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
BluetoothService.LocalBinder binder =
(BluetoothService.LocalBinder) service;
BService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
private ServiceConnection sConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
SoundManager.LocalBinder binder = (SoundManager.LocalBinder) service;
SService = binder.getService();
sBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
sBound = false;
}
public void startServer(){
if (bluetoothAdapter == null) {
Log.d("tag","Device doesn't support Bluetooth") ;
}
if (!bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
if(bluetoothAdapter.isEnabled()){
startBluetoothservice();
}
}
private void startBluetoothservice(){
Intent intent = new Intent (this,BluetoothService.class);
bindService(intent, bConnection, Context.BIND_AUTO_CREATE);
Log.i(TAG,"Trying to start bluetoothservice");
}
private void startSoundManagerService(){
Intent intent = new Intent (this,SoundManager.class);
bindService(intent, sConnection, Context.BIND_AUTO_CREATE);
Log.i(TAG,"Trying to start soundservice");
}
So how can I implement 2 different services in 1 activity?
Edit Solution: I forgot to register the service in the manifestfile. ;)
I found the solution: I forgot to register the 2nd Service in the manifest. Thats all ;)
I have a service listening for UDP packets that is bound to my MainActivity (which is the only activity in the app). The service runs on its own thread and I can see the UDP messages as well as the parsed messages in logcat. I created a setParsedMessage() and a public getParsedMessage() in order to get the parsed string and send it to my main activity in order to change a TextView and an ImageView depending on what the parsed message is, however it does not appear to be retrieving the String for some reason. I read about this method on the Developer.Android website, however I've also seen something about using Handler to do this instead. Here is my code:
MainActivity:
public class MainActivity extends Activity {
AlertAssignments mAlertAssignments;
Button startListeningButton;
boolean started;
int counter;
boolean mBound = false;
Context context;
ListenerService mListenerService;
TextView mTextView;
TextView mBlinkView;
ImageView mImageView;
private StartListening _StartListeningTask;
String messageFromService = "";
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//start listener service
Intent listenerServiceIntent = new Intent(MainActivity.this, ListenerService.class);
this.bindService(listenerServiceIntent, mConnection, Context.BIND_AUTO_CREATE);
mImageView = (ImageView) findViewById(R.id.image_view);
mTextView = (TextView) findViewById(R.id.alert_text);
mBlinkView = (TextView) findViewById(R.id.blinking_text);
Animation mAnimation = new AlphaAnimation(0.0f, 1.0f);
mAnimation.setDuration(50);
mAnimation.setStartOffset(20);
mAnimation.setRepeatCount(Animation.INFINITE);
mAnimation.setRepeatMode(Animation.REVERSE);
mBlinkView.startAnimation(mAnimation); //animation value
mAlertAssignments = new AlertAssignments();
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
ListenerService.LocalBinder binder = (ListenerService.LocalBinder) service;
mListenerService = binder.getService();
mBound = true;
if(mBound) {
Log.e("UDP", "Service has been bound successfully");
}
else {
Log.e("UDP", "Service has not been bound");
}
readFromService();
}
#Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
}
};
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onStop() {
super.onStop();
//unbind from service
if(mBound) {
this.unbindService(mConnection);
mBound = false;
}
}
private void readFromService() {
try {
Integer parsedMessage = Integer.valueOf(mListenerService.getParsedMessage());
mImageView.setImageResource(mAlertAssignments.alarmImages[parsedMessage]);
if(parsedMessage >= 10 && parsedMessage <= 19 && parsedMessage != 0) {
mTextView.setText(mAlertAssignments.alertTextMessages[parsedMessage]);
} else {
mBlinkView.setText(mAlertAssignments.alertTextMessages[parsedMessage]);
}
} catch(NumberFormatException e) {
e.printStackTrace();
}
}
}
I had read that using the public getter like this:
Integer parsedMessage = Integer.valueOf(mListenerService.getParsedMessage());
would allow me to access the string value of mListenerService.getParsedMessage, however I'm guessing that may only work for started services, not bound services.
AlertAssignments is a simple enumeration that uses ordinal arrays to bind images and Strings to values, so mImageView.setImageResource(mAlertAssignments.alarmImages[parsedMessage]) would set the ImageView to an image. Finally, here is the Service:
public class ListenerService extends Service{
public String the_alarm_S;
public String parsedMessage = "";
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
ListenerService getService() {
return ListenerService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
DatagramSocket socket;
Thread UDPBroadcastThread;
void startListenForUDPBroadcast() {
UDPBroadcastThread = new Thread(new Runnable() {
public void run() {
try {
while (shouldRestartSocketListen) {
try {
socket = new DatagramSocket(12001);
socket.setReuseAddress(true);
String message = "";
byte[] recvBuf = new byte[1024];
DatagramPacket packet = new DatagramPacket(recvBuf, 1024);
Log.e("UDP", "Waiting for UDP broadcast");
try {
socket.receive(packet);
Log.e("UDP", "Received Packet");
} catch (IOException e) {
e.printStackTrace();
}
message = new String(packet.getData());
Log.e("UDP", "Got UDB broadcast message: " + message);
setParsedMessage(message);
if(socket != null) {
socket.close();
}
} catch (SocketException e) {
e.printStackTrace();
}
}
//if (!shouldListenForUDPBroadcast) throw new ThreadDeath();
} catch (Exception e) {
Log.i("UDP", "no longer listening for UDP broadcasts cause of error " + e.getMessage());
}
}
});
UDPBroadcastThread.start();
}
private Boolean shouldRestartSocketListen = true;
private void setParsedMessage(String messageContents) {
the_alarm_S = messageContents;
String parseMessage[] = the_alarm_S.split("!!!");
Log.e("UDP", "Parsed message with value " + parseMessage[1]);
parsedMessage = parseMessage[1];
}
public String getParsedMessage() {
return parsedMessage;
}
private void stopListen() {
shouldRestartSocketListen = false;
if(socket != null) {
socket.close();
}
}
#Override
public void onCreate() {
startListenForUDPBroadcast();
}
#Override
public void onDestroy() {
stopListen();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
shouldRestartSocketListen = true;
startListenForUDPBroadcast();
Log.i("UDP", "Service started");
return START_STICKY;
}
}
Can someone give me the simplest method of getting the String from the service to the main activity, or if I already have it, where I am going wrong in using it? I would like to avoid having to rewrite my Service as an IntentService unless it's absolutely necessary to do so since this is a relatively simple object to pass to MainActivity
Thanks
You could try subscribing to the service. What I mean is pass some interface that the service calls to notify the activity about changes, here's an example I just tested:
A Subscriber interface
public interface ServiceSubscriber {
void messageCallback(String message);
}
Subscribe to the service using the Subscriber
public class TestService extends Service {
ArrayList<ServiceSubscriber> subscribers = new ArrayList<>();
private TestBinder testBinder = new TestBinder();
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(){
#Override
public void run() {
while(true){
//this is where you are receiving UDP packets
doStuff();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
return super.onStartCommand(intent, flags, startId);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return testBinder;
}
private void doStuff() {
System.out.println("Service is doing stuff!");
//loop through your subscribers and notify them of your changes
//a loop here isn't very costly, if there aren't many subscribers
for (ServiceSubscriber subscriber : subscribers) {
subscriber.messageCallback("I'm doing stuff");
}
}
public class TestBinder extends Binder {
public TestService getService() {
return TestService.this;
}
}
public void subscribeToMessages(ServiceSubscriber subscriber) {
subscribers.add(subscriber);
}
public void unSubscribeToMessages(ServiceSubscriber subscriber) {
subscribers.remove(subscriber);
}
}
Now for the usual Binding Activity, where you define what you need to do with the Message Callback:
public class MainActivity extends AppCompatActivity {
private TestService testService;
private Subscriber subscriber;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart() {
super.onStart();
bindService(new Intent(this, TestService.class),serviceConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
testService = ((TestService.TestBinder)service).getService();
subscriber = new ServiceSubscriber() {
#Override
public void messageCallback(String message) {
//I'm just printing out the message received
//Be careful if you need to do UI stuff to use a
//Handler
System.out.println(message);
}
}
testService.subscribeToMessages(subscriber );
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
Of course don't forget to unsubscribe on destroy.
Updating UI often doesn't break your app if you do it by using a handler
//activity fields
Handler handler
//in activity constructor
handler = new Handler();
//update UI by calling
handler.post(new Runnable(){
#Override
public void run(){
//update the UI here
}
EDIT: I forgot to keep a reference of the subscriber, to unsubscribe later. Changed from anonymous instance to a field.
Make below method to your sevice class:
private void sendMessage() {
Intent intent = new Intent("message");
intent.putExtra("message", your_message);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
And put the below code in your activity class:
#Override
public void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(this)
.registerReceiver(mMessageReceiver,
new IntentFilter("message"));
}
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String yourMessage = intent.getIntExtra("message",-1);
}
};
#Override
protected void onPause() {
LocalBroadcastManager.getInstance(this)
.unregisterReceiver(mMessageReceiver);
super.onPause();
}
Note: -1 is for default value
I have some programm, where I want to save the instance of service and use it in another activities. But service doesn't create.
Just see the code, please.
MainActivity.java:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainService.get(this);
}
}
MainService.java:
public class MainService extends Service {
public static Object sWait = new Object();
public static MainService instance;
#Override
public IBinder onBind(Intent intent) {
return null;
}
public static MainService get(Context mContext) {
if (instance == null) {
Intent intent = new Intent(mContext, MainService.class);
mContext.startService(intent);
}
while (true) {
if (instance != null) {
Log.v("myLogs", "all is good!");
break;
}
synchronized (sWait) {
try {
sWait.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return instance;
}
#Override
public void onCreate() {
Log.v("myLogs", "created!");
instance = this;
synchronized (sWait) {
sWait.notify();
}
}
}
When I don't use while in MainService.get(), service creates. I added this service to manifest file. I don't know where is there error. I need your help.
That's just not the way you should use Service in Android.
What you probably need is to use bindService() call from your Activity.
See more about bound service here http://developer.android.com/guide/components/bound-services.html
If you need the service to be the same instance each time you bind to it, call startService once when your application start.
Example code:
public class LocalBinder<T> extends Binder {
private WeakReference<T> mService;
public LocalBinder(T service) {
mService = new WeakReference<T>(service);
}
public T getService() {
return mService.get();
}
}
public class MyService extends Service {
private final LocalBinder<MyService> binder;
public MyService() {
binder = new LocalBinder<MyService>(this);
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
}
public class MyActivity extends Activity implements ServiceConnection {
#Override
protected void onStart() {
super.onStart();
bindService(new Intent(this, MyService.class), this, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
unbindService(this);
}
#SuppressWarnings("unchecked")
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyService serv = ((LocalBinder<MyService>) service).getService();
// serv is your service instance now
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
}
To start your service use (call this from your activity!):
Intent serviceIntent = new Intent(this, MainService.class);
startService(serviceIntent);
see docs: https://developer.android.com/training/run-background-service/send-request.html
That is definitely not the way you are supposed to use services in android.
I would suggest you revisit the offical android docs.
To get a quick introduction visit this tutorial here.
I have the following code being executed, I'm running this through a debugger and audioPlayerConnection.service is always null. Why may this be?
The various log calls don't always seem to be executed either (I guess this may have to do with the service being already starte).
Intent intent = new Intent(this, AudioPlayer.class);
AudioPlayerConnection audioPlayerConnection = new AudioPlayerConnection();
startService(intent);
bindService(intent, audioPlayerConnection, Context.BIND_AUTO_CREATE);
AudioPlayerConnection
public class AudioPlayerConnection implements ServiceConnection {
public IBinder service;
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
this.service = service;
Log.d("hmm", "audio service connected!!!");
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
}
AudioPlayer
public class AudioPlayer extends Service {
public ArrayList<MediaPlayer> audioResources = new ArrayList<MediaPlayer>();
public AudioPlayer() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
Log.d("hmm", "audio service binded!!!");
return new AudioPlayerBinder();
}
public class AudioPlayerBinder extends Binder {
public void stopAll()
{
int i = 0;
for (MediaPlayer mp : audioResources)
{
mp.stop();
mp.release();
audioResources.remove(i);
i++;
}
}
public void add(Integer resourceId, boolean loop)
{
MediaPlayer mp = MediaPlayer.create(null, resourceId);
if (loop)
{
mp.setLooping(true);
audioResources.add(mp);
}
mp.start();
}
}
}
You're declaring audioPlayerService in the local scope where you are calling bindService(). The call to bindService is asynchronous, and onServiceConnected() is not being called before you are (presumably) trying to use audioPlayerConnection as if the Service was already bound.
I am using a Service to play background Music. The problem is that the music continues playing when i have finished the activity.
Here is code From Main Activity which starts the service
Intent svc=new Intent(HomeActivity.this, BackgroundSoundService.class);
startService(svc);
BackgroundSoundService.java
public class BackgroundSoundService extends Service {
private static final String TAG = null;
public static MediaPlayer player;
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
Log.d("atMedia", "Backround Music playing");
player = MediaPlayer.create(this, R.raw.background);
player.setLooping(true); // Set looping
player.setVolume(100,100);
}
public int onStartCommand(Intent intent, int flags, int startId) {
player.start();
return 1;
}
public void onStart(Intent intent, int startId) {
// TO DO
}
public IBinder onUnBind(Intent arg0) {
// TO DO Auto-generated method
return null;
}
public void onStop() {
}
public void onPause() {
}
#Override
public void onDestroy() {
super.onDestroy();
player.stop();
player.release();
}
#Override
public void onLowMemory() {
}
}
Try to stop service from your MainActivity:
Intent svc=new Intent(HomeActivity.this, BackgroundSoundService.class);
stopService(svc);
You have to call selfStop() method inside your service.
or use stopService() API