Socket closing during lifecycle changes - android

I'm trying to keep a socket open during lifecycle changes in a headless fragment with setRetainInstance(true); in onCreate. However, when my app comes back the following exception occurs.
E/Client: Receiving thread loop error
java.net.SocketException: Socket closed
at libcore.io.Posix.recvfromBytes(Native Method)
at libcore.io.Posix.recvfrom(Posix.java:189)
at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:250)
at libcore.io.IoBridge.recvfrom(IoBridge.java:549)
at java.net.PlainSocketImpl.read(PlainSocketImpl.java:481)
at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:37)
at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:237)
at java.io.InputStreamReader.read(InputStreamReader.java:233)
at java.io.BufferedReader.fillBuf(BufferedReader.java:145)
at java.io.BufferedReader.readLine(BufferedReader.java:397)
at com.gm.popper_6.ConnectionFragment$Client$ReceivingThread.run(ConnectionFragment.java:183)
at java.lang.Thread.run(Thread.java:818)
Here's the code for the fragment
public class ConnectionFragment extends Fragment {
private InetAddress mGoAddress;
private int mGoPort;
private Client mClient;
private static final String TAG = "Connection";
private Server mServer;
private Socket mSocket;
private ConnectionFragmentListener listener;
private String mMessage;
public static ConnectionFragment newInstance(InetAddress address, int port){
Bundle bundle = new Bundle();
bundle.putSerializable("GoAddress", address);
bundle.putInt("GoPort", port);
ConnectionFragment fragment = new ConnectionFragment();
fragment.setArguments(bundle);
return fragment;
}
public interface ConnectionFragmentListener{
void onMessageRcvd(String message);
}
public void setConnectionFragmentListener(ConnectionFragmentListener listener){
this.listener = listener;
}
private void readBundle(Bundle bundle){
if (bundle != null){
mGoAddress = (InetAddress)bundle.getSerializable("GoAddress");
mGoPort = bundle.getInt("GoPort");
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
readBundle(getArguments());
mGoAddress = (InetAddress) getArguments().getSerializable("GoAddress");
mGoPort = getArguments().getInt("GoPort");
mServer = new Server();
}
#Override
public void onStart() {
super.onStart();
}
// THE SERVER CLASS
private class Server{ //DECLARATION
ServerSocket mServerSocket = null;
Thread mThread = null;
public Server(){ //CONSTRUCTOR
mThread = new Thread(new ServerThread());
mThread.start();
}
public void tearDown(){
mThread.interrupt();
try {
mServerSocket.close();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "Error closing server socket");
}
}
class ServerThread implements Runnable{
#Override
public void run() {
//REMOVE OR COMMENT OUT FOR FINAL
//android.os.Debug.waitForDebugger();
try {
mServerSocket = new ServerSocket(mGoPort, 50, mGoAddress);
} catch (IOException e) {
e.printStackTrace();
}
while (!Thread.currentThread().isInterrupted()){
try {
mSocket = mServerSocket.accept();
Log.d(TAG, "Connected");
if (mClient == null){
mClient = new Client();
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
}
}
//THE CLIENT CLASS
private class Client { //DECLARATION
private final String CLIENT_TAG = "Client";
private Thread mSendThread;
private Thread mRecThread;
public Client() { //CONSTRUCTOR
Log.d(CLIENT_TAG, "Creating Client");
mSendThread = new Thread(new SendingThread());
mSendThread.start();
}
class SendingThread implements Runnable { //an inner class of Client
BlockingQueue<String> mMessageQueue;
private int QUEUE_CAPACITY = 10;
public SendingThread() {
mMessageQueue = new ArrayBlockingQueue<String>(QUEUE_CAPACITY);
}
#Override
public void run() {
mRecThread = new Thread(new ReceivingThread());
mRecThread.start();
while (true){
try {
String msg = mMessageQueue.take();
sendMessage(msg);
} catch (InterruptedException e) {
Log.d(CLIENT_TAG, "Sending loop interrupted, exiting");
}
}
}
} //closes SendingThread, an inner class of Client
class ReceivingThread implements Runnable{ //an inner class of Client
#Override
public void run() {
BufferedReader input;
try {
//android.os.Debug.waitForDebugger();
input = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
while (!Thread.currentThread().isInterrupted()){
String messageStr = null;
messageStr = input.readLine(); //Line 183
if (messageStr!= null){
Log.d(CLIENT_TAG, "Read from the stream: " + messageStr);
mMessage = messageStr;
updateMessages(false);
}
else{
Log.d(CLIENT_TAG, "The null!!!");
}
}
input.close();
} catch (IOException e) {
Log.e(CLIENT_TAG, "Receiving thread loop error", e);
e.printStackTrace();
}
} //closes run method
} //closes ReceivingThread, an inner class of Client
public void tearDown(){ //a method of Client
try {
getSocket().close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMessage(String msg){ //a method of Client
try {
Socket socket = getSocket(); //should return mSocket
if (socket == null) {
Log.d(CLIENT_TAG, "Socket is null");
} else if (socket.getOutputStream() == null) {
Log.d(CLIENT_TAG, "Socket output stream in null");
}
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(getSocket().getOutputStream())), true);
out.println(msg);
out.flush();
mMessage = msg;
updateMessages(true);
} catch (UnknownHostException e){
Log.d(CLIENT_TAG, "Unkown host", e);
} catch (IOException e) {
Log.d(CLIENT_TAG, "I/O exception", e);
} catch (Exception e){
Log.d(CLIENT_TAG, "Error 3", e);
}
Log.d(CLIENT_TAG, "Message sent: " + msg);
} //closes sendMessage, a method of the inner Client class
} //closes Client class, an inner class of Connection
private Socket getSocket() {
return mSocket;
}
public synchronized void updateMessages(boolean local){
Log.i(TAG, "Updating message: " + mMessage);
if (local){
mMessage = "me: " + mMessage;
}
else{
mMessage = "them: " + mMessage;
}
if (listener!= null){
listener.onMessageRcvd(mMessage);
}
} //closes updateMessages
public void sendMessage(String msg){ //CALL FROM MAIN ACTIVITY
if(mClient != null){ //TO SEND A STRING MESSAGE
mClient.sendMessage(msg);
}
}
public void tearDown(){
mServer.tearDown();
mClient.tearDown();
}
#Override
public void onDestroy() {
tearDown();
super.onDestroy();
}
} //closes class declaration
And here's the main activity
public class MainActivity extends Activity implements ChannelListener, DeviceActionListener,
ConnectionInfoListener, ConnectionFragment.ConnectionFragmentListener{
//CLASS DECLARATIONS
public static final String TAG = "Popper";
private WifiP2pManager manager;
private Boolean isWifiP2pEnabled = false;
ArrayList<Target> mTargets = new ArrayList<Target>(0);
Target mTarget;
TextView rcvd;
TextView ip;
EditText mssg;
String goAddress = "";
InetAddress goInetAddress;
int prefixedPort;
//declare and initialize an intent filter
private final IntentFilter intentFilter = new IntentFilter();
//private final IntentFilter serverFilter = new IntentFilter();
private Channel channel;
private BroadcastReceiver receiver = null;
private ConnectionInfoListener infoListener;
private Intent serverServiceIntent;
ConnectionFragment mConnection;
//????
public void setIsWifiP2pEnabled(boolean isWifiP2pEnabled) {
this.isWifiP2pEnabled = isWifiP2pEnabled;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//register app w/p2p framework with call to initialize
//channel is my apps connection to the p2p framework
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel = manager.initialize(this, getMainLooper(), null);
receiver = new P2pReceiver(manager, channel, this);
rcvd = (TextView)findViewById(R.id.rcvd);
rcvd.setMovementMethod(new ScrollingMovementMethod());
//initialize filter and setup to listen for the following broadcast intents
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);
Resources res = getResources();
prefixedPort = res.getInteger(R.integer.GOport);
}
#Override
public void onMessageRcvd(String message) {
addLine(message);
}
#Override
protected void onResume() {
super.onResume();
receiver = new P2pReceiver(manager, channel, this);
registerReceiver(receiver, intentFilter);
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.action_items, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.atn_direct_discover:
if (!isWifiP2pEnabled) {
NotificationToast.showToast(MainActivity.this, "Enable P2P!!!");
return true;
}
final TargetListFragment fragment = (TargetListFragment) getFragmentManager()
.findFragmentById(R.id.frag_list);
fragment.onInitiateDiscovery();
manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
NotificationToast.showToast(MainActivity.this, "Discovery initiated");
}
#Override
public void onFailure(int reason) {
NotificationToast.showToast(MainActivity.this, "Discovery failed");
}
});
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override //this is associated with ChannelListener
public void onChannelDisconnected() { //removal causes error.
}
#Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
goAddress = info.groupOwnerAddress.getHostAddress(); //this returns a string rep of add.
goInetAddress = info.groupOwnerAddress; //this returns actual inet add.
ip = (TextView) findViewById(R.id.ip);
mssg = (EditText) findViewById(R.id.mssg);
ip.setText(goAddress + ":" + "8080"); //display GO address and IP
startConnectionFragment();
}
//this override method is triggered by TargetListFragment's DeviceActionListener
#Override
public void connect(WifiP2pConfig config) {
manager.connect(channel, config, new ActionListener() {
#Override
public void onSuccess() {
//maybe use this to gray out and disable the listview object that connected
}
#Override
public void onFailure(int reason) {
}
});}
public void startConnectionFragment(){
mConnection = ConnectionFragment.newInstance(goInetAddress, prefixedPort);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(mConnection, "TAG_1");
ft.commit();
mConnection.setConnectionFragmentListener(this);
}
public void addLine(String line){
final String msg = line;
runOnUiThread(new Runnable(){
#Override
public void run() {
rcvd.append("\n" + msg);
}
});
}
#Override
public void onTargetListClick(Target target) {
mTarget = target;
}
public void stopServer() {
if(serverServiceIntent != null)
{
stopService(serverServiceIntent);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if (mConnection != null){
//mConnection.tearDown();
}
stopServer();
}
public void SendMessage(View v){
EditText txt = (EditText) this.findViewById(R.id.mssg);
String str = txt.getText().toString();
mConnection.sendMessage(str);
txt.getText().clear();
}
}
Could this have something to do with detaching when the app goes on pause or stop and not re-attaching when it comes back to life? Are there other things I should be considering?
Ultimately the app needs to keep communication open to about 5 or 6 devices over p2p. if there is a better strategy I'm open to suggestions. Thanks.
Update - So I've confirmed that both the onDestroy and onDetach methods of the fragment are firing when the main activity goes onStop. Since I have a method to close the sockets on death of the fragment they are getting closed. The big question now is how to keep the fragment alive?

You should maybe create a helper class that will open/close sockets on behalf of other classes, such as that fragment, that helper class won't be subjected to any life cycle events, and can be kept running as long as the Application process is alive

Related

bluetooth as service and send/receive from it

I'm trying to recieve/send data to arduino board using bluetooth, and I can connect to board from one activity. I know that I can make my other activities connect with bluetooth using service but I don't know how to make bluetooth as service. and i don't know how to send and recieve from it.
my Paired Devices code:
public class BTConnect extends AppCompatActivity {
private static final String TAG = "BTConnect";
ListView IdLista;
public static String EXTRA_DEVICE_ADDRESS = "device_address";
private BluetoothAdapter mBtAdapter;
private ArrayAdapter<String> mPairedDevicesArrayAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_btconnect);
}
#Override
public void onResume()
{
super.onResume();
//---------------------------------
VerificarEstadoBT();
//
mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.btconnect_nombre);
IdLista = (ListView)findViewById(R.id.Id2);
IdLista.setAdapter(mPairedDevicesArrayAdapter);
IdLista.setOnItemClickListener(mDeviceClickListener);
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
if (pairedDevices.size() > 0)
{
for (BluetoothDevice device: pairedDevices) {
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
}
}
private AdapterView.OnItemClickListener mDeviceClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView av, View v, int arg2, long arg3) {
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
Intent i = new Intent(BTConnect.this, device.class);
i.putExtra(EXTRA_DEVICE_ADDRESS, address);
startActivity(i);
}
};
private void VerificarEstadoBT() {
mBtAdapter= BluetoothAdapter.getDefaultAdapter();
if(mBtAdapter==null) {
Toast.makeText(getBaseContext(), "the device can't connect to BT", Toast.LENGTH_SHORT).show();
} else {
if (mBtAdapter.isEnabled()) {
Log.d(TAG, "...Bluetooth Activation...");
} else {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
}
}
}}
And my first activity 'device' :
public class device extends AppCompatActivity {
Button IdEncender, IdApagar,IdDesconectar,IdReset;
ArrayList<String> addArray = new ArrayList<String>();
ListView show;
//-------------------------------------------
Handler bluetoothIn;
final int handlerState = 0;
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket = null;
private StringBuilder DataStringIN = new StringBuilder();
private ConnectedThread MyConexionBT;
// Identificador unico de servicio - SPP UUID
private static final UUID BTMODULEUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// String para la direccion MAC
private static String address = null;
//-------------------------------------------
#SuppressLint("HandlerLeak")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_device);
IdEncender = (Button) findViewById(R.id.IdEncender);
IdApagar = (Button) findViewById(R.id.IdApagar);
IdDesconectar = (Button) findViewById(R.id.IdDisconectar);
show = (ListView) findViewById(R.id.LIST1) ;
IdReset=(Button)findViewById(R.id.IdReset);
bluetoothIn = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == handlerState) {
String readMessage = (String) msg.obj;
DataStringIN.append(readMessage);
int endOfLineIndex = DataStringIN.indexOf("#");
if (endOfLineIndex > 0) {
String dataInPrint = DataStringIN.substring(0, endOfLineIndex);
String newline = "\r\n";
DataStringIN.delete(0, DataStringIN.length());
//--List adapter--//
addArray.add(dataInPrint);
ArrayAdapter<String> adapter =new ArrayAdapter<String>(device.this, android.R.layout.simple_list_item_1, addArray);
show.setAdapter(adapter);
}
}
};
btAdapter = BluetoothAdapter.getDefaultAdapter(); // get Bluetooth adapter
VerificarEstadoBT();
IdEncender.setOnClickListener(new View.OnClickListener() {
public void onClick(View v)
{
MyConexionBT.write("1");
}
});
IdApagar.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
MyConexionBT.write("0");
}
});
IdDesconectar.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (btSocket!=null)
{
try {btSocket.close();}
catch (IOException e)
{ Toast.makeText(getBaseContext(), "Error", Toast.LENGTH_SHORT).show();;}
}
finish();
}
});
configurebutton();
}
private void configurebutton() {
Button startbutton = (Button)findViewById(R.id.Start);
startbutton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(device.this,chart.class));
}
});
}
private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException
{
return device.createRfcommSocketToServiceRecord(BTMODULEUUID);
}
#Override
public void onResume()
{
super.onResume();
Intent intent = getIntent();
address = intent.getStringExtra(BTConnect.EXTRA_DEVICE_ADDRESS);
BluetoothDevice device = btAdapter.getRemoteDevice(address);
try
{
btSocket = createBluetoothSocket(device);
} catch (IOException e) {
Toast.makeText(getBaseContext(), "fail", Toast.LENGTH_LONG).show();
}
try
{
btSocket.connect();
} catch (IOException e) {
try {
btSocket.close();
} catch (IOException e2) {}
}
MyConexionBT = new ConnectedThread(btSocket);
MyConexionBT.start();
}
#Override
public void onPause()
{
super.onPause();
try
{
btSocket.close();
} catch (IOException e2) {}
}
private void VerificarEstadoBT() {
if(btAdapter==null) {
Toast.makeText(getBaseContext(), "error in bluetooth connection", Toast.LENGTH_LONG).show();
} else {
if (btAdapter.isEnabled()) {
} else {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
}
}
}
public void savefile(String file, String text){
try {
FileOutputStream fos = openFileOutput(file, Context.MODE_APPEND);
fos.write(text.getBytes());
fos.close();
Toast.makeText(device.this, "saved!", Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(device.this,"error",Toast.LENGTH_LONG).show();
}
}
//Crea la clase que permite crear el evento de conexion
private class ConnectedThread extends Thread
{
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket)
{
InputStream tmpIn = null;
OutputStream tmpOut = null;
try
{
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run()
{
byte[] buffer = new byte[256];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
String readMessage = new String(buffer, 0, bytes);
bluetoothIn.obtainMessage(handlerState, bytes, -1, readMessage).sendToTarget();
} catch (IOException e) {
break;
}
}
}
public void write(String input)
{
try {
mmOutStream.write(input.getBytes());
}
catch (IOException e)
{
Toast.makeText(getBaseContext(), "fail to connect", Toast.LENGTH_LONG).show();
finish();
}
}
}
}
If shortly move your connection/message_exchange logic to Thread/Runnable and start it from Service. You can exchange data between Service and Activity/Activities with BroadcastReceivers or Messenger. I also recommend you to use Bluetooth lib:
implementation 'me.aflak.libraries:bluetooth:1.3.4' this one already have inside thread so it is become easy to embed in your service.
Example code of service which use this lib and Messenger:
private ArrayList<Messenger> mClients = new ArrayList<>();
final private Messenger inComingMessenger = new Messenger(mIncomingHandler);
#SuppressLint("HandlerLeak")
final Handler mIncomingHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Constants.MSG_REGISTER_CLIENT:
mClients.add(msg.replyTo);
Log.d(TAG, "handleMessage: new client connected. Total: " + mClients.size());
break;
case Constants.MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
Log.d(TAG, "handleMessage: client disconnected. Total: " + mClients.size());
break;
case Constants.MSG_YOUR_MESSAGE_TYPE:
String val = (String) msg.obj;
// stuff to do
break;
}
}
};
/**
* Send message to connected activities
*/
public void sendMessageToClients(int msgSignal, Object obj) {
if (mClients.size() == 0)
return;
sendMessage(mClients.get(0), Message.obtain(null, msgSignal, obj));
for (int i = 1; i < mClients.size(); i++) {
if (mClients.get(i) == null)
continue;
sendMessage(mClients.get(i), Message.obtain(null, msgSignal, obj));
}
}
/**
* Send message to binded activity
*/
private void sendMessage(Messenger msgr, Message msg) {
try {
msgr.send((msg));
} catch (RemoteException e) {
Log.e(TAG, "can't send message", e);
e.printStackTrace();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Log.d(TAG, "onStartCommand");
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return inComingMessenger.getBinder();
}
#Override
public void onCreate() {
super.onCreate();
bleDevices = new ArrayList<>();
if(bluetooth == null) {
bluetooth = new Bluetooth(this);
bluetooth.setBluetoothCallback(new BluetoothCallback() {
#Override
public void onBluetoothTurningOn() {}
#Override
public void onBluetoothOn() {}
#Override
public void onBluetoothTurningOff() {
bluetooth = null;
}
#Override
public void onBluetoothOff() { }
#Override
public void onUserDeniedActivation() {
// when using bluetooth.showEnableDialog()
// you will also have to call bluetooth.onActivityResult()
}
});
bluetooth.setDiscoveryCallback(new DiscoveryCallback() {
#Override public void onDiscoveryStarted() {
}
#Override public void onDiscoveryFinished() {
bleDevices.clear();
}
#Override public void onDeviceFound(BluetoothDevice device) {
if(bleDevices.indexOf(device)<0) {
bleDevices.add(device);
Log.d(TAG, "Found new device while scanning: "+device.getAddress());
sendMessageToClients(Constants.MSG_BLE_DEVICE_FOUND, device);
}
}
#Override public void onDevicePaired(BluetoothDevice device) {}
#Override public void onDeviceUnpaired(BluetoothDevice device) {}
#Override public void onError(String message) {
Log.e(TAG, "DiscoveryCallback onError "+message);
}
});
bluetooth.setDeviceCallback(new DeviceCallback() {
#Override public void onDeviceConnected(BluetoothDevice device) { }
#Override public void onDeviceDisconnected(BluetoothDevice device, String message) { }
#Override public void onMessage(String message) {
// Handle your message
yourHandleFunction(message.replaceAll(" ",""));
Log.d(TAG, message);
}
#Override public void onError(String message) {
Log.e(TAG, "DeviceCallback onError "+message);
}
#Override public void onConnectError(BluetoothDevice device, String message) { }
});
bluetooth.onStart();
}
connectToSavedDevice();
}
}
private void connectToSavedDevice() {
Log.d(TAG, "connectToSavedDevice state="+getState());
if(getState() != STATE_DISCONNECTED) return;
SharedPreferences pref = getSharedPreferences(App.TAG, 0);
String address = pref.getString(Constants.PREF_AUTO_CONNECT_TO_ADDRESS, null);
if(address == null) {
Log.d(TAG, "saved address==null start scan for devices");
scanDevices();
return;
}
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
if(device!=null) {
Log.d(TAG, "device found try to connect/bound, connect to Arduino");
bluetooth.connectToAddress(address,false);
}
}
In activity implement ServiceConnection interface:
protected synchronized void unbindService() {
if (!isBound()) {
return;
}
// lock object (prevents access to service while disconnecting)
synchronized (outComingMessenger) {
sendMessageToService(Message.obtain(null, Constants.MSG_UNREGISTER_CLIENT));
unbindService(this);
outComingMessenger = null;
}
}
protected void bindService() {
bindService(mServiceIntent, this, BIND_AUTO_CREATE);
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
outComingMessenger = new Messenger(service);
final Message msg = Message.obtain(null, Constants.MSG_REGISTER_CLIENT);
msg.replyTo = inComingMessenger;
msg.obj = getClass().getSimpleName();
sendMessageToService(msg);
sendMessageToService(Constants.MSG_CHECK_IS_CONNECTION_READY);
}
#Override
public void onServiceDisconnected(ComponentName name) {
outComingMessenger = null;
bindService();
}
/**
* Send message to service
*/
protected void sendMessageToService(Message msg) {
if (!isBound()) {
return;
}
try {
msg.replyTo = inComingMessenger;
outComingMessenger.send(msg);
} catch (RemoteException e) {
}
}
/**
* Send simple message to connected service
* #param messageId
*/
protected void sendMessageToService(int messageId) {
sendMessageToService(Message.obtain(null, messageId));
}
/**
* Send simple message to connected service
* #param messageId
*/
protected void sendMessageToService(int messageId, Object obj) {
sendMessageToService(Message.obtain(null, messageId, obj));
}
/**
* Service is connected?
*/
protected final boolean isBound() {
return outComingMessenger != null;
}
#SuppressLint("HandlerLeak")
private final Handler mIncomingHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case Constants.MSG_YOUR_MESSAGE:
int res = (int) msg.obj;
break;
case Constants.MSG_CONNECTION_READY:
isReady = (boolean) msg.obj;
if(isReady) {
// show toast or what you want to do with the UI
} else {
// do something else
}
break;
case Constants.MSG_BLE_DEVICE_FOUND:
BluetoothDevice device = (BluetoothDevice)msg.obj;
SharedPreferences pref = getSharedPreferences(App.TAG, 0);
String deviceAddress = pref.getString(Constants.PREF_AUTO_CONNECT_TO_ADDRESS, null);
break;
}
}
};
final private Messenger inComingMessenger = new Messenger(mIncomingHandler);

