I'm attempting to create a program in Android which communicates rapidly with a remote service (~40,000/sec), however all Android IPC seems to fall short of being able to accomplish this task. My first attempt involved a standard Messenger system which was unable to do more then ~2,000/second and equally bad was that it seemed punctuated with intermittent lag.
MainActivity (Test with Messengers)
public class MainActivity extends Activity implements ServiceConnection{
Messenger mServiceMessenger;
Messenger mClientMessenger = new Messenger(new ClientHandler());
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,TestService.class);
bindService(intent,this, Context.BIND_AUTO_CREATE);
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
mServiceMessenger = new Messenger(service);
Message m = Message.obtain();
m.replyTo = mClientMessenger;
try {
mServiceMessenger.send(m);
} catch (RemoteException e) {
e.printStackTrace();
}
}
#Override
public void onServiceDisconnected(ComponentName name) {}
public class ClientHandler extends Handler {
#Override
public void handleMessage(Message msg) {
Log.d("Spam","Message Received");
}
}
}
RemoteService (Test with Messengers)
public class TestService extends Service {
private Messenger mServiceMessenger = new Messenger(new ServiceHandler());
private Messenger mClientMessenger;
private Random r = new Random();
public TestService() {
super();
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public IBinder onBind(Intent intent) {
return mServiceMessenger.getBinder();
}
public void initSpam(){
for(int i=0;i<10;i++) {
TimerTask task = new TimerTask() {
#Override
public void run() {
Bundle b = new Bundle();
b.putInt("INT",r.nextInt());
b.putLong("LONG",r.nextLong());
b.putBoolean("BOOL",r.nextBoolean());
b.putFloat("FLOAT",r.nextFloat());
b.putDouble("DOUBLE",r.nextDouble());
b.putString("STRING",String.valueOf(r.nextInt()));
Message msg = Message.obtain();
msg.setData(b);
try {
mClientMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
Timer timer = new Timer();
timer.scheduleAtFixedRate(task,1,1);
}
}
public class ServiceHandler extends Handler {
#Override
public void handleMessage(Message msg) {
mClientMessenger = msg.replyTo;
initBarrage();
}
}
}
The second attempt was done with AIDL. Although this also implements Binders for IPC, I assumed had significantly less overhead. However, AIDL proved to not be significantly more efficient then Messengers and it also did not solved the issue with stuttering.
MainActivity (Test with AIDL)
public class MainActivity extends Activity implements ServiceConnection{
IRemoteService mService;
TextView countTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,TestService.class);
bindService(intent,this, Context.BIND_AUTO_CREATE);
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IRemoteService.Stub.asInterface(service);
try {
mService.registerCallback(mClientBinder);
} catch (RemoteException e) {
e.printStackTrace();
}
}
#Override
public void onServiceDisconnected(ComponentName name) {}
public final IServiceAidlCallback.Stub mClientBinder = new IServiceAidlCallback.Stub(){
public void basicTypes(int anInt, long aLong, boolean aBoolean,
float aFloat, double aDouble, String aString){
Log.d("Spam","Callback Received");
}
};
}
RemoteService (Test with AIDL)
public class TestService extends Service {
private Random r = new Random();
private IServiceAidlCallback mClientCallback;
public TestService() {
super();
}
#Override
public void onRebind(Intent intent) {
super.onRebind(intent);
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public final IRemoteService.Stub mBinder = new IRemoteService.Stub(){
public void registerCallback(IBinder callback){
mClientCallback = IServiceAidlCallback.Stub.asInterface(callback);
initSpam();
}
};
public void initSpam(){
for(int i=0;i<10;i++) {
TimerTask task = new TimerTask() {
#Override
public void run() {
try {
mClientCallback.basicTypes(
r.nextInt(),
r.nextLong(),
r.nextBoolean(),
r.nextFloat(),
r.nextDouble(),
String.valueOf(r.nextInt()));
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
Timer timer = new Timer();
timer.scheduleAtFixedRate(task,1,1);
}
}
}
Am I doing something wrong in either of these cases which would prevent me from getting above ~5,000/second? or is there another system for Android IPC that I was not aware of?
do something like that:
MainActivity
// use it for writing: stream.write(byte[])
// (make sure to write as biggest data chunks as possible)
// or wrap it around some other streams like DataOutputStream
private OutputStream stream;
// ServiceConnection implementation
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
stream = new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]);
Parcel data = Parcel.obtain();
FileDescriptor readFileDescriptor = pipe[0].getFileDescriptor();
data.writeFileDescriptor(readFileDescriptor);
service.transact(IBinder.FIRST_CALL_TRANSACTION, data, null, 0);
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "onServiceConnected " + stream);
}
RemoteService
#Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind ");
return binder;
}
IBinder binder = new Binder() {
#Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
ParcelFileDescriptor pfd = data.readFileDescriptor();
final InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
// do something with a 'stream', start a new Thread for example and read data in a loop
...
...
return true;
}
};
Related
I'm creating an application where I want a Handler to send an http request every 15 second. The problem is, that while my device (huawei watch 2) is on chare, the Handler works as supposed to, but when I take the watch off the charger, the 15 second is changes between 15 and 40 seconds. Is there a problem with my implementation? I'm not passing any Runnable to the Handler, since there is only a little work to do. I have a SensorHelper class, which just gets the heart rate value. In the request I'm sending a custom message object as JSON.
MainActivity:
public class MainActivity extends WearableActivity {
private static ConnectionService mService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.BODY_SENSORS)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.BODY_SENSORS},
1);
}
Intent intent = new Intent(this, ConnectionService.class);
this.startService(intent);
this.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
setContentView(R.layout.activity_main);
// Enables Always-on
setAmbientEnabled();
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
ConnectionService.LocalBinder binder = (ConnectionService.LocalBinder) service;
mService = binder.getServiceInstance();
try {
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
}
};
public static void sendMessage(String message) {
mService.sendMessage(message);
}
}
ConnectionService in order to avoid my application to go into DOZE mode:
public class ConnectionService extends Service {
private final IBinder mBinder = new LocalBinder();
private static SensorHelper sensorHelper;
private static OkHttpClient client = new OkHttpClient();
public static final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
public class LocalBinder extends Binder {
public ConnectionService getServiceInstance() {
return ConnectionService.this;
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onCreate() {
if (sensorHelper == null) {
sensorHelper = new SensorHelper(this);
}
super.onCreate();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("ASD")
.setContentText("ASD")
.setContentIntent(pendingIntent).build();
startForeground(1337, notification);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_REDELIVER_INTENT;
}
public void sendMessage(String message) {
Message msg = new Message("HR", message);
RequestBody requestBody = RequestBody.create(JSON, msg.toJson());
Request request = new Request.Builder()
.url("http://104.248.32.100/")
.post(requestBody)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
}
});
}
}
SensorHelper in order to get the heart rate value, and post it:
public class SensorHelper implements SensorEventListener {
private String sensorValue = "normal";
private static Handler handler = new Handler();
private int delay = 15000;
public SensorHelper(Context context) {
SensorManager sensorManager = (SensorManager) context.getSystemService(SENSOR_SERVICE);
Sensor heartRateSensor = sensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE);
sensorManager.registerListener(this, heartRateSensor, SensorManager.SENSOR_DELAY_NORMAL);
handler.postDelayed(new Runnable(){
public void run() {
sendMessage();
handler.postDelayed(this, delay);
}
}, delay);
}
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_HEART_RATE) {
sensorValue = String.valueOf(event.values[0]);
}
}
#Override
public void onAccuracyChanged (Sensor sensor,int i){
}
private String getSensorValue() {
return sensorValue;
}
private void sendMessage() {
MainActivity.sendMessage(getSensorValue());
}
}
Is there any mistakes I'm making, while the Handler is not working correctly? Is passing a Runnable necessary to create a new Thread? As far as is read, the Handler is creating a new Thread
I had the same exact problem, with a lot of applications that run on the background while the device is not charging. The problem is Android's battery optimization.
The solution is pretty simple, you have to disable your app's battery optimization by going to Settings > Battery > Battery optimization (The path varies by manufacturer).
Some manufacturers also add extra measures to optimize battery by making timed tasks proc less often, so check out for extra settings that might affect this.
Hope this helps!
I am creating bound service for socket connection.Which means it is creating a long polling connection and listens my server.If user closes the app in task manager my service is killing i have no problem with this.But when user presses the back button I am calling activity.finish() method for close app.But with this method my service doesn't kill,it is still connected to socket server.
Is this normal ? And Could be this drain the battery ?
My service:
public class SocketService extends Service {
//you need constants to tell servise and activity what you are sending a message for
public static final int REGISTER_CHAT_ACTIVITY = 1;
public static final int MESSAGE_RECEIVED = 2;
final Messenger mMessenger = new Messenger(new IncomingHandler());
Messenger chat;
private Socket socket;
#Override
public void onCreate() {
try {
socket = IO.socket("ip");
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
}
}).on("connected", new Emitter.Listener() {
#Override
public void call(Object... args) {
}
}).on("message", new Emitter.Listener() {
#Override
public void call(Object... args) {
try {
chat.send(android.os.Message.obtain(null, MESSAGE_RECEIVED, args[0]));
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
//and add all the other on listeners here
socket.connect();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (socket != null) {
socket.disconnect();
socket.connect();
} else {
try {
socket = IO.socket("ip");
socket.connect();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
class IncomingHandler extends Handler {
#Override
public void handleMessage(android.os.Message msg) {
switch(msg.what){
case REGISTER_CHAT_ACTIVITY:
chat = msg.replyTo;
break;
}
}
}
public class LocalBinder extends Binder {
SocketService getService() {
return SocketService.this;
}
}
}
I had something similar a while ago i solved the issue by using shared preferences.(Note: I dont think it's the best answer but it solved my problem)
I saved in preferences a boolean to register when i dont need the service anymore but lost reference of it.
public class YourService extends Service {
private YourService serv;
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
serv = this;
Then Somehwere on your code that the service does frequently.
if(!sharedPref.getBoolean("TurnOffService", false)){
serv.stopSelf();
}
Hope it helps.
I am attempting to connect to my XAMPP server and interact with the MySQL database with the classes below. However, the error notes that I receive a NullPointerException at the line:
result = imService.createNewGroup(newGroupName);
In the CreateGroup class. It should be noted that the CreateGroup class is also called right after a user inputs text into a Dialog and the service is started from there. I am fairly new to services and network connections, but is there something I'm missing that should allow to at least verify that the service is connected before trying to send the .createGroup command?
CreateGroup Class:
public class CreateGroup extends Activity {
private static final String SERVER_RES_RES_SIGN_UP_SUCCESFULL = "1";
private static final String SERVER_RES_SIGN_UP_USERNAME_CRASHED = "2";
private Manager imService;
private Handler handler = new Handler();
String newGroupName;
public ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
imService = ((MessagingService.IMBinder) service).getService();
}
public void onServiceDisconnected(ComponentName className) {
imService = null;
Toast.makeText(CreateGroup.this, R.string.local_service_stopped,
Toast.LENGTH_SHORT).show();
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindService(new Intent(CreateGroup.this, MessagingService.class),
mConnection, Context.BIND_AUTO_CREATE);
// Getting intent and info from the dialog
Intent i = getIntent();
Bundle extras = i.getExtras();
newGroupName = extras.getString("groupName");
Thread thread = new Thread() {
String result = new String();
#Override
public void run() {
// Send group name to the messaging
// service
try {
result = imService.createNewGroup(newGroupName);
} catch (NullPointerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d("problem", "The value of result is " + result.toString());
handler.post(new Runnable() {
#Override
public void run() {
if (result == null) {
Toast.makeText(getApplicationContext(),
"It's null, not working", Toast.LENGTH_LONG)
.show();
}
if (result != null
&& result
.equals(SERVER_RES_RES_SIGN_UP_SUCCESFULL)) {
Toast.makeText(getApplicationContext(),
R.string.signup_successfull,
Toast.LENGTH_LONG).show();
// showDialog(SIGN_UP_SUCCESSFULL);
} else if (result != null
&& result
.equals(SERVER_RES_SIGN_UP_USERNAME_CRASHED)) {
Toast.makeText(getApplicationContext(),
R.string.signup_username_crashed,
Toast.LENGTH_LONG).show();
// showDialog(SIGN_UP_USERNAME_CRASHED);
} else // if
// (result.equals(SERVER_RES_SIGN_UP_FAILED))
{
Toast.makeText(getApplicationContext(),
R.string.signup_failed, Toast.LENGTH_LONG)
.show();
// showDialog(SIGN_UP_FAILED);
}
}
});
}
};
thread.start();
}
Server Case for "createGroup" method:
case "createGroup":
$SQLtest = "insert into groups(groupName, uniqueGroup, createTime)
VALUES('TestGroup', 1234567891, NOW())";
error_log("$SQLtest", 3 , "error_log");
if($result = $db -> query($SQLtest))
{
$out = SUCCESSFUL;
}
else
{
$out = FAILED;
}
break;
Messaging Service and createGroup method:
public class MessagingService extends Service implements Manager, Updater {
// private NotificationManager mNM;
public static String USERNAME;
public static final String TAKE_MESSAGE = "Take_Message";
public static final String FRIEND_LIST_UPDATED = "Take Friend List";
public static final String MESSAGE_LIST_UPDATED = "Take Message List";
public ConnectivityManager conManager = null;
private final int UPDATE_TIME_PERIOD = 15000;
private String rawFriendList = new String();
private String rawMessageList = new String();
SocketerInterface socketOperator = new Socketer(this);
private final IBinder mBinder = new IMBinder();
private String username;
private String password;
private boolean authenticatedUser = false;
// timer to take the updated data from server
private Timer timer;
private StorageManipulater localstoragehandler;
private NotificationManager mNM;
public class IMBinder extends Binder {
public Manager getService() {
return MessagingService.this;
}
}
#Override
public void onCreate() {
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
localstoragehandler = new StorageManipulater(this);
// Display a notification about us starting. We put an icon in the
// status bar.
// showNotification();
conManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
new StorageManipulater(this);
// Timer is used to take the friendList info every UPDATE_TIME_PERIOD;
timer = new Timer();
Thread thread = new Thread() {
#Override
public void run() {
Random random = new Random();
int tryCount = 0;
while (socketOperator.startListening(10000 + random
.nextInt(20000)) == 0) {
tryCount++;
if (tryCount > 10) {
// if it can't listen a port after trying 10 times, give
// up...
break;
}
}
}
};
thread.start();
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public String createNewGroup(String groupName) throws NullPointerException, UnsupportedEncodingException {
String params = "action=createGroup";
String result = socketOperator.sendHttpRequest(params);
return result;
}
}
Because your code has an inherent race condition. And an evil one.
Change to something like this:
public void onCreate(Bundle savedInstanceState) {
bindService(new Intent(CreateGroup.this, MessagingService.class),
mConnection, Context.BIND_AUTO_CREATE);
// but do not start thread here!
}
public ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
imService = ((MessagingService.IMBinder) service).getService();
startCommunicationThread(); // <----------------------- only here can you start comm. thread
}
public void onServiceDisconnected(ComponentName className) {
imService = null;
Toast.makeText(CreateGroup.this, R.string.local_service_stopped,
Toast.LENGTH_SHORT).show();
}
};
void startCommunicationThread() {
Thread thread = new Thread() {
String result = new String();
#Override
public void run() {
try {
result = imService.createNewGroup(newGroupName);
..........
}
If you want your code to be even more secure, use a connection state field:
public ServiceConnection mConnection = new ServiceConnection() {
volatile boolean isConnected;
public void onServiceConnected(ComponentName className, IBinder service) {
isConnected = true; // <---------------------
imService = ((MessagingService.IMBinder) service).getService();
startCommunicationThread();
}
public void onServiceDisconnected(ComponentName className) {
isConnected = false; // <---------------
imService = null;
Toast.makeText(CreateGroup.this, R.string.local_service_stopped,
Toast.LENGTH_SHORT).show();
}
};
And poll isConnected from within startCommunicationThread to make sure no sudden disconnects.
in my project MessagingService.IMBinder MessagingService gives error is there any java class that I should import.
Service class:
private IBinder mBinder ;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
}
#Override
public void onDestroy() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("service","started");
new Connect().execute("");
return Service.START_STICKY;
}
private class Connect extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
ConnectionConfiguration connConfig = new ConnectionConfiguration(
HOST, PORT, SERVICE);
final XMPPConnection connection = new XMPPConnection(connConfig);
Thread t= new Thread(new Runnable() {
#Override
public void run() {
try {
connection.connect();
// SASLAuthentication.supportSASLMechanism("PLAIN", 0);
connection.login(USERNAME, PASSWORD);
Log.i("NetWorkConnection",
"Logged in as " + connection.getUser());
System.out.println(connection);
setConnection(connection);
} catch (XMPPException ex) {
Log.e("NetWorkConnection", "Failed to log in as "
+ USERNAME);
Log.e("NetWorkConnection", ex.toString());
setConnection(null);
}
}});
t.start();
return null;
}
}
public void setConnection(XMPPConnection connection) {
NetworkConnection.connection = connection;
}
public class MyBinder extends Binder
{
NetworkConnection getService() {
return NetworkConnection.this;
}
}
public XMPPConnection getconnection()
{
if (connection != null) {
Log.d("NetworkConnection","connection send");
return connection;
}
else
{
Log.d("NetworkConnection","connection null");
return null;
}
}
}
Activity Class:
private NetworkConnection service;
XMPPConnection connection=NetworkConnection.connection;
Button next;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.sign_in);
next=(Button)findViewById(R.id.bRetry);
if(!isMyServiceRunning())
{
Intent i=new Intent(this,NetworkConnection.class);
startService(i);
}
next.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
System.out.println(connection);
if(connection!=null)
{
Intent i = new Intent (getApplicationContext(),UserIndex.class);
startActivity(i);
}else{
Intent i = new Intent(SignIn.this,SignIn.class);
startActivity(i);
}
}
});
}
#Override
protected void onResume() {
bindService(new Intent(this, NetworkConnection.class), mConnection,
Context.BIND_AUTO_CREATE);
super.onResume();
}
#Override
protected void onPause() {
unbindService(mConnection);
super.onPause();
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
service = ((NetworkConnection.MyBinder) binder).getService();
Log.d("Service","Connected");
System.out.println("service connection methoddd");
connection=service.getconnection();
}
public void onServiceDisconnected(ComponentName className) {
connection=null;
service = null;
}
};
private boolean isMyServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (NetworkConnection.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
}
I am creating a chat application using XMPP and asmack, So i used service. But the problem is that when i start the service onServiceConnected method never execute.That is why when i retrieve the connection object from service it always give null value. I have not much idea about it . please guide me.
Good Morning All,
I am currently buidling a media player for Android, and I am having trouble binding my player service to an Activity and pulling data from it. Bear with me...a lot of code follows.
My code---
Interface:
interface MyInterface{
void playFile( in String file);
void shuffle ();
String getPlayingData();
}
Service:
public class MyService extends Service {
public Context context;
public static String nowPlayingData = null;
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final MyInterface.Stub mBinder = new MyInterface.Stub() {
public void playFile(String file) throws DeadObjectException {
//Song playing method working great!
}
public void shuffle()throws DeadObjectException {
//This method picks a random song and passes it to nowPlayingData string
}
public String getPlayingData() throws RemoteException {
return nowPlayingData;
}
};
#Override
public void onCreate() {
//Toast.makeText(this, "My Service Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
mp.setLooping(false); // Set looping
}
#Override
public void onDestroy() {
//Toast.makeText(this, "My Service Stopped", Toast.LENGTH_LONG).show();
Log.d(TAG, "onDestroy");
mp.stop();
}
#Override
public void onStart(Intent intent, int startid) {
//Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
Log.d(TAG, "onStart");
}
}
Main Screen Activity, Shuffle Button:
Service is started in onCreate. When I click on the shuffle button it uses a method in the service to play a random song, thus setting the nowPlayingData string.
public class mainMenu extends Activity {
private MyInterface mInterface;
private ServiceToken mToken;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent startedSvc = new Intent(mainMenu.this, MyService.class);
boolean success = this.bindService(
startedSvc, svcConn, Context.BIND_AUTO_CREATE);
this.startService(startedSvc);
findViewById(R.id.shuffle).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
sInterface.shuffle();
} catch (RemoteException e) {
e.printStackTrace();
}
Intent play_screen = new Intent(MyPlayer.getContext(), NowPlaying.class);
startActivity(play_screen);
}
Player Activity:
I want to bind to the service, and pull nowPlayingData over using the interfaces getPlayingData method.
public class NowPlaying extends Activity implements OnClickListener {
public static String nowPlayingData = null;
MyInterface mInterface;
boolean isConnected = false;
RemoteServiceConnection conn = null;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.now_playing);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
Log.i("Log", "Player Loaded");
bindService();
getData();
fillView();
}
public void fillView(){
//This method needs the nowPlayingData string to update the view
}
class RemoteServiceConnection implements ServiceConnection {
public void onServiceConnected(ComponentName className,
IBinder boundService ) {
mInterface = MyInterface.Stub.asInterface((IBinder)boundService);
isConnected = true;
Log.d("Now Playing", "Service Connected" );
}
public void onServiceDisconnected(ComponentName className) {
sInterface = null;
// updateServiceStatus();
isConnected = false;
Log.d( getClass().getSimpleName(), "onServiceDisconnected" );
getData();
}
};
private void bindService() {
if(conn == null) {
conn = new RemoteServiceConnection();
Intent i = new Intent();
i.setClassName("com.musicplayer.MyPlayer", "com.musicplayer.MyPlayer.MyService");
bindService(i, conn, Context.BIND_AUTO_CREATE);
Log.d( getClass().getSimpleName(), "bindService()" );
} else {
Toast.makeText(NowPlaying.this, "Cannot bind - service already bound", Toast.LENGTH_SHORT).show();
}
}
private void getData() {
if(conn == null) {
Log.i("getData", "No Connection");
} else {
try {
String data = mInterface.getPlayingData();
Log.i("Data Recieved", data);
Log.d( getClass().getSimpleName(), "invokeService()" );
} catch (RemoteException re) {
Log.e( getClass().getSimpleName(), "RemoteException" );
}
}
}
}
I have been studying many examples online, and perhaps my mish-mash of attempts has caused this to not work. My code works all the way through to binding the service, but OnServiceConnected is never called, and conn remains null.
Any help you guys can provide is greatly appreciated.
Thanks,
Josh
Android will not make re-entrant event calls to your activity, so onServiceConnected can't be called until onCreate has returned