android implement xmppconnection service - android

I am trying to create a basic chat app using asmack and Openfire.
I have created a bound service for the XMPPConnection and each Activity binds to it.
Whenever I try to bind to a Service there is a very long delay. I know that the bindService is asynchronous but I want to be certain that my implementation of the Service is correct before I begin looking elsewere for problems.
I bind my Service in the onCreate method and try to access the connection in the onStart.
I am still new to this but I suspect that I have done something wrong thread-wise. The way my app runs now, the mBound variable returns true only if I try to access it from an OnClickListener. What is it that happens in the Listener that makes such a big difference? I tried to find the code for the OnClick method but I couldn't find it.
My XMPPConnectionService is this:
package com.example.smack_text;
import java.io.File;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class XMPPService extends Service{
XMPPConnection connection;
// private final IBinder mBinder = new LocalBinder();
#Override
public void onCreate(){
super.onCreate();
Log.d("service","created");
}
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
#Override
public IBinder onBind(Intent intent) {
Log.d("sevice","bound");
LocalBinder mBinder = new LocalBinder (this);
return mBinder;
}
public class LocalBinder extends Binder {
XMPPService service;
public LocalBinder (XMPPService service)
{
this.service = service;
}
public XMPPService getService (){
return service;
}
// XMPPService getService() {
// return XMPPService.this;
// }
}
public void connect(final String user, final String pass) {
Log.d("Xmpp Alex","in service");
ConnectionConfiguration config = new ConnectionConfiguration("10.0.2.2",5222);
// KEYSTORE SETTINGS
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
config.setTruststoreType("AndroidCAStore");
config.setTruststorePassword(null);
config.setTruststorePath(null);
}
else {
config.setTruststoreType("BKS");
String path = System.getProperty("javax.net.ssl.trustStore");
if (path == null)
path = System.getProperty("java.home") + File.separator + "etc"
+ File.separator + "security" + File.separator
+ "cacerts.bks";
config.setTruststorePath(path);
}
// Create XMPP Connection
connection = new XMPPConnection(config);
new Thread(new Runnable() {
#Override
public void run() {
try {
connection.connect();
connection.login(user, pass);
if(connection.isConnected()){
Log.d("Alex", "connected biatch!");
}
else{
Log.d("Alex","not connected");
}
} catch (XMPPException e) {
e.printStackTrace();
}
}
}).start();
}
public void disconnect(){
if(connection.isConnected()){
connection.disconnect();
}
else{
Toast.makeText(getApplicationContext(), "not connected", Toast.LENGTH_LONG).show();
}
}
}

I implement an Android Chat with Asmack.
I have created a Service.
The service has a global variable with the XmppConnection.
At the begining i use the thread for connect and login.
then I set VCard for logged user, set rosterListener
finally set connection.addPacketListener
I update the activities with a BroadcastReceiver activity side and
#Override
public IBinder onBind(Intent arg0) {
return mBinderXmpp;
}
public class BinderServiceXmpp extends Binder {
ServiceXmpp getService() {
return ServiceXmpp.this;
}
}
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
DisplayInfo();
handler.postDelayed(this, 2000); // 2 segundos
}
};
private void DisplayInfo() {
isRunning = true; // flag to know if service is running
Intent tempIntent;
tempIntent = new Intent(BROADCAST_ACTION);
tempIntent.putExtra("UPDATE_OPTION", UPDATE_ACTION);
sendBroadcast(tempIntent);
}