NullPointerException in `BluetoothAdapter` when startService() is invoked [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
Error I'm getting null point exception in Bluetooth when I'm starting a service.
LiveFragment.class
public class LiveFragment extends Fragment {
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;
private static final int REQUEST_ENABLE_BT = 3;
private BluetoothAdapter mBluetoothAdapter =null;
public BluetoothChatService mChatService = null;
private PowerManager.WakeLock wakeLock = null;
private PowerManager powerManager = null;
private String mConnectedDeviceName = null;
private boolean isServiceBound;
private boolean preRequisites = true;
private SharedPreferences prefs;
private BroadcastReceiver broadcastReceiver;
private Context c;
private AbstractGatewayService ab;
protected ImageView blue_onoffBut, gps_Button, obd_inidca, ss_button, bluetooth_indicator, gps_indicator,obd_connectButt;
protected TextView ss_Status,btStatusTextView,obdStatusTextView,gpsStatusTextView;
private LinearLayout vv;
protected BluetoothSocket sock = null;
public LiveFragment() {
// Required empty public constructor
}
private final Runnable mQueueCommands = new Runnable() {
public void run() {
Log.d(TAG, "Runnable mQueueCommands ()");
if (ab != null && ab.isRunning() && ab.queueEmpty()) {
queueCommands();
}
// run again in period defined in preferences
new Handler().postDelayed(mQueueCommands, 4000);
}
};
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View view = inflater.inflate(R.layout.fragment_live, container, false);
blue_onoffBut = (ImageView) view.findViewById(R.id.blutooth_butoon);
gps_Button = (ImageView) view.findViewById(R.id.gps_button);
obd_inidca = (ImageView) view.findViewById(R.id.obd_Indicator);
ss_button = (ImageView) view.findViewById(ssButton);
gps_indicator = (ImageView) view.findViewById(R.id.gps_indicator);
bluetooth_indicator = (ImageView) view.findViewById(R.id.bluetooth_indicator);
obd_connectButt = (ImageView) view.findViewById(R.id.Obd_Connect_Button);
ss_Status = (TextView) view.findViewById(R.id.statusTx);
btStatusTextView = (TextView) view.findViewById(R.id.blue);
obdStatusTextView = (TextView) view.findViewById(R.id.obd);
gpsStatusTextView = (TextView) view.findViewById(R.id.gps);
vv = (LinearLayout) view.findViewById(R.id.fragment_live_layout);
ss_Status.setTextColor(getResources().getColor(R.color.colorGreen));
if (mBluetoothAdapter.isEnabled()) {
bluetooth_indicator.setImageResource(R.drawable.green_circle);
} else {
bluetooth_indicator.setImageResource(R.drawable.red_circle);
}
gps_Button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final LocationManager manager = (LocationManager) getActivity().getSystemService( Context.LOCATION_SERVICE );
if ( !manager.isProviderEnabled( LocationManager.GPS_PROVIDER ) ) {
buildAlertMessageNoGps();
}
else {
showToast("Already GPS is ON");
}
}
});
blue_onoffBut.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.enable();
showToast("Bluetooth Turned ON"+"\n"+"Connect Your OBD now");
bluetooth_indicator.setImageResource(R.drawable.green_circle);
mChatService = new BluetoothChatService(getActivity(), mHandler);
if (mChatService != null) {
// Only if the state is STATE_NONE, do we know that we haven't started already
if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
// Start the Bluetooth chat services
mChatService.start();
}
}
} else if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
mBluetoothAdapter.cancelDiscovery();
obd_inidca.setImageResource(R.drawable.red_circle);
showToast("Bluetooth Turned OFF");
bluetooth_indicator.setImageResource(R.drawable.red_circle);
}
}
});
ss_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mBluetoothAdapter.isEnabled() && mChatService.getState() == BluetoothChatService.STATE_CONNECTED) {
startLiveData();
} else if (!mBluetoothAdapter.isEnabled()) {
showToast("Turn ON Bluetooth to Continue");
}
else if (!(mChatService.getState() == BluetoothChatService.STATE_CONNECTED)){
showToast("Select your OBD to Start ");
}
}
});
obd_connectButt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mBluetoothAdapter.isEnabled()) {
Intent serverIntent = new Intent(getActivity(), DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);
}
else if (!mBluetoothAdapter.isEnabled()){
showToast("Turn ON Bluetooth to Connect OBD");
}
}
});
return view;
}
private ServiceConnection serviceConn = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder binder) {
Log.d(TAG, className.toString() + " service is bound");
isServiceBound = true;
ab = ((AbstractGatewayService.AbstractGatewayServiceBinder) binder).getService();
ab.setContext(getActivity());
Log.d(TAG, "Starting live data");
try {
ab.startService();
if (preRequisites)
btStatusTextView.setText("Connected");
} catch (IOException ioe) {
Log.e(TAG, "Failure Starting live data");
btStatusTextView.setText("Connection failed");
doUnbindService();
}
}
#Override
protected Object clone() throws CloneNotSupportedException {
Log.d(TAG, "CloneNotSupportedException ");
return super.clone();
}
#Override
public void onServiceDisconnected(ComponentName className) {
Log.d(TAG, className.toString() + " service is unbound");
isServiceBound = false;
}
};
public static String LookUpCommand(String txt) {
Log.d(TAG, "LookUpCommand() ");
for (AvailableCommandNames item : AvailableCommandNames.values()) {
if (item.getValue().equals(txt)) return item.name();
}
return txt;
}
public void updateTextView(final TextView view, final String txt) {
Log.d(TAG, "updateTextView() ");
new Handler().post(new Runnable() {
public void run() {
view.setText(txt);
}
});
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void stateUpdate(ObdCommandJob job) {
final String cmdName = job.getCommand().getName();
String cmdResult = "";
final String cmdID = LookUpCommand(cmdName);
Log.d(TAG, "stateUpdate() ");
if (job.getState().equals(ObdCommandJob.ObdCommandJobState.EXECUTION_ERROR)) {
cmdResult = job.getCommand().getResult();
if (cmdResult != null && isServiceBound) {
obdStatusTextView.setText(cmdResult.toLowerCase());
}
} else if (job.getState().equals(ObdCommandJob.ObdCommandJobState.BROKEN_PIPE)) {
if (isServiceBound)
stopLiveData();
} else if (job.getState().equals(ObdCommandJob.ObdCommandJobState.NOT_SUPPORTED)) {
cmdResult = "NA";
} else {
cmdResult = job.getCommand().getFormattedResult();
if (isServiceBound)
obdStatusTextView.setText("Receiving data...");
}
cmdResult.replace("NODATA", "0");
if (vv.findViewWithTag(cmdID) != null) {
TextView existingTV = (TextView) vv.findViewWithTag(cmdID);
existingTV.setText(cmdResult);
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
// Get local Bluetooth adapter
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// If the adapter is null, then Bluetooth is not supported
if (mBluetoothAdapter == null) {
FragmentActivity activity = getActivity();
Toast.makeText(activity, "No Bluetooth Feature in Device", Toast.LENGTH_LONG).show();
activity.finish();
}
}
#Override
public void onStart() {
super.onStart();
final LocationManager manager = (LocationManager) getActivity().getSystemService( Context.LOCATION_SERVICE );
if ( !manager.isProviderEnabled( LocationManager.GPS_PROVIDER ) ) {
gps_indicator.setImageResource(R.drawable.red_circle);
}
if(mBluetoothAdapter.isEnabled()){
mBluetoothAdapter.disable();
bluetooth_indicator.setImageResource(R.drawable.red_circle);
}
}
#Override
public void onResume() {
super.onResume();
powerManager = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "ObdReader");
final LocationManager manager = (LocationManager) getActivity().getSystemService( Context.LOCATION_SERVICE );
if ( manager.isProviderEnabled( LocationManager.GPS_PROVIDER ) ) {
gps_indicator.setImageResource(R.drawable.green_circle);
} else {
gps_indicator.setImageResource(R.drawable.red_circle);
}
EventBus.getDefault().register(this);
if(mBluetoothAdapter.isEnabled()) {
if (mChatService != null) {
// Only if the state is STATE_NONE, do we know that we haven't started already
if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
// Start the Bluetooth chat services
mChatService.start();
}
}
}
}
#Override
public void onPause() {
super.onPause();
Log.d(TAG, "Pausing..");
releaseWakeLockIfHeld();
EventBus.getDefault().unregister(this);
}
private void showToast(String message) {
final Toast toast = Toast.makeText(getContext(), message, Toast.LENGTH_SHORT);
toast.show();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
toast.cancel();
}
}, 500);
}
#Override
public void onDestroy() {
/* unregisterReceiver(mReceiver);*/
super.onDestroy();
releaseWakeLockIfHeld();
if (mChatService != null) {
mChatService.stop();
}
if (isServiceBound) {
doUnbindService();
}
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
}
showToast("Take Care!");
}
private void startLiveData() {
if (mChatService.getState() == BluetoothChatService.STATE_CONNECTED) {
Log.d(TAG, "Starting live data..");
ss_Status.setText("Stop");
ss_Status.setTextColor(getResources().getColor(R.color.colorRed));
wakeLock.acquire();
ss_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ss_Status.setText("Go Live");
ss_Status.setTextColor(getResources().getColor(R.color.colorGreen));
stopLiveData();
}
});
doBindService();
LocalBroadcastManager.getInstance(getActivity()).registerReceiver((broadcastReceiver), new IntentFilter(OBD_GATEWAY_SERVICE));
new Handler().post(mQueueCommands);
}
}
private void stopLiveData() {
Log.d(TAG, "Stopping live data..");
releaseWakeLockIfHeld();
new Handler().removeCallbacks(mQueueCommands);
ss_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ss_Status.setText("Go Live");
ss_Status.setTextColor(getResources().getColor(R.color.colorGreen));
startLiveData();
}
});
doUnbindService();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(broadcastReceiver);
}
private void queueCommands() {
Log.d(TAG, "LiveFragment queueCommands() ");
if (isServiceBound) {
for (ObdCommand Command : ObdConfig.getCommands()) {
if (prefs.getBoolean(Command.getName(), true))
ab.queueJob(new ObdCommandJob(Command));
}
}
}
private void doBindService() {
if (!isServiceBound) {
Log.d(TAG, "Binding OBD service..");
if (preRequisites) {
btStatusTextView.setText("Connecting.....");
Intent serviceIntent = new Intent(getActivity(),ObdGatewayService.class);
getActivity().bindService(serviceIntent, serviceConn, Context.BIND_AUTO_CREATE);
}
}
}
private void doUnbindService() {
if (isServiceBound) {
if (ab.isRunning()) {
ab.stopService();
if (preRequisites)
btStatusTextView.setText("Ready...");
}
Log.d(TAG, "Unbinding OBD service..");
getActivity().unbindService(serviceConn);
isServiceBound = false;
obdStatusTextView.setText("Disconnected");
}
}
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
FragmentActivity activity = getActivity();
switch (msg.what) {
case Constants.MESSAGE_STATE_CHANGE:
switch (msg.arg1) {
case BluetoothChatService.STATE_CONNECTED:
obd_inidca.setImageResource(R.drawable.green_circle);
break;
case BluetoothChatService.STATE_CONNECTING:
obd_inidca.setImageResource(R.drawable.orange_circle);
break;
case BluetoothChatService.STATE_LISTEN:
case BluetoothChatService.STATE_NONE:
obd_inidca.setImageResource(R.drawable.red_circle);
break;
}
break;
case Constants.MESSAGE_DEVICE_NAME:
// save the connected device's name
mConnectedDeviceName = msg.getData().getString(Constants.DEVICE_NAME);
if (null != activity) {
Toast.makeText(activity, "Connected to "
+ mConnectedDeviceName, Toast.LENGTH_SHORT).show();
obd_inidca.setImageResource(R.drawable.green_circle);
}
break;
case Constants.MESSAGE_TOAST:
if (null != activity) {
Toast.makeText(activity, msg.getData().getString(Constants.TOAST),
Toast.LENGTH_SHORT).show();
}
break;
}
}
};
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CONNECT_DEVICE_SECURE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
try {
connectDevice(data, true);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void connectDevice(Intent data, boolean secure) throws IOException {
// Get the device MAC address
String address = data.getExtras()
.getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
// Get the BluetoothDevice object
BluetoothDevice dev = mBluetoothAdapter.getRemoteDevice(address);
// Attempt to connect to the device
mChatService.connect(dev, secure);
}.
This is ObdGateway service class:
public class ObdGatewayService extends AbstractGatewayService {
private static final String TAG = ObdGatewayService.class.getName();
#Inject
SharedPreferences prefs;
private BluetoothDevice dev = null;
private BluetoothSocket sock = null;
private BluetoothChatService mChatservice = null;
private BluetoothAdapter bluetoothAdapter =null;
public final static String JOB_NAME_STAMP = "Name";
public final static String JOB_STATE_STAMP = "State";
public final static String JOB_RESULT_STAMP = "Result";
public final static String JOB_FORMATED_RESULT_STAMP = "Formated REsult";
public final static String OBD_GATEWAY_SERVICE = "com.samplersoft.saz.Obd.ObdGatewayService";
public void startService() throws IOException {
Log.d(TAG, "Starting service..");
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// get the remote Bluetooth device
if(mChatservice.getState() != BluetoothChatService.STATE_CONNECTED){
Toast.makeText(ctx, "No Bluetooth device selected", Toast.LENGTH_LONG).show();
// log error
Log.e(TAG, "No Bluetooth device has been selected.");
stopService();
throw new IOException();
}
else
{
Log.d(TAG, "Stopping Bluetooth discovery.");
bluetoothAdapter.cancelDiscovery();
try {
startObdConnection();
} catch (Exception e) {
Log.e(
TAG,
"There was an error while establishing connection. -> "
+ e.getMessage()
);
// in case of failure, stop this service.
stopService();
throw new IOException();
}
}
}
private void startObdConnection() throws IOException {
Log.d(TAG, "Starting OBD connection..");
isRunning = true;
if(mChatservice.getState() == BluetoothChatService.STATE_CONNECTED){
// Let's configure the connection.
Log.d(TAG, "Queueing jobs for connection configuration..");
queueJob(new ObdCommandJob(new ObdResetCommand()));
try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
queueJob(new ObdCommandJob(new EchoOffCommand()));
queueJob(new ObdCommandJob(new EchoOffCommand()));
queueJob(new ObdCommandJob(new LineFeedOffCommand()));
queueJob(new ObdCommandJob(new TimeoutCommand(62)));
// Get protocol from preferences
queueJob(new ObdCommandJob(new SelectProtocolCommand(ObdProtocols.valueOf("AUTO"))));
// Job for returning dummy data
queueJob(new ObdCommandJob(new AmbientAirTemperatureCommand()));
queueCounter = 0L;
Log.d(TAG, "Initialization jobs queued.");
}
else {
stopService();
throw new IOException();
}
}
#Override
public void queueJob(ObdCommandJob job) {
// This is a good place to enforce the imperial units option
//job.getCommand().useImperialUnits(prefs.getBoolean(ConfigActivity.IMPERIAL_UNITS_KEY, false));
// Now we can pass it along
super.queueJob(job);
}
protected void executeQueue() throws InterruptedException {
Log.d(TAG, "Executing queue..");
while (!Thread.currentThread().isInterrupted()) {
ObdCommandJob job = null;
try {
job = jobsQueue.take();
// log job
Log.d(TAG, "Taking job[" + job.getId() + "] from queue..");
if (job.getState().equals(ObdCommandJob.ObdCommandJobState.NEW)) {
Log.d(TAG, "Job state is NEW. Run it..");
job.setState(ObdCommandJob.ObdCommandJobState.RUNNING);
if (sock.isConnected()) {
job.getCommand().run(sock.getInputStream(), sock.getOutputStream());
} else {
job.setState(ObdCommandJob.ObdCommandJobState.EXECUTION_ERROR);
Log.e(TAG, "Can't run command on a closed socket.");
}
} else
// log not new job
Log.e(TAG,
"Job state was not new, so it shouldn't be in queue. BUG ALERT!");
} catch (InterruptedException i) {
Thread.currentThread().interrupt();
} catch (UnsupportedCommandException u) {
if (job != null) {
job.setState(ObdCommandJob.ObdCommandJobState.NOT_SUPPORTED);
}
Log.d(TAG, "Command not supported. -> " + u.getMessage());
} catch (IOException io) {
if (job != null) {
if(io.getMessage().contains("Broken pipe"))
job.setState(ObdCommandJob.ObdCommandJobState.BROKEN_PIPE);
else
job.setState(ObdCommandJob.ObdCommandJobState.EXECUTION_ERROR);
}
Log.e(TAG, "IO error. -> " + io.getMessage());
} catch (Exception e) {
if (job != null) {
job.setState(ObdCommandJob.ObdCommandJobState.EXECUTION_ERROR);
}
Log.e(TAG, "Failed to run command. -> " + e.getMessage());
}
ObdCommandJob job2 = job;
if(job2 !=null)
EventBus.getDefault().post(job2);
}
}
public void stopService() {
Log.d(TAG, "Stopping service..");
jobsQueue.clear();
isRunning = false;
if (sock != null)
// close socket
try {
sock.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
// kill service
stopSelf();
}
public boolean isRunning() {
return isRunning;
}
}.
This is Abstract Class where service method gets called from from Livefragment Class from serivceConnection().
public abstract class AbstractGatewayService extends RoboService {
private static final String TAG = AbstractGatewayService.class.getName();
private final IBinder binder = new AbstractGatewayServiceBinder();
protected Context ctx;
protected boolean isRunning = false;
protected Long queueCounter = 0L;
protected BlockingQueue<ObdCommandJob> jobsQueue = new LinkedBlockingQueue<>();
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
executeQueue();
} catch (InterruptedException e) {
t.interrupt();
}
}
});
protected LocalBroadcastManager broadcastManager;
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "Creating service..");
final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
t.start();
Log.d(TAG, "Service created.");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "Destroying service...");
t.interrupt();
broadcastManager = LocalBroadcastManager.getInstance(this);
Log.d(TAG, "Service destroyed.");
}
public boolean isRunning() {
return isRunning;
}
public boolean queueEmpty() {
return jobsQueue.isEmpty();
}
public void queueJob(ObdCommandJob job) {
queueCounter++;
Log.d(TAG, "Adding job[" + queueCounter + "] to queue..");
job.setId(queueCounter);
try {
jobsQueue.put(job);
Log.d(TAG, "Job queued successfully.");
} catch (InterruptedException e) {
job.setState(ObdCommandJob.ObdCommandJobState.QUEUE_ERROR);
Log.e(TAG, "Failed to queue job.");
}
}
public void setContext(Context c) {
ctx = c;
}
abstract protected void executeQueue() throws InterruptedException;
abstract public void startService() throws IOException;
abstract public void stopService();
public class AbstractGatewayServiceBinder extends Binder {
public AbstractGatewayService getService() {
return AbstractGatewayService.this;
}
}
}.
You are getting the exception because in class ObdGatewayService your class member mChatservice is not the same as mChatservice in class LiveFragment
They are just different member variables
mChatservice gets assigned like this in your Fragment
mChatService = new BluetoothChatService(getActivity(), mHandler);
You need to pass this reference to ObdGatewayService 's startService() like this where ever you are instantiating/invoking it:-
ObdGatewayService ogs;
....
ogs.startservice(mChatservice); // This is fragment's member reference
And in ObdGatewayService you have to assign it accordingly:-
public void startService(BluetoothChatService _mChatservice) throws IOException {
Log.d(TAG, "Starting service..");
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mChatservice = _mChatservice //Assignment YOU ARE MISSING THIS
.......
.......
}

