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.
Related
I'm trying to call a service class from another service class but I get this error:
android.content.Context.getPackageName() on a null object reference
Do you know how I call service from another service?
When I setup my app to phone first, a broadcastreceiver is starting Alarm class and in Alarm class, I want to start another service in ReadGmail() method. But I get that null object reference error.
Here is my code:
public class Alarm extends Service {
private String userName;
private String password;
private String receivingHost;
Context context;
public int onStartCommand(Intent intent, int flags, int startId) {
final Handler handler = new Handler();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
String senderPassword=new String("password");
String senderUserName=new String("username#gmail.com");
Alarm newGmailClient=new Alarm();
newGmailClient.setAccountDetails(senderUserName, senderPassword);
newGmailClient.readGmail();
}
});
}
};
Timer timer = new Timer();
timer.schedule(doAsynchronousTask, 10, 120000);
return super.onStartCommand(intent, flags, startId);
};
public void setAccountDetails(String userName,String password){
this.userName=userName;//sender's email can also use as User Name
this.password=password;
}
public void readGmail(){
this.receivingHost="imap.gmail.com";//for imap protocol
Properties props2=System.getProperties();
props2.setProperty("mail.store.protocol", "imaps");
Session session2=Session.getInstance(props2, null);
try {
Store store=session2.getStore("imaps");
store.connect(this.receivingHost,this.userName, this.password);
Folder folder=store.getFolder("INBOX");//get inbox
folder.open(Folder.READ_ONLY);//open folder only to read
Message message[]=folder.getMessages();
String key= "Hey";
String subject;
for(int i=0;i<message.length;i++){
System.out.println(message[i].getSubject());
subject=message[i].getSubject();
if(subject.equals(key)){
System.out.println("inside");
Intent mTutorial = new Intent(Alarm.this, LaunchActivity.class);
this.startService(mTutorial);
//I want to call service class in here. LaunchActivity is my service class.
}
//Log.d(message[i].getSubject(),message[i].getSubject());
}
folder.close(true);
store.close();
} catch (Exception e) {
System.out.println(e.toString());
}
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.d("", "FirstService destroyed");
}
}
This is your problem:
Alarm newGmailClient=new Alarm();
Your Alarm class extends Service. It is an Android Service. You cannot create an instance of an Android component with new. Only Android can create Android components. If you want to start a Service, you call startService.
Why do you want to start another Service? Please explain.
Use an interface your Service will use to communicate events:
public interface ServiceCallbacks {
void doSomething();
}
I have asked this question here but it was marked as duplicate -
however I didn't find any solution helpful mentioned in comments.
Here, I am asking again with more details ...
I am doing a sample app (PoC) on HCE and using HostApduService as per Android user guide. I have created two apps
1) ReaderApp - acting as card reader
2) HCEApp - emulating a card
In HCEApp, I have created a class 'MyService' extending HostApduService
public class MyService extends HostApduService {
private int messageCounter;
private final String TAG = "MyService";
Intent mIntent;
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate");
mIntent = new Intent(this, MyActivity.class);
mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(mIntent);
}
/**
* returned bytes will be sent as response. This method runs in Main thread
* so return ASAP.
*/
#Override
public byte[] processCommandApdu(byte[] apdu, Bundle extras) {
if (selectAidApdu(apdu)) {
Log.i(TAG, "Application selected");
return getWelcomeMessage();
} else {
Log.i(TAG, "Received: " + new String(apdu));
return getNextMessage();
}
}
private byte[] getWelcomeMessage() {
return "Hello Desktop!".getBytes();
}
private byte[] getNextMessage() {
return ("Message from android: " + messageCounter++).getBytes();
}
private boolean selectAidApdu(byte[] apdu) {
if (apdu != null) {
for (byte b : apdu) {
System.out.printf("0x%02X", b);
}
}
return apdu.length >= 2 && apdu[0] == (byte) 0
&& apdu[1] == (byte) 0xa4;
}
#Override
public void onDeactivated(int reason) {
Log.i(TAG, "Deactivated: " + reason);
}
#Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
As you can see in onCreate(), I am launching MyActivity provides user to enter some information and needs to be sent back to MyService.
I think I can not use binding as 'onBind()' is declared final in HostApduService as below
#Override
public final IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
Please let me know if I am understading it correctly. Appreciate any help.
Thanks
iuq
Whether you can use onBind or not I do not know, but I recently worked with a BroadcastReceiver from which I had to start a Service. You cannot bind a Service from a BroadcastReceiver according to docs, you can only start it. I needed to send some data to the Service from my BroadcastReceiver at some later point, and since the binder techniques was not available to me, I had to find a different way to communicate with the Service, much like your case where you don't have a reference to it.
I did some research but could not find any solution, but then I remembered that you can pass intent data with the startService(intent) call. I start my Service work in onCreate instead, as onCreate is only called once when the Service is created.
In your Activity
public void sendDataToService(){
Intent intent = new Intent(context, MyService.class);
intent.putExtra("message", SOME_DATA);
context.startService(intent);
}
In your Service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Check if intent has extras
if(intent.getExtras() != null){
// Get message
int message = intent.getExtras().getInt("message");
}
return START_NOT_STICKY;
}
This may be some sort what of a hack since "startService" does not sound like it should be used to send messages, and am not sure if this is exactly what you need, but it worked for me, so I hope it works for you. Cheers
Edit: BTW. I use it to tell a LocationService that a particular activity no longer want location updates.
I ended up taking a different approach to solving this same problem. When I bind to my HostApduService subclass, I grab a handle to the Messenger interface returned by the HostApduService onBind implementation.
Here's some sample code. This would all go in your activity implementation (calling it MyActivity here, communicating with MyHostApduServiceSubclass). Here's what MyActivity would need to include:
private Messenger mAPDUMessenger;
...
#Override
protected void onStart() {
super.onStart();
Context context = getApplicationContext();
Intent apduIntent = new Intent(montext, ContactlessApduService.class);
context.bindService(apduIntent, mAPDUConnection, Context.BIND_AUTO_CREATE);
}
...
private ServiceConnection mAPDUConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
// The HostApduService has a final override on the onBind() service method that returns
// an IMessageHandler interface that we can grab and use to send messages back to the
// terminal - would be better to get a handle to the running instance of the service so
// that we could make use of the HostApduService#sendResponseApdu public method
mAPDUMessenger = new Messenger(service);
registerAPDUMessengerIntentFilters();
// ^ This method sets up my handlers for local broadcast messages my BroadcastReceiver processes.
}
...
}
...
private void registerAPDUMessengerIntentFilters() {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(MyActivity.this);
IntentFilter intentFilter = new IntentFilter(MyHostApduServiceSubclass.ACTION_PPSE_APDU_SELECT);
lbm.registerReceiver(apduMessageBroadcastReceiver, intentFilter);
}
...
BroadcastReceiver apduMessageBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(MyHostApduServiceSubclass.ACTION_PPSE_APDU_SELECT)) {
sendResponseApdu(MyActivity.PPSE_APDU_SELECT_RESPONSE_BYTES);
}
}
};
...
public final void sendResponseApdu(byte[] responseApdu) {
Message responseMsg = Message.obtain(null, MyHostApduServiceSubclass.MSG_RESPONSE_APDU);
// ^ Note here that because MSG_RESPONSE_APDU is the message type
// defined in the abstract HostApduService class, I had to override
// the definition in my subclass to expose it for use from MyActivity.
// Same with the KEY_DATA constant value below.
Bundle dataBundle = new Bundle();
dataBundle.putByteArray(MyHostApduServiceSubclass.KEY_DATA, responseApdu);
responseMsg.setData(dataBundle);
try {
mAPDUMessenger.send(responseMsg);
} catch (RemoteException e) {
// Do something with the failed message
}
}
And then your HostApduService subclass would just need to send a broadcast to your activity indicating what APDU command was received. Here is what would need to be included in MyHostApduServiceSubclass:
public static final String ACTION_PPSE_APDU_SELECT = "ACTION_PPSE_APDU_SELECT";
// Abstract super class constant overrides
public static final String KEY_DATA = "data";
public static final int MSG_RESPONSE_APDU = 1;
#Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
Context context = getApplicationContext();
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
if (Arrays.equals(MyHostApduServiceSubclass.PPSE_APDU_SELECT_BYTES, commandApdu)) {
lbm.sendBroadcast(new Intent(ACTION_PPSE_APDU_SELECT));
}
return null;
// ^ Note the need to return null so that the other end waits for the
// activity to send the response via the Messenger handle
}
I created an activity that calls a service and the service creates a Thread that send and receive some data to/from the server, I can open other apps and the Service and the Thread run ok, but when I close the activity, the Service keeps running but the thread stops working. Why??? How can I keep the Thread running!!.
Code
Activity
package com.connectus.app;
public class ConnectUsActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_connect_us);
Intent startServiceIntent = new Intent(getApplicationContext(), ConnectUsService.class);
startService(startServiceIntent);
}
Service
package com.connectus.app;
public class ConnectUsService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Thread t=new Thread(new Runnable() {
private DataInputStream in;
private BufferedReader br;
private DataOutputStream out;
#Override
public void run() {
Socket server=null;
try{
server=new Socket("10.10.40.58",4444);
in = new DataInputStream(server.getInputStream());
br=new BufferedReader(new InputStreamReader(in));
out = new DataOutputStream(server.getOutputStream());
while(true){
out.writeUTF("aaaaa");
String leido=in.readUTF();
out.writeUTF("asdf");
Thread.sleep(60000);
}
}catch(IOException ioe){
ioe.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
}
});
t.start();
return START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
This is just a part of my code, I hope it helps.
Thanks everyone, finally i find a solution. It was necesary to use the setForeground() method, I just added this code to my service Class:
Notification note=new Notification();
startForeground(1337, note);
According to my research, this code is used to prevent that the service get killed by itself.
best regards!
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
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.