Your implementation works, you still need to implement the handler for the actions like CONNECT and DISCONNECT from your clients bound (LoginActivity for instance).
Example:
class IncomingHandler extends Handler { // Handler of incoming messages from clients bound.
#Override
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_CONNECT_XMPP:
new AsyncTask<Void, Void, Boolean>(){
#Override
protected Boolean doInBackground(Void... params) {
// Do connection
}
#Override
protected void onPostExecute(Boolean aBoolean) {
// Notify the connection status
}
}.execute();
break;
case MSG_DICCONNECT_XMPP:
new AsyncTask<Void, Void, Boolean>(){
#Override
protected Boolean doInBackground(Void... params) {
// Do disconnection
}
#Override
protected void onPostExecute(Boolean aBoolean) {
// Notify the connection status
}
}.execute();
break;
default:
super.handleMessage(msg);
}
}
}
But, this approach of creating an AsyncTask anytime the Service needs to run a network action will reach its limit for the sendBroadcast in a BroadcastReceiver.
If you have BroadcastReceiver that needs to start or stop the connection by sending a message to the XMPPService, you have something like this:
public class NetworkConnectivityReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NetworkInfo network = cm.getActiveNetworkInfo();
network = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if (XmppService.isRunning() && network.isConnected()) {
context.sendBroadcast(new Intent(XmppService.ACTION_CONNECT));
} else if (XmppService.isRunning() && !network.isConnected()) {
context.sendBroadcast(new Intent(XmppService.ACTION_DISCONNECT));
}
}
}
Then, you will need to implement a Broadcast listener in the XmppService class.
But, you CANNOT run an AsyncTask in a Broadcast listener!
The remain options are described in my post here:
Android - Best option to implement Networking Class

Related

service instance still null after binding

I have a service, and I am trying to bind an activity to it. The problem is...after running bindService(..), the service instance that Im setting inside the serviceconnection is still null, and I dont know why.
private ConnectionService conn;
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
conn = ((ConnectionService.ConnectionBinder)service).getService();
Toast.makeText(main_tab_page.this, "Connected", Toast.LENGTH_SHORT)
.show();
}
#Override
public void onServiceDisconnected(ComponentName name) {
conn = null;
}
};
#Override
protected void onStart()
{
super.onStart();
//check start connection service
if(conn == null)
{
Intent serviceIntent = new Intent(this, ConnectionService.class);
bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
}
//connect to server
server.conn = conn;
//THIS STATEMENT FAILS: NULL REFERENCE, conn is Null here, and I have no idea why
conn.ConnectToServer(server);
server.StartReader();
}
Yes: The service is defined in the manifest.
Yes: I can start the service from the MAIN Activity (this code resides in an activity that is started BY the main activity, which is where i need to bind to the service) I have checked to make sure the service actually does start....it does
According to every example i've managed to locate for bound services, this should be working. Can anyone tell me why its not?
Edit: Add service code definition
public class ConnectionService extends Service{
private BlockingQueue<String> MessageQueue;
public final IBinder myBind = new ConnectionBinder();
public class ConnectionBinder extends Binder {
ConnectionService getService() {
return ConnectionService.this;
}
}
private Socket socket;
private BufferedWriter writer;
private BufferedReader reader;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(MessageQueue == null)
MessageQueue = new LinkedBlockingQueue<String>();
return Service.START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
return myBind;
}
//some other code that has everything to do with what the service does, and nothing to do with how it should be started/run
}
Please check the service is declared in Manifest.

How to get progress dialog until get the response from service in android?