TextToSpeech stops working after a few hours

I'm trying to make an app reading a string coming from a socket connection, but after a few hours the app stops talking (without exceptions). I'm sure the app is still running because the server sending the string continues to detect the response echo after sending it.
public class MainActivity extends AppCompatActivity {
TextToSpeech textToSpeech;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textToSpeech = new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if(status != TextToSpeech.ERROR) {
textToSpeech.setLanguage(Locale.ITALY);
}
}
});
Thread socketT = new Thread(new SocketThread());
socketT.start();
}
#Override
public void onDestroy() {
if (textToSpeech != null) {
textToSpeech.stop();
textToSpeech.shutdown();
}
super.onDestroy();
}
private class SocketThread extends Thread {
static final int socketPort = 3333;
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(socketPort);
try {
while(true) {
Socket clientSocket = serverSocket.accept();
try {
new ServerThread(clientSocket);
} catch(IOException e) {
clientSocket.close();
} }
}
catch (IOException e) {
}
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
class ServerThread extends Thread {
private int counter = 0;
private int id = ++counter;
private Socket socket;
private BufferedReader in;
private PrintWriter out;
public ServerThread(Socket s) throws IOException {
socket = s;
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream());
out = new PrintWriter(new BufferedWriter(osw), true);
start();
}
public void run() {
try {
while (true) {
String str = in.readLine();
textToSpeech.speak(str, TextToSpeech.QUEUE_FLUSH, null);
}
} catch (IOException e) {}
try {
socket.close();
} catch(IOException e) {}
}
}
}
}
TextToSpeech instance will be available after connect to system service, not after invoke constructor.
So, your plan need to edit like this:
Call TextToSpeech constructor.
Check your TextToSpeech instance is finish to connect to system service through TextToSpeech.OnInitListener.onInit().
Then, connect to your custom service.
Try this as below:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textToSpeech = new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if(status != TextToSpeech.ERROR) {
int res = textToSpeech.setLanguage(Locale.ITALY);
if (res >= TextToSpeech.LANG_AVAILABLE) {
// TextToSpeech instance is available after connect to system service!
Thread socketT = new Thread(new SocketThread());
socketT.start();
}
}
}
});
// At this time, your TextToSpeech instance may be not available yet.
//Thread socketT = new Thread(new SocketThread());
//socketT.start();
}

