I have activity in which is started service with startService() and in onStart() method binded to the same service. I'm sending some text using Messenger to service, then service open socket to the server in which this text is send to it, and server respond with some text (this working fine). The problem occurs when I'm trying to send response from service to activity using messenger. When application is started first time even that works fine, but after app is killed (so service restart) and I'm trying to send response from service to activity I get DeadObjectException. I commented line in service in which error occurse.
Here is my activity:
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
TextView tvFromServer;
EditText etSend;
Button bSend, bStopSocket, bBound, bStopService;
boolean mRun;
Intent mIntent;
/** Messenger for communicating with the service. */
Messenger mService = null;
/** Flag indicating whether we have called bind on the service. */
boolean mBound;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
//SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
// .findFragmentById(R.id.map);
//mapFragment.getMapAsync(this);
initialize();
mIntent = new Intent(this, SocketService.class);
startService(mIntent);
}
#Override
protected void onStart() {
super.onStart();
Intent iBind = new Intent(this, SocketService.class);
iBind.putExtra("messenger", new Messenger(mHandler));
bindService(iBind, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
mConnection = null;
mHandler = null;
}
}
Handler mHandler = new Handler(Looper.getMainLooper()){
#Override
public void handleMessage(Message msg) {
//Log.v("MapsActivity", (String) msg.obj );(String) msg.obj
tvFromServer.setText(msg.getData().getString("text"));
}
};
/**
* Class for interacting with the main interface of the service.
*/
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;
}
};
private void initialize(){
tvFromServer = (TextView) findViewById(R.id.tv_from_server);
bStopSocket = (Button) findViewById(R.id.b_stop);
mRun = false;
bStopSocket.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mRun = false;
}
});
etSend = (EditText) findViewById(R.id.et_send);
bSend = (Button) findViewById(R.id.b_send);
bSend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!mBound) return;
Message msg = Message.obtain(null, 1, etSend.getText().toString());
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
bBound = (Button) findViewById(R.id.b_bound);
bBound.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!mBound) return;
Message msg = Message.obtain(null, 1, "Hello from Activity");
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
bStopService = (Button) findViewById(R.id.b_stop_service);
bStopService.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mBound) {
unbindService(mConnection);
mBound = false;
}
stopService(mIntent);
}
});
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
#Override
public void onMapReady(GoogleMap googleMap) {
//mMap = googleMap;
// Add a marker in Sydney and move the camera
//LatLng sydney = new LatLng(-34, 151);
//mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
//mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}
}
Service:
public class SocketService extends Service {
public SocketService() {
}
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
public Messenger mMessenger, mUiMessenger;
PrintWriter out;
Socket mSocket;
boolean mRun;
Thread threa;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
if(msg.what == 1){
out.println((String) msg.obj);
}
}
}
#Override
public void onCreate() {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("SocketService");
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
mMessenger = new Messenger(new ServiceHandler(mServiceLooper));
mRun = false;
threa = new Thread(new Runnable() {
#Override
public void run() {
socketConnection();
}
});
threa.start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
Bundle extras = intent.getExtras();
mUiMessenger = (Messenger) extras.get("messenger");
return mMessenger.getBinder();
}
#Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
private void socketConnection() {
mRun = true;
try{
mSocket = new Socket("xxx.xxx.xxx.xxx", xxxxx);
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream())), true);
BufferedReader in = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
while(mRun){
String s = in.readLine();
Log.v("SocketServiceFromServer", s);
Bundle bundle = new Bundle();
bundle.putString("text", s);
Message msg = Message.obtain(null, 1);
msg.setData(bundle);
try {
mUiMessenger.send(msg); //DeadObjectException is thrown here after service is restarted
} catch (RemoteException e) {
e.printStackTrace();
}
}
mSocket.close();
}catch(Exception e){
Log.e("SocketService ", e.toString());
}
}
}
logcat:
My question is, why this error is thrown? Looks like activity do not send new messenger object to service when binding to it after restart.
I had exactly the same problem and I found solution. I lost 4 hours on debugging code, search Internet and try millions of different approaches. Solution is very easy. Remove calling startService in your onCreate. Use only bindService and unbindService. Yes it is so simple...
Related
I have created background service to connect my socket server, it works background while app is off, when user open the app MainActivity join to my service class and it looks fine, my service can change fragment in main activity, but when it get disconnected and want to change fragment in main activity then app crash
check my MainActivity
public class MainActivity extends AppCompatActivity {
private clientService mclientService;
private Intent mServiceIntent;
private final FragmentManager fm = getFragmentManager();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mclientService = new clientService(this);
mServiceIntent = new Intent(this, mclientService.getClass());
if (!isMyServiceRunning(mclientService.getClass())) {
startService(mServiceIntent);
}
}
public Fragment changeFragment (Fragment cls) {
FragmentTransaction ft = this.fm.beginTransaction();
ft.replace(R.id.bodyFrame, cls);
ft.commit();
return cls;
}
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
Log.i ("isMyServiceRunning?", true+"");
return true;
}
}
Log.i ("isMyServiceRunning?", false+"");
return false;
}
}
and the clientService:
public class clientService extends Service {
private Socket mSocket;
{
try {
IO.Options opts = new IO.Options();
opts.query = "_d=jakistakiid";
mSocket = IO.socket("http://10.0.2.2:3000", opts);
} catch (URISyntaxException e) {}
}
public clientService(MainActivity main) {
super();
mainAttach(main);
}
public clientService() {
}
public MainActivity mMain;
public void startIt(){
Log.i("eroapp", "Service Started");
if(mSocket != null) {
mSocket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.i("eroapp", "connected");
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.i("eroapp", "dc:"+mMain);
onDC();
}
});
mSocket.connect();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
startIt();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Intent broadcastIntent = new Intent(this, restartReceiver.class);
sendBroadcast(broadcastIntent);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
// CLIENT FUNCTIONS //
private void onDC(){
Log.i("eroapp", "DC:"+mMain);
}
private void mainAttach(MainActivity m) {
mMain = m;
Log.i("eroapp","Main created!");
if(!mSocket.connected()) {
mMain.changeFragment(new offlineFragment());
}else{
mMain.changeFragment(new singFragment());
}
}
}
looks fine, when i close app activity my service restarts and run in background, it says in logcat:
2019-11-17 02:41:22.686 17458-17458/com.example.secmsg I/eroapp: Service Started
2019-11-17 02:41:22.803 17458-17483/com.example.secmsg I/eroapp: connected
when i open app again, my service is already running, so its run only function mainAttach in clientService, and then service run changeFragment function in main activity, works great, but
when I get disconnected from server it says mMain is null ; < and logcat output:
2019-11-17 02:41:31.654 17458-17499/com.example.secmsg I/eroapp: dc:null
2019-11-17 02:41:31.654 17458-17499/com.example.secmsg I/eroapp: DCnull
The mclientService you created on the MainActivity is not the same as the clientService that was started by the Android system when you called startService(intent). All services created and started by the Android system by using the service class' empty constructor, therefore, clientService#mainAttach will never be called. Take a look at this answer for more information.
If you want to directly interact with the service on the MainActivity, you might want to bind the service to your activity. Check out the documentation about bound services here.
Another thing... It looks like you're planning to directly control the MainActivity from the service using the reference to the activity. Please never do that and use broadcasts instead. Good luck!
I've a task to running service every 3 second, the service will execute asynctask to checking sqlite and sending data into server
Code of myService.class
/* import foo.foo.foo */
public class myService extends Service {
public Runnable mRunnable = null;
private boolean mRunning = false;
Handler mHandler = new Handler();
IBinder mBinder = new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class LocalBinder extends Binder {
public myService getServerInstance() {
return myService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("Service"," onstart kepanggil ga?");
mRunnable = new Runnable() {
#Override
public void run() {
Log.d("Service","SERVICE RUN");
SharedPreferences pref = getSharedPreferences("wit_player_shared_preferences", MODE_PRIVATE);
String servcheck = pref.getString("serviceChecker", null);
DatabaseHandler db = new DatabaseHandler(getApplicationContext());
int countFlagAuditID = db.getCountFlagAuditID();
int countNeedToSend = db.getCountContact();
if (countNeedToSend > 0){
Log.d("countNeedToSend : ", String.valueOf(countNeedToSend));
sending a = new sending();
try {
if(servcheck.equals("no")){
Log.d("Service","SERVICE TRY CALL SENDING");
a.execute().get();
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
if (countFlagAuditID > 0){
Log.d("countFlagAuditID : ", String.valueOf(countFlagAuditID));
if(servcheck.equals("no")){
Log.d("Service","SERVICE TRY CALL SENDGET");
sendget b = new sendget();
b.execute();
}
}
db.close();
mHandler.postDelayed(mRunnable, 3 * 1000);
}
};
mHandler.postDelayed(mRunnable, 3 * 1000);
return START_STICKY;
}
//async task
private class sending extends AsyncTask<Void, Void, String >
{
#Override
protected void onPreExecute() {
Log.i("SENDING", "start sending");
SharedPreferences pref = getSharedPreferences("wit_player_shared_preferences", MODE_PRIVATE);
pref.edit().putString("serviceChecker", "yes").commit();
if (serv.equals("yes")){
Log.i("stop service", "service di stop");
stopSelf();
}
}
#Override
protected String doInBackground(Void... params) {
//send data to server
}
#Override
protected void onPostExecute(String result) {
SharedPreferences pref = getSharedPreferences("wit_player_shared_preferences", MODE_PRIVATE);
pref.edit().putString("serviceChecker", "no").commit();
}
}
private class sendget extends AsyncTask<Void, Void, String >
{
//execute post to server
}
}
I've a list of question about the code above:
to let my service run every 3sec I need to declare twice of mHandler.postDelayed(mRunnable, 3 * 1000);, if I'm declare the code just one, the service will run once, why it can be like that?
on sending asynctask I've add stopSelf() on onPreExecute() that mean the service will stop, but why doInBackground() task keep run?
Try to use timer instead of handler
private final Timer mTimer = new Timer();
mTimer.scheduleAtFixedRate(new LocationUpdateTask(), 0, 3000);
private class LocationUpdateTask extends TimerTask {
#Override
public void run() {
try {
//Do your stuff
} catch (Exception e) {
// TODO: handle exception
} catch (ExceptionInInitializerError in) {
}
}
}
I have written a Service that listens for UDP messages then changes a TextView and an ImageView based on the parsed message from the UDP messages. I'm getting an NPE when attemping to use a public getParsedMessage method from the service, which means that the service has not been started. It is declared as a service in the manifest exactly as it is spelled, so I know that is not the problem. Here is my MainActivity's code:
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;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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();
Integer parsedMessage = Integer.valueOf(mListenerService.getParsedMessage()); //this is the cause of the NPE
mImageView.setImageResource(mAlertAssignments.alarmImages[parsedMessage]);
if(parsedMessage >= 10 && parsedMessage <= 19 && parsedMessage != 0) {
mTextView.setText(mAlertAssignments.alertTextMessages[parsedMessage]);
} else {
mBlinkView.setText(mAlertAssignments.alertTextMessages[parsedMessage]);
}
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
ListenerService.LocalBinder binder = (ListenerService.LocalBinder) service;
mListenerService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
}
};
#Override
protected void onStart() {
super.onStart();
//start listener service
Intent listenerServiceIntent = new Intent(MainActivity.this, ListenerService.class);
this.bindService(listenerServiceIntent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
//unbind from service
if(mBound) {
this.unbindService(mConnection);
mBound = false;
}
}
}
The error occurs on line 75, which is marked above (Integer parsedMessage = Integer.valueOf(mListenerService.getParsedMessage());). I have followed the developer.android documentation in setting up and starting my service, however i seem to see conflicting information in multiple locations. Here is my ListenerService:
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;
}
static String UDP_BROADCAST = "UDPBroadcast";
//Boolean shouldListenForUDPBroadcast = false;
DatagramSocket socket;
private void listenAndWaitAndThrowIntent(InetAddress broadcastIP, Integer port) throws Exception {
byte[] recvBuf = new byte[15000];
if (socket == null || socket.isClosed()) {
socket = new DatagramSocket(port, broadcastIP);
socket.setBroadcast(true);
}
//socket.setSoTimeout(1000);
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
Log.e("UDP", "Waiting for UDP broadcast");
socket.receive(packet);
String senderIP = packet.getAddress().getHostAddress();
String message = new String(packet.getData()).trim();
Log.e("UDP", "Got UDB broadcast from " + senderIP + ", message: " + message);
broadcastIntent(senderIP, message);
setParsedMessage(message);
socket.close();
}
private void broadcastIntent(String senderIP, String message) {
Intent intent = new Intent(ListenerService.UDP_BROADCAST);
intent.putExtra("sender", senderIP);
intent.putExtra("message", message);
Log.e("UDP", "Message received containing" +message);
sendBroadcast(intent);
}
Thread UDPBroadcastThread;
void startListenForUDPBroadcast() {
UDPBroadcastThread = new Thread(new Runnable() {
public void run() {
try {
InetAddress broadcastIP = InetAddress.getByName("172.16.238.255"); //172.16.238.42 //192.168.1.255
Integer port = 12001;
while (shouldRestartSocketListen) {
listenAndWaitAndThrowIntent(broadcastIP, port);
}
//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;
}
void stopListen() {
shouldRestartSocketListen = false;
socket.close();
}
#Override
public void onCreate() {
};
#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;
}
}
I had previously been using an AsyncTask to fetch this data, however, I need it to be constantly fetching the data and updating the TextView and ImageView objects, and due to the ping speed using a while loop to do this caused it to run out of memory due to i assume it running on the UI thread. AlertAssignments is simply an Enum that binds image files and Strings to ordinal array values so that I can easily change the TextView and ImageView based on the integer value of the parsed message (parsedMessage[1] of the original message xxx!!!n!!!xxx gives parsedMessage[1] = n)
Any advice on how to resolve what is probably an oversight on my part would be great, thanks
Take a look at the Android activity lifecycle:
One thing you'll notice is that onCreate() is called before onStart(). This means you're trying to access the service before it actually starts.
The way I would work around this is to start your service in onCreate() (so it will start as soon as your activity is first created) and then read the value inside onResume(), so that every time your activity comes back into the foreground it will update according to the service.
You may also notice that if resources are required, your app could be killed as early as onPause(). It would be a good idea to do your cleanup there, instead of onDestroy().
EDIT:
If the above option didn't work, I suspect there's a race condition going on. Just because you started the service before you read from it, doesn't mean it was fully configured. Thankfully, you have a listener to tell you when the service is bound.
You can write a separate method specifically for updating the UI, and have your activity only call it once the service has started:
public class MyActivity {
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
ListenerService.LocalBinder binder = (ListenerService.LocalBinder) service;
mListenerService = binder.getService();
mBound = true;
readFromService();
}
#Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
}
};
private void readFromService() {
Integer parsedMessage = Integer.valueOf(mListenerService.getParsedMessage()); //this is the cause of the NPE
mImageView.setImageResource(mAlertAssignments.alarmImages[parsedMessage]);
if(parsedMessage >= 10 && parsedMessage <= 19 && parsedMessage != 0) {
mTextView.setText(mAlertAssignments.alertTextMessages[parsedMessage]);
} else {
mBlinkView.setText(mAlertAssignments.alertTextMessages[parsedMessage]);
}
}
}
I am trying to develop an application where the user can know the status of his/her Bluetooth Le device once he/she launches the app and the connection status is updated in text view in Home Fragment.I have tried to implement it by sending Broadcast from Ble service and catching it in onResume of Home fragment and subsequently updating it in status text view. The status does gets updated but if I change the fragment and come back to the home fragment the text view to show the status gets blank although the Bluetooth Le device is connected.How can I resolve this problem so that the status shows connected all through out if the device is connected and disconnected if it is disconnected?
Any Kind of guidance will be highly appreciated.
here are the code segments I have used to implement the above
In Bleservice.java
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
In HomeFragment.java
public class HomeFragment extends Fragment
{
private BroadcastReceiver mReceiver;
#Override
protected void onResume() {
super.onResume();
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (Bleservice.ACTION_GATT_CONNECTED.equals(action)) {
mConnected = true;
updateConnectionState(R.string.connected);
} else if (Bleservice.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
updateConnectionState(R.string.disconnected);
}
}
};
getActivity().registerReceiver(mReceiver,makeGattUpdateIntentFilter());
}
private void updateConnectionState(final int resourceId) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
tv_connected_disconnected.setText(resourceId);
}
});
}
#Override
public void onDestroy() {
super.onDestroy();
getActivity().unregisterReceiver(mReceiver);
}
private static IntentFilter makeGattUpdateIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Bleservice.ACTION_GATT_CONNECTED);
intentFilter.addAction(Bleservice.ACTION_GATT_DISCONNECTED);
return intentFilter;
}
Connect to your BleService by bindService. Check out example with Activity and Service.
private BleService mBluetoothLeService;
private boolean isConnected;
#Override
protected void onStart() {
super.onStart();
Intent bindIntent = new Intent(this, BleService.class);
startService(bindIntent);
bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
registerServiceReceiver(); //register here your mGattCallback that get actions from BleService
}
#Override
protected void onStop() {
super.onStop();
unbindService(mServiceConnection);
mBluetoothLeService = null;
LocalBroadcastManager.getInstance(this).unregisterReceiver(mGattUpdateReceiver);
}
In method bindService you need to pass a ServiceConnection that manage Service Lifecycle.
// Code to manage Service lifecycle.
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService = ((BleService.LocalBinder) service).getService();
isConnected = (mBluetoothLeService.getConnectionState() != BleService.STATE_CONNECTED)
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
In Service you need to declare Binder.
private final IBinder mBinder = new LocalBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class LocalBinder extends Binder {
public BleService getService() {
return BleService.this;
}
}
public int getConnectionState() {
return mConnectionState;
}
So now, after binding to BleService, you can get a connection state.
I am developing a an android app that uses service discovery over wifi direct,based on the provided google sample code, the problem is i can't get a fixed value of the advertised TXT record even though i'm using a final hashmap to store the value, the Hashmap is modified every time the onDnsSdTxtRecordAvailable callback is called, even though i'm using a final hashmap declared globally to store the first value, it gets replaced by null. here is the code i'm using. thanks
private WifiP2pManager manager;
private final IntentFilter intentFilter = new IntentFilter();
private Channel channel;
private BroadcastReceiver receiver = null;
private WifiP2pDnsSdServiceRequest serviceRequest;
private TextView statusTxtView;
private TextView services;
private Button register;
private Button broadcast;
private LocationManager locationManager;
final HashMap<String, String> buddies = new HashMap<String, String>();
private TextView locationTxt;
public String value1;
private Button loc;
private final String name = new String();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
statusTxtView = (TextView) findViewById(R.id.status);
services = (TextView) findViewById(R.id.services);
register = (Button) findViewById(R.id.discover);
broadcast = (Button) findViewById(R.id.bd);
locationTxt = (TextView)findViewById(R.id.location);
loc = (Button)findViewById(R.id.loc);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter
.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter
.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel = manager.initialize(this, getMainLooper(), null);
startRegistrationAndDiscovery();
register.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startRegistrationAndDiscovery();
}
});
broadcast.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
discoverService();
}
});
loc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
doIt();
}
});
}
#Override
public void onResume() {
super.onResume();
receiver = new MyReceiver(manager, channel, this);
registerReceiver(receiver, intentFilter);
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
public void appendStatus(String status) {
String current = statusTxtView.getText().toString();
statusTxtView.setText(current + "\n" + status);
}
//service discvery handllng methods
private void startRegistrationAndDiscovery() {
Map<String, String> record = new HashMap<String, String>();
record.put(TXTRECORD_PROP_AVAILABLE, "visible");
WifiP2pDnsSdServiceInfo service = WifiP2pDnsSdServiceInfo.newInstance(
SERVICE_INSTANCE, SERVICE_REG_TYPE, record);
manager.addLocalService(channel, service, new ActionListener() {
#Override
public void onSuccess() {
appendStatus("Added Local Service");
}
#Override
public void onFailure(int error) {
appendStatus("Failed to add a service");
}
});
discoverService();
}
private void discoverService() {
/*
* Register listeners for DNS-SD services. These are callbacks invoked
* by the system when a service is actually discovered.
*/
manager.setDnsSdResponseListeners(channel,
new DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName,
String registrationType, WifiP2pDevice srcDevice) {
// A service has been discovered. Is this our app?
if (instanceName.equalsIgnoreCase(SERVICE_INSTANCE)) {
// update the UI and add the item the discovered
// device.
/* WiFiP2pService service = new WiFiP2pService();
service.device = srcDevice;
service.instanceName = instanceName;
service.serviceRegistrationType = registrationType;*/
//put data to textview here
services.setText(srcDevice.status+" Instance name " + instanceName + " type " + registrationType);
Log.d(TAG, "onBonjourServiceAvailable "
+ instanceName);
Http_client http_client = new Http_client(SERVICE_INSTANCE);
appendStatus("data sent to server successfully");
}
}
}, new DnsSdTxtRecordListener() {
/**
* A new TXT record is available. Pick up the advertised
* buddy name.
*/
#Override
public void onDnsSdTxtRecordAvailable(String fullDomainName, Map<String, String> record,WifiP2pDevice device) {
Log.d(TAG, device.deviceName + " is " + record.get(TXTRECORD_PROP_AVAILABLE));
buddies.put("mm",record.get(TXTRECORD_PROP_AVAILABLE));
Toast.makeText(getBaseContext(),record.get(TXTRECORD_PROP_AVAILABLE),Toast.LENGTH_LONG).show();
//
}
});
// After attaching listeners, create a service request and initiate
// discovery.
serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
manager.addServiceRequest(channel, serviceRequest,
new ActionListener() {
#Override
public void onSuccess() {
appendStatus("Added service discovery request");
}
#Override
public void onFailure(int arg0) {
appendStatus("Failed adding service discovery request");
}
});
manager.discoverServices(channel, new ActionListener() {
#Override
public void onSuccess() {
appendStatus("Service discovery initiated");
}
#Override
public void onFailure(int arg0) {
appendStatus("Service discovery failed");
}
});
}
public void doIt(){
buddies.put("mm","value1");
Toast.makeText(getBaseContext(),buddies.get("mm"),Toast.LENGTH_LONG).show();
buddies.put("mm","value2");
Toast.makeText(getBaseContext(),buddies.get("mm"),Toast.LENGTH_LONG).show();
}
A final variable will not help you, as I have commented. Based on your question, what you need to do is to always check if the value is set in your hashmap, before saving the new returned variable. Something like
if (!buddies.containKey("mm"))
buddies.put("mm", .....)