I am using service for running long background tasks in my application, in the service these functions are running login to XMPP and getting some data from XMPP server. i want to show the progress bar upto login completed. How to get response from service to activity to Update progress bar properly to avoid some exceptions in UI.
I am calling service like this
final Intent gtalk_intent = new Intent(AccountsActivity.this, GtalkService.class);
gtalk_intent.putExtra("user_name", acc.getAcc_Name());
gtalk_intent.putExtra("user_pass", acc.getAcc_Pass());
startService(gtalk_intent);
this is the code from service
public class PmService extends Service {
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class PmBinder extends Binder {
public PmService getService() {
return PmService.this;
}
}
#Override
public void onCreate() {
super.onCreate();
context = this;
app_preferences = new AppPreferences(this);
chat_source = new ChatsDataSource(this);
chat_source.open();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Bundle extras = intent.getExtras();
if(extras == null) {
full_name = extras.getString("user_name");
if(full_name.contains("#")) {
String[] _na = full_name.split("#");
U_name = _na[0];
}
U_pass = extras.getString("user_pass");
}
new PmAsync().execute();
return START_STICKY;
}
private class PmAsync extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
}
#Override
protected Void doInBackground(Void... params) {
SASLAuthentication.supportSASLMechanism("PLAIN", 0);
ConnectionConfiguration config = new ConnectionConfiguration(server_host, SERVER_PORT, SERVICE_NAME);
configure(ProviderManager.getInstance());
m_connection = new XMPPConnection(config);
try {
m_connection.connect();
Roster.setDefaultSubscriptionMode(Roster.SubscriptionMode.manual);
} catch (XMPPException e) {
e.printStackTrace();
}
try {
m_connection.login(U_name, U_pass);
setPacketFilters();
} catch (XMPPException e) {
}
return null;
}
}
i want to show the progress bar upto login completed, how to response from service after login completed?
Via Binder you can send callbacks to your Activity, which means that you can update UI.
Add according method to your Binder (let's name it onProgress)
From your AsyncTask call method of this Binder
In order to know about progress updates consider using Observer pattern (in other words - your Activity should listen for updates of your Binder, or more specifically - of calling Binder.onProgress method)
You can update the progress bar via overriding the onProgress() method
here is a close to your case that you can refer to.link

How to bind an Activity to a Service and control and manage the Service from the Activity

I'm trying to bind an Activity to a LocalService to interact with it. But in my Activity I am only able to make calls to methods defined in my LocalBinder and not in my LocalService. What am I doing wrong?
Not starting scratch I read another question and I have read a little how to code some sample code and my code resembles that sample code. Also I have been reading some of the Service Documentation for convenience here is a small quote from that section of the documentation:
"A service is "bound" when an application component binds to it by calling bindService(). A bound service offers a client-server interface that allows components to interact with the service, send requests, get results, and even do so across processes with interprocess communication (IPC). A bound service runs only as long as another application component is bound to it. Multiple components can bind to the service at once, but when all of them unbind, the service is destroyed."
But I can't do that. As mentioned above the best I can do is to have my Activity call methods defined in my LocalBinder. I have achieved nothing like the part highlighted in black above.
If it helps here are the relevant portions of my code.
LocalService to be bound to:
/**************************************************************************************************
* Filename: LocalService.java
* Project name: Local Service Sample
* Application name: Local Service
* Description: This file contains the LocalService (extends Service) for our Local Service app
**************************************************************************************************/
package com.marie.localservicesample;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
public class LocalService extends Service {
private NotificationManager mNM;
// Unique Identification Number for the Notification.
// We use it on Notification start, and to cancel it.
private int NOTIFICATION = R.string.local_service_started;
// just some arbitrary numbers for test purposes
public static int statusCode = 99;
public static int emptyMsg = 549;
// I get my Extras from onStartCommand and use in ServiceWorker() thread
public static final String EXTRA_MAC = "com.marie.localservicesample.EXTRA_MAC";
private String macString;
public static final String EXTRA_MESSENGER = "com.marie.localservicesample.EXTRA_MESSENGER";
private Messenger messenger;
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
//private static final String macString = "00:06:66:02:D0:EC";
Boolean stop_receive_data = false;
// This is the object that receives interactions from clients. See
// RemoteService for a more complete example - or not because
// this is a local service
private final IBinder mBinder = new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
Log.i("onBind", "called in LocalService" );
Log.i("onBind", "intent: " + intent.toString());
Log.i("onBind", "mBinder: " + mBinder);
return mBinder;
}
#Override
public void onCreate() {
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// Display a notification about us starting. We put an icon in the status bar.
showNotification();
}
// Call this at the end of onStartCommand() after we got the Extras
public void afterStartCommand() {
Thread thr = new Thread(null, new ServiceWorker(), "LocalService");
thr.start();
}
/*
* This is the ServiceWorker thread that passes messages to the handler defined in
* the Controller activity.
*/
class ServiceWorker implements Runnable
{
public void run() {
// do background processing here... something simple
Looper.prepare();
BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice btDevice = btAdapter.getRemoteDevice(macString);
BluetoothSocket btSocket = null;
InputStream btIstream = null;
OutputStream btOstream = null;
try {
btSocket = btDevice.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e1) {
e1.printStackTrace();
}
try {
btSocket.connect();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
btIstream = btSocket.getInputStream();
btOstream = btSocket.getOutputStream();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
int data = btIstream.read();
// reset the bluetooth device
while (data != 63) {
Log.d("LocalService", "resetting bluetooth device");
btOstream.write('r');
data = btIstream.read();
}
StringBuffer strBuffer = new StringBuffer("");
Boolean dataBegin = false;
int ndxPlus = 0;
while (data != -1) {
char printableB = (char) data;
if (data < 32 || data > 126) {
//printableB = ' ';
}
//Log.d("LocalService", Character.toString(printableB) + "(" + data + ")");
if (data == 63) {
btOstream.write('$');
btOstream.write(',');
}
if (data == 45) {
btOstream.write('1');
btOstream.write(',');
dataBegin = true;
}
if (dataBegin == true) {
strBuffer = strBuffer.append(Character.toString(printableB));
}
if (data == 13) {
dataBegin = false;
//Log.d("LocalServiceDataString", strBuffer.toString());
// send data to the handler to plot the data
Message msg = Message.obtain();
msg.what = Controller.MESSAGE_MAC;
msg.obj = strBuffer;
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
strBuffer = new StringBuffer("");
if (ndxPlus < 0) {
btOstream.write('+');
ndxPlus++;
}
}
data = btIstream.read();
if (stop_receive_data) data = -1;
}
} catch (IOException e1) {
e1.printStackTrace();
}
try {
btSocket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
LocalService.this.stopSelf();
Looper.loop();
// stop the service when done...
// Or use the unbindBtn in the MainActivity class?
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("LocalService", "Received start id " + startId + ": " + intent);
Bundle extras = intent.getExtras();
messenger = (Messenger)extras.get(EXTRA_MESSENGER);
macString = extras.getString(EXTRA_MAC);
afterStartCommand();
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
#Override
public void onDestroy() {
// Cancel the persistent notification.
mNM.cancel(NOTIFICATION);
stop_receive_data = true;
// Tell the user we stopped.
Toast.makeText(this, R.string.local_service_stopped, Toast.LENGTH_SHORT).show();
}
/**
* Show a notification while this service is running.
*/
private void showNotification() {
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.local_service_started);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.stat_sample, text, System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Controller.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, getText(R.string.local_service_label), text, contentIntent);
// Send the notification.
mNM.notify(NOTIFICATION, notification);
}
}
Activity that binds to LocalService:
/**************************************************************************************************
* Filename: Binding.java
* Project name: Local Service Sample
* Application name: Local Service
* Description: This file contains the Binding class for our Local Service application
**************************************************************************************************/
package com.marie.localservicesample;
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.IBinder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
/*
* Example of binding and unbinding to the local service.
* This demonstrates the implementation of a service which the client will
* bind to, receiving an object through which it can communicate with the service.
*/
public class Binding extends Activity {
private ILocalBinder mBoundService;
private boolean mIsBound;
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 = (ILocalBinder)service;
int statusCode = mBoundService.getStatusCode();
Log.d("Binding.java","called onServiceConnected. statusCode: " + statusCode);
Toast.makeText(Binding.this, R.string.local_service_connected,
Toast.LENGTH_SHORT).show();
}
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;
Log.d("Binding", "called onServiceDisconnected");
Toast.makeText(Binding.this, R.string.local_service_disconnected,
Toast.LENGTH_SHORT).show();
}
};
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).
bindService(new Intent(Binding.this, LocalService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
int statusCode = mBoundService.getStatusCode();
if (statusCode != 0) Log.d("doUnbindService", "Binding.java statusCode: " + statusCode);
// Tell the user we did an unbind
Toast.makeText(this, R.string.local_service_unbound, Toast.LENGTH_SHORT).show();
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.local_service_binding);
// Watch for button clicks.
Button button = (Button)findViewById(R.id.bind);
button.setOnClickListener(mBindListener);
button = (Button)findViewById(R.id.unbind);
button.setOnClickListener(mUnbindListener);
}
private OnClickListener mBindListener = new OnClickListener() {
public void onClick(View v) {
doBindService();
}
};
private OnClickListener mUnbindListener = new OnClickListener() {
public void onClick(View v) {
doUnbindService();
}
};
#Override
protected void onDestroy() {
super.onDestroy();
doUnbindService();
}
}
My ILocalBinder and LocalBinder:
/**************************************************************************************************
* Filename: ILocalBinder.java
* Project name: Local Service Sample
* Application name: Local Service
* Description: This file contains an example interface for my LocalBinder
**************************************************************************************************/
package com.marie.localservicesample;
public interface ILocalBinder {
public int getStatusCode();
}
/**************************************************************************************************
* Filename: LocalBinder.java
* Project name: Local Service Sample
* Application name: Local Service
* Description: This file contains the LocalBinder class for our Local Service application
**************************************************************************************************/
package com.marie.localservicesample;
import android.os.Binder;
import com.marie.localservicesample.LocalService;
/**
* 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 implements ILocalBinder {
#Override
public int getStatusCode() {
return LocalService.statusCode;
}
}
Thanks!
See the local service example.
Just copy the binder class code they have into your service instead of making a separate file for it: (inside the LocalService class declaration)
public class LocalService {
// This is the object that receives interactions from clients. See
// RemoteService for a more complete example.
private final IBinder mBinder = new LocalBinder();
/**
* 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;
}
}
...
}
and then:
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();
Now you can access your service directly using mBoundService.

Can Android's ServiceTestCase<MyService> send Messages to my service?

I want to test my bound service with ServiceTestCase.
The testing consists of binding to MyBindServer, and sending a Message.
Watching the logs, you can see the service is started when onBind() is called,
and a message is sent from testAHello(), but, the server's handleMessage() is never called.
From the logs:
I/TestRunner( 2099): started: testAHello(com.inthinc.mybindserver.test.MyBindServerTest)
I/MyBindServerTest( 2099): setUp()
I/MyBindServer( 2099): onBind, action=com.inthinc.mybindserver.START
I/MyBindServerTest( 2099): testAHello
I/MyBindServerTest( 2099): sending SAY_HELLO
[here is where I expect to see the output from handleMessage()]
I/MyBindServerTest( 2099): tearDown()
I/TestRunner( 2099): finished:testAHello(com.inthinc.mybindserver.test.MyBindServerTest)
I/TestRunner( 2099): passed: testAHello(com.inthinc.mybindserver.test.MyBindServerTest)
Here is the code for MyBindServer.java:
package com.inthinc.mybindserver;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
public class MyBindServer extends Service {
static final String TAG = "MyBindServer";
public static final int MSG_SAY_HELLO = 1;
final Messenger mMessenger = new Messenger(new IncomingHandler());
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
Log.i(TAG, String.format("handleMessage, what=%d", msg.what));
switch (msg.what) {
case MSG_SAY_HELLO:
Log.i(TAG, "hello");
break;
default:
super.handleMessage(msg);
}
}
}
#Override
public IBinder onBind(Intent intent) {
Log.i(TAG, String.format("onBind, action=%s", intent.getAction()));
return mMessenger.getBinder();
}
}
Here is the code for MyBindServerTest.java:
package com.inthinc.mybindserver.test;
import com.inthinc.mybindserver.MyBindServer;
import android.content.Intent;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.test.ServiceTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
public class MyBindServerTest extends ServiceTestCase<MyBindServer> {
private static final String TAG = "MyBindServerTest";
Messenger mServer = null;
public MyBindServerTest() {
super(MyBindServer.class);
}
public MyBindServerTest(Class<MyBindServer> serviceClass) {
super(serviceClass);
}
#Override
public void setUp() {
try {
super.setUp();
Log.i(TAG, "setUp()");
Intent bindIntent = new Intent("com.inthinc.mybindserver.START");
IBinder binder = bindService(bindIntent);
assertNotNull(binder);
mServer = new Messenger(binder);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void tearDown() {
try {
super.tearDown();
Log.i(TAG, "tearDown()");
} catch (Exception e) {
e.printStackTrace();
}
}
#SmallTest
public void testAHello() {
Log.i(TAG, "testAHello");
assertNotNull(mServer);
Message msg = Message.obtain(null, MyBindServer.MSG_SAY_HELLO);
Log.i(TAG, "sending SAY_HELLO");
try {
mServer.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
I was able to get this working using the procedure below..anyone is welcome to chime in if this is incorrect, but the example above works (i.e. MyBindServer's handler receives messages)
It seems as though ServiceTestCase's bindService() method intends to act like a local service. In this case, the goal is to test as a separate process, which means using the following instead of ServiceTestCase's bindService:
Intent bindIntent = new Intent(<registered intent>); //Where registered intent is declared in the manifest file
getContext().bindService(bindIntent,mConn,Context.BIND_AUTO_CREATE);
where mConn is a ServiceConnection object implemented to do whatever your test needs it to do, in the case above, set mServer.
With the above, MyBindServer's handleMessage() is called for the testAHello() test.
UPDATE: I have noticed that depending on how quickly the test processing is done, teardown() can be called before the binding is ready to use. In the case above adding control variables to throttle the program flow based on mConn's onServiceConnected being called provided consistent results.
E.g.
protected boolean bound = false;
protected boolean processed = false;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
Log.i(TAG,"Service conn");
mServer = new Messenger(service);
if(mServer != null
&& mServer != null){
bound = true;
}
processed = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
Log.i(TAG,"Service Disconn");
}
};
Then add:
while(!processed){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
to testAHello()

Message to Activity from AsyncTask

I am trying to send a message to my main activity from an Async task embedded within a Service. Basically, the Async task has to block on input and it can't run in the main Activity thread (the blocking was removed from the example code below). When the data comes in though, I need to send it to the main activity. I am finding that the messages sent below never make it. If the answer is moving the bind within the Async task, how do you do that? Pointing to example code would be a big help if possible.
public class InputService2 extends Service {
int bufferSize = 1024;
Process process;
DataInputStream os;
TextView inputView;
byte[] buffer = new byte[bufferSize];
private MyAsyncTask inputTask = null;
public void onCreate(){
inputTask = new MyAsyncTask();
inputTask.execute((Void[])null);
}
private class MyAsyncTask extends AsyncTask<Void,Void,Void> {
int mValue = 0;
static final int MSG_SET_VALUE = 3;
protected void onProgressUpdate(Void progress){
}
protected void onPostExecute(Void result) {
}
protected Void doInBackground(Void... params) {
int i = 0;
try {
mValue = 0x23;
Message message = Message.obtain(null,MSG_SET_VALUE,mValue,0);
mMessenger.send(message);
}
catch (Exception e) {
}
}
}
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
}
}
final Messenger mMessenger = new Messenger(new IncomingHandler());
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
Below is inside the activity:
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, msg.arg1, duration);
toast.show();
}
}
boolean mBound;
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 object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mBound = false;
}
};
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, InputService2.class), mConnection,
Context.BIND_AUTO_CREATE);
}
It looks like you based your example on the javadoc reference at http://developer.android.com/reference/android/app/Service.html#RemoteMessengerServiceSample, however you left out much of the implementation detail that actually makes it work. You have to go back and implement the full functionality referenced in that example to use that particular pattern: pay careful attention to the REGISTER_CLIENT and UN_REGISTER_CLIENT implementation sections in the IncomingHandler class as these are the bits that actually ensure that the Message can be transferred from the Service to the Activity.

Categories

Resources