Is it possible to pass Chromcast connection info between Activities?

I am developing an app that connects to a Chromecast, everything works fine when I do it from one activity, the problem is, that I want that activity to be fullscreen with no action bar, and no soft buttons. I am achiving that, hiding them when the users connects to the Chromecast, but it would be better if the users connect from the first activity (with action bar) and then goes to the second activity and the magic occurs there. But I can't pass the session between the activities. I have follow this tutorial to make the communication with the chromecast but tried to change a little to make the 2 acitivites communication.
Of course I have tested it and it returns a NullPointerException.
ConnectionFailedListener.java
public class ConnectionFailedListener implements GoogleApiClient.OnConnectionFailedListener {
private String TAG;
private MyConnectionCallbacks myConnectionCB;
public ConnectionFailedListener(String _TAG)
{
this.TAG=_TAG;
}
private void setMyConnectionCallBack(MyConnectionCallbacks _ConnectionCallbacks)
{
this.myConnectionCB = _ConnectionCallbacks;
}
#Override
public void onConnectionFailed(ConnectionResult result)
{
Log.e(TAG, "onConnectionFailed ");
myConnectionCB.teardown();
}
}
Channel.java
public class EventChannel implements Cast.MessageReceivedCallback
{
private Context myContext;
private String TAG;
/**
* #return custom namespace
*/
public EventChannel(Context _context, String _TAG)
{
this.myContext = _context;
this.TAG = _TAG;
}
public String getNamespace()
{
return myContext.getString(R.string.namespace);
}
/*
* Receive message from the receiver app
*/
#Override
public void onMessageReceived(CastDevice castDevice, String namespace,String message)
{
Log.d(TAG, "onMessageReceived: " + message);
}
}
ConnectionCallbacks.java
public class MyConnectionCallbacks implements GoogleApiClient.ConnectionCallbacks
{
private String TAG;
private Context myContext;
public CastDevice mSelectedDevice;
private GoogleApiClient mApiClient;
private boolean mWaitingForReconnect;
private EventChannel mEventChannel;
private String mSessionId;
private boolean mApplicationStarted;
private EventChannel myChannel;
public MyConnectionCallbacks(Context _context, String _TAG)
{
this.myContext=_context;
this.TAG = _TAG;
}
public void setApiClient(GoogleApiClient _newApiClient)
{
this.mApiClient = _newApiClient;
}
#Override
public void onConnected(Bundle connectionHint)
{
Log.d(TAG, "onConnected");
if (mApiClient == null)
{
// We got disconnected while this runnable was pending execution.
return;
}
try
{
if (mWaitingForReconnect)
{
mWaitingForReconnect = false;
// Check if the receiver app is still running
if ((connectionHint != null) && connectionHint.getBoolean(Cast.EXTRA_APP_NO_LONGER_RUNNING))
{
Log.d(TAG, "App is no longer running");
teardown();
}
else
{// Re-create the custom message channel
try
{
Cast.CastApi.setMessageReceivedCallbacks(mApiClient,mEventChannel.getNamespace(),mEventChannel);
}
catch (IOException e)
{
Log.e(TAG, "Exception while creating channel", e);
}
}
}
else
{// Launch the receiver app because is connected
Cast.CastApi.launchApplication(mApiClient,myContext.getString(R.string.app_id), false).setResultCallback(
new ResultCallback<Cast.ApplicationConnectionResult>()
{
#Override
public void onResult(Cast.ApplicationConnectionResult result) {
Status status = result.getStatus();
Log.d(TAG,"ApplicationConnectionResultCallback.onResult: statusCode"+ status.getStatusCode());
if (status.isSuccess())
{
ApplicationMetadata applicationMetadata = result.getApplicationMetadata();
mSessionId = result.getSessionId();
String applicationStatus = result.getApplicationStatus();
boolean wasLaunched = result.getWasLaunched();
Log.d(TAG,"application name: "+ applicationMetadata.getName()
+ ", status: "+ applicationStatus
+ ", sessionId: "+ mSessionId
+ ", wasLaunched: "+ wasLaunched);
mApplicationStarted = true;
// Create the custom message channel
mEventChannel = new EventChannel(myContext,TAG);
try
{
Cast.CastApi.setMessageReceivedCallbacks(mApiClient,mEventChannel.getNamespace(),mEventChannel);
}
catch (IOException e)
{
Log.e(TAG,"Exception while creating channel",e);
}
// set the initial instructions on the receiver
sendMessage("starting from mobile");
}
else
{
Log.e(TAG,"application could not launch");
teardown();
}
}
});
}
}
catch (Exception e)
{
Log.e(TAG, "Failed to launch application", e);
}
}
#Override
public void onConnectionSuspended(int cause)
{
Log.d(TAG, "onConnectionSuspended");
mWaitingForReconnect = true;
}
public void sendMessage(String message)
{
if (mApiClient != null && mEventChannel != null)
{
try
{
Cast.CastApi.sendMessage(mApiClient,mEventChannel.getNamespace(), message)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status result)
{
if (!result.isSuccess())
{
Log.e(TAG, "Sending message failed");
}
}
});
}
catch (Exception e)
{
Log.e(TAG, "Exception while sending message", e);
}
}
else
{
Toast.makeText(myContext, message, Toast.LENGTH_SHORT).show();
}
}
public void teardown()
{
Log.d(TAG, "teardown");
if (mApiClient != null)
{
if (mApplicationStarted)
{
if (mApiClient.isConnected() || mApiClient.isConnecting())
{
try
{
Cast.CastApi.stopApplication(mApiClient, mSessionId);
if (myChannel != null)
{
Cast.CastApi.removeMessageReceivedCallbacks(mApiClient,myChannel.getNamespace());
myChannel = null;
}
}
catch (IOException e)
{
Log.e(TAG, "Exception while removing channel", e);
}
mApiClient.disconnect();
}
mApplicationStarted = false;
}
mApiClient = null;
}
mSelectedDevice = null;
mWaitingForReconnect = false;
mSessionId = null;
}
}
MediaRouterCallback.java
public class MyMediaRouterCallback extends MediaRouter.Callback {
private GoogleApiClient mApiClient;
private Cast.Listener mCastListener;
private Context myContext;
private ConnectionFailedListener mConnectionFailedListener;
public MyConnectionCallbacks mConnectionCallbacks;
public String TAG;
//private String mSessionId;
public MyMediaRouterCallback(Context _context, String _TAG)
{
this.myContext = _context;
this.TAG = _TAG;
mConnectionCallbacks = new MyConnectionCallbacks(myContext,TAG);
}
#Override
public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) {
Log.d(TAG, "onRouteSelected");
mConnectionCallbacks.mSelectedDevice = CastDevice.getFromBundle(info.getExtras());
launchReceiver();
}
#Override
public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) {
Log.d(TAG, "onRouteUnselected: info=" + info);
mConnectionCallbacks.teardown();
mConnectionCallbacks.mSelectedDevice = null;
}
private void launchReceiver()
{
try
{
mCastListener = new Cast.Listener() {
#Override
public void onApplicationDisconnected(int errorCode) {
Log.d(TAG, "application has stopped");
mConnectionCallbacks.teardown();
}
};
//Constructors for Google Play Services Connection
//mConnectionCallbacks = new MyConnectionCallbacks(myContext,TAG);
mConnectionFailedListener = new ConnectionFailedListener(TAG);
Cast.CastOptions.Builder apiOptionsBuilder =
Cast.CastOptions.builder(mConnectionCallbacks.mSelectedDevice, mCastListener);
// ApiClient to Connect to Google Play services
mApiClient = new GoogleApiClient.Builder(myContext)
.addApi(Cast.API, apiOptionsBuilder.build())
.addConnectionCallbacks(mConnectionCallbacks)
.addOnConnectionFailedListener(mConnectionFailedListener)
.build();
mConnectionCallbacks.setApiClient(mApiClient);//setting ApiClient to achieve sendMessage
//Connect to Google Play services
mApiClient.connect();
}
catch (Exception e)
{
Log.e(TAG, "Failed launchReceiver", e);
}
}
}
FirstActivity (where the chromecast is connected)
public class ConnectCastActivity extends ActionBarActivity {
private static final String TAG = ConnectCastActivity.class.getSimpleName();
private MediaRouter mMediaRouter;
private MediaRouteSelector mMediaRouteSelector;
private MediaRouter.Callback mMediaRouterCallback;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar actionBar = getSupportActionBar();
actionBar.setBackgroundDrawable(new ColorDrawable(android.R.color.transparent));
setContentView(R.layout.activity_connect_cast);
// Configure Cast device discovery
mMediaRouter = MediaRouter.getInstance(getApplicationContext());
mMediaRouteSelector = new MediaRouteSelector.Builder().addControlCategory(CastMediaControlIntent.categoryForCast(getResources().getString(R.string.app_id))).build();
mMediaRouterCallback = new MyMediaRouterCallback(getApplicationContext(),TAG);
TextView myTextView = (TextView)findViewById(R.id.txt_helloworld);
myTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(getApplicationContext(),MainActivity.class);
startActivity(i);
}
});
}
#Override
protected void onStart() {
super.onStart();
// Start media router discovery
mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
}
#Override
protected void onStop() {
// End media router discovery
Log.w(TAG, "onStop");
//mMediaRouter.removeCallback(mMediaRouterCallback);
super.onStop();
}
#Override
public void onDestroy() {
Log.w(TAG, "onDestroy");
// mMediaRouterCallback.onRouteUnselected(mMediaRouter,null);
super.onDestroy();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu_connect_cast, menu);
MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item);
MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat.getActionProvider(mediaRouteMenuItem);
// Set the MediaRouteActionProvider selector for device discovery.
mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector);
return true;
}
}
SecondActivity (the one that will send the message)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MediaRouter mMediaRouter = MediaRouter.getInstance(getApplicationContext());
mConnectionCallbacks = new MyConnectionCallbacks(getApplicationContext(),TAG);
setContentView(R.layout.activity_main);
//What should I put here?
}
If you have an application with multiple activities, you are better off if you do not tie the cast connectivity and related states to any of those activities, instead you can have a singleton, or use your Application instance or use a background service or ... to maintain the connection and access the required pieces that are maintained in that global place. If it fits your requirement, you might want to use the CastCompanionLibrary that already does most of the routine stuff for you; if not, you can take a look at it and the see how the CastVideos sample app uses that and try to do something similar for your application.

Discovering local server connection via LAN using Android

I am trying to discover local server(apache tomcat) running on http://localhost:8080 through my android device.To achieve that i thought of using jmdns library from heere
but i am really confused about how to proceed with as i don't understand the networking much.
here is the codei have written with little googling but any help would a be a great help.
public class DnssdDiscovery extends Activity {
protected static final String TAG = DnssdDiscovery.class.getSimpleName();
android.net.wifi.WifiManager.MulticastLock lock;
android.os.Handler handler = new android.os.Handler();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
handler.postDelayed(new Runnable() {
public void run() {
setUp();
}
}, 1000);
} /** Called when the activity is first created. */
// private String type = "_workstation._tcp.local.";_http._tcp.local.
private String type = "_http._tcp.local.";
private JmDNS jmdns = null;
private ServiceListener listener = null;
private ServiceInfo serviceInfo;
private void setUp() {
android.net.wifi.WifiManager wifi = (android.net.wifi.WifiManager) getSystemService(android.content.Context.WIFI_SERVICE);
lock = wifi.createMulticastLock("mylockthereturn");
lock.setReferenceCounted(true);
lock.acquire();
try {
InetAddress Address = InetAddress.getLocalHost();
Log.e("Local :", Address.getHostName());
jmdns = JmDNS.create(Address);
jmdns.addServiceListener(type, listener = new ServiceListener() {
#Override
public void serviceResolved(ServiceEvent ev) {
notifyUser("Service resolved: " + ev.getInfo().getQualifiedName() + " port:" + ev.getInfo().getPort());
}
#Override
public void serviceRemoved(ServiceEvent ev) {
notifyUser("Service removed: " + ev.getName());
}
#Override
public void serviceAdded(ServiceEvent event) {
// Required to force serviceResolved to be called again (after the first search)
jmdns.requestServiceInfo(event.getType(), event.getName(), 1);
}
});
serviceInfo = ServiceInfo.create("_http._tcp.local.", "AndroidTest", 8080, "plain test service from android");
jmdns.registerService(serviceInfo);
} catch (IOException e) {
e.printStackTrace();
return;
}
}
private void notifyUser(final String msg) {
handler.postDelayed(new Runnable() {
public void run() {
TextView t = (TextView)findViewById(R.id.text);
t.setText(msg+"\n=== "+t.getText());
}
}, 1);
}
#Override
protected void onStart() {
super.onStart();
//new Thread(){public void run() {setUp();}}.start();
}
#Override
protected void onStop() {
if (jmdns != null) {
if (listener != null) {
jmdns.removeServiceListener(type, listener);
listener = null;
}
jmdns.unregisterAllServices();
try {
jmdns.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
jmdns = null;
}
//repo.stop();
//s.stop();
lock.release();
super.onStop();
}
}

Categories

Resources