Use a service to send/receive data through a socket connection. - java

I have created a client-server application that the two parties communicate using a socket connection and input/output streams to send/receive data. It all works great but only if I have just one activity that uses the connection. Since I will be having more than just one activities in my application, and after some searching around, I've concluded that I have to create a Service which will handle the socket connection and sending/receiving from the socket streams. I've never worked with Services before and I thought I'd start one step at a time. At the moment I've just created a Service that creates an instance of my Client class(which extends Thread) and starts that thread, which establishes the connection to the server.
My Client class
T_Client:
public class T_Client extends Thread {
private static final String TAG = "T_Client";
private static String serverIP = "192.168.2.3";
private static int port = 4444;
private InetAddress serverAddr = null;
private Socket sock = null;
private boolean running = false;
private ObjectInputStream in;
private ObjectOutputStream out;
private Object objIn;
public void send(MessageCustom _msg) {
if (out != null) {
try {
out.writeObject(_msg);
out.flush();
Log.i("Send Method", "Outgoing : " + _msg.toString());
} catch (IOException ex) {
Log.e("Send Method", ex.toString());
}
}
}
public void stopClient() {
Log.v(TAG,"stopClient method run");
running = false;
}
#Override
public void run() {
running = true;
try {
serverAddr = InetAddress.getByName(serverIP);
Log.i("TCP Client", "C: Connecting...");
sock = new Socket(serverAddr, port);
try {
out = new ObjectOutputStream(sock.getOutputStream());
in = new ObjectInputStream(sock.getInputStream());
Log.i(TAG, "C: Connected.");
while (running) {
objIn = in.readObject();
Log.i("Object Read Class", objIn.getClass().toString());
Log.i("Object Read", objIn.toString());
}
Log.e("RESPONSE FROM SERVER", "S: Received Message: '" + objIn + "'");
} catch (Exception e) {
Log.e(TAG, "S: Error", e);
} finally {
out.close();
in.close();
sock.close();
Log.i(TAG, "Closing socket: " + sock);
}
} catch (Exception e) {
Log.e(TAG, "C: Error", e);
}
}
}
My Service Class
MyService:
public class MyService extends Service {
private static final String TAG = "MyService";
private T_Client client;
#Override
public void onDestroy() {
Log.v(TAG, "onDestroy");
if (client != null) {
try {
client.stopClient();
} catch (Exception e) {
Log.e(TAG, "Error on close: " + e);
}
}
super.onDestroy();
Toast.makeText(this, "Service stopped", Toast.LENGTH_LONG).show();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v(TAG, "onStartCommand");
client = new T_Client();
client.start();
Toast.makeText(this, "Service started", Toast.LENGTH_LONG).show();
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
All I do in my main activity at the moment is use a start and a stop button to start/stop the service
public void start(View v){
Log.i(TAG,"Start pressed");
Intent intent=new Intent(getBaseContext(),MyService.class);
startService(intent);
}
public void stop(View v){
Log.i(TAG,"Stop pressed");
Intent intent=new Intent(getBaseContext(),MyService.class);
stopService(intent);
}
So my questions are:
What do I have to do to send something using my Service?
How do I handle the objects that I read from the server so I can let the application know that something has been received, in real time?
Any input that could guide me towards resolving my issue is greatly appreciated.
Thank you in advance.

In case anyone else comes across this question, that has a similar problem, I managed to solve my problem by playing around with code from these two posts
Example: Communication between Activity and Service using
Messaging
How to keep the android client connected to the
server even on activity changes and send data to server?

Related

Android Bluetooth method call

My Application contains 3 Activities -
MainActivity.java
Write.java
BluetoothConnectionService.java
BluetoothConnectionService.java
public class BluetoothConnectionService {
private static final String TAG = "BluetoothConnectionServ";
private static final String appName = "MYAPP";
private static final UUID MY_UUID_INSECURE =
UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66");
private final BluetoothAdapter mBluetoothAdapter;
Context mContext;
private AcceptThread mInsecureAcceptThread;
private ConnectThread mConnectThread;
private BluetoothDevice mmDevice;
private UUID deviceUUID;
ProgressDialog mProgressDialog;
private ConnectedThread mConnectedThread;
public BluetoothConnectionService(Context context) {
mContext = context;
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//start();
}
/**
* This thread runs while listening for incoming connections. It behaves
* like a server-side client. It runs until a connection is accepted
* (or until cancelled).
*/
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket mmServerSocket;
public AcceptThread(){
BluetoothServerSocket tmp = null;
// Create a new listening server socket
try{
tmp = mBluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord(appName, MY_UUID_INSECURE);
Log.d(TAG, "AcceptThread: Setting up Server using: " + MY_UUID_INSECURE);
}catch (IOException e){
Log.e(TAG, "AcceptThread: IOException: " + e.getMessage() );
}
mmServerSocket = tmp;
}
public void run(){
Log.d(TAG, "run: AcceptThread Running.");
BluetoothSocket socket = null;
try{
// This is a blocking call and will only return on a
// successful connection or an exception
Log.d(TAG, "run: RFCOM server socket start.....");
socket = mmServerSocket.accept();
Log.d(TAG, "run: RFCOM server socket accepted connection.");
}catch (IOException e){
Log.e(TAG, "AcceptThread: IOException: " + e.getMessage() );
}
if(socket != null){
connected(socket,mmDevice);
}
Log.i(TAG, "END mAcceptThread ");
}
public void cancel() {
Log.d(TAG, "cancel: Canceling AcceptThread.");
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "cancel: Close of AcceptThread ServerSocket failed. " + e.getMessage() );
}
}
}
/**
* This thread runs while attempting to make an outgoing connection
* with a device. It runs straight through; the connection either
* succeeds or fails.
*/
private class ConnectThread extends Thread {
private BluetoothSocket mmSocket;
public ConnectThread(BluetoothDevice device, UUID uuid) {
Log.d(TAG, "ConnectThread: started.");
mmDevice = device;
deviceUUID = uuid;
}
public void run(){
BluetoothSocket tmp = null;
Log.i(TAG, "RUN mConnectThread ");
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
Log.d(TAG, "ConnectThread: Trying to create InsecureRfcommSocket using UUID: "
+MY_UUID_INSECURE );
tmp = mmDevice.createRfcommSocketToServiceRecord(deviceUUID);
} catch (IOException e) {
Log.e(TAG, "ConnectThread: Could not create InsecureRfcommSocket " + e.getMessage());
}
mmSocket = tmp;
// Always cancel discovery because it will slow down a connection
mBluetoothAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
Log.d(TAG, "run: ConnectThread connected.");
//mProgressDialog.cancel();
//Toast.makeText(mContext,"Connected", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
// Close the socket
try {
mmSocket.close();
Log.d(TAG, "run: Closed Socket.");
} catch (IOException e1) {
Log.e(TAG, "mConnectThread: run: Unable to close connection in socket " + e1.getMessage());
}
Log.d(TAG, "run: ConnectThread: Could not connect to UUID: " + MY_UUID_INSECURE );
}
connected(mmSocket,mmDevice);
}
public void cancel() {
try {
Log.d(TAG, "cancel: Closing Client Socket.");
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "cancel: close() of mmSocket in Connectthread failed. " + e.getMessage());
}
}
}
private void connected(BluetoothSocket mmSocket, BluetoothDevice mmDevice) {
Log.d(TAG, "connected: Starting.");
// Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(mmSocket);
mConnectedThread.start();
//start new activity
Intent intent = new Intent(mContext, Write.class);
mContext.startActivity(intent);
}
/**
Finally the ConnectedThread which is responsible for maintaining the BTConnection, Sending the data, and
receiving incoming data through input/output streams respectively.
**/
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "ConnectedThread: Starting.");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
//dismiss the progress dialog when connection is established
try{
mProgressDialog.dismiss();
}catch (NullPointerException e){
e.printStackTrace();
}
try {
tmpIn = mmSocket.getInputStream();
tmpOut = mmSocket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run(){
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
// Read from the InputStream
try {
bytes = mmInStream.read(buffer);
String incomingMessage = new String(buffer, 0, bytes);
Log.d(TAG, "InputStream: " + incomingMessage);
Intent incomingMessageIntent = new Intent("incomingMessage");
incomingMessageIntent.putExtra("theMessage", incomingMessage);
LocalBroadcastManager.getInstance(mContext).sendBroadcast(incomingMessageIntent);
Log.d(TAG, "broadcast sent");
} catch (IOException e) {
Log.e(TAG, "write: Error reading Input Stream. " + e.getMessage() );
break;
}
}
}
//Call this from the main activity to send data to the remote device
/*public void write(byte[] bytes) {
String text = new String(bytes, Charset.defaultCharset());
Log.d(TAG, "write: Writing to outputstream: " + text);
try {
mmOutStream.write(bytes);
} catch (IOException e) {
Log.e(TAG, "write: Error writing to output stream. " + e.getMessage() );
}
}*/
public void write(String input) {
byte[] msgBuffer = input.getBytes(); //converts entered String into bytes
try {
mmOutStream.write(msgBuffer); //write bytes over BT connection via outstream
} catch (IOException e) {
//if you cannot write, close the application
Toast.makeText(mContext, "Connection Failure", Toast.LENGTH_LONG).show();
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
public void start() {
Log.d(TAG, "start");
// Cancel any thread attempting to make a connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mInsecureAcceptThread == null) {
mInsecureAcceptThread = new AcceptThread();
mInsecureAcceptThread.start();
}
}
public void startClient(BluetoothDevice device,UUID uuid){
Log.d(TAG, "startClient: Started.");
//init progress dialog
mProgressDialog = ProgressDialog.show(mContext,"Connecting Bluetooth"
,"Please Wait...",true);
mConnectThread = new ConnectThread(device, uuid);
mConnectThread.start();
}
/**
* Write to the ConnectedThread in an unsynchronized manner
*
*/
public void write() {
// Create temporary object
//ConnectedThread r;
// Synchronize a copy of the ConnectedThread
Log.d(TAG, "write: Write Called.");
//perform the write
mConnectedThread.write("1");
}
}
PROBLEM:-
From the MainActivity, I created a BluetoothConnectionService object
BluetoothConnectionService mBluetoothConnection = new BluetoothConnectionService(MainActivity.this);
Then, I called startClient(device,uuid) method on mBluetoothConnection object
mBluetoothConnection.startClient(device,uuid);
Now, after successful connection is made, I can send out data to other devices by calling write() from the MainActivity
mBluetoothConnection.write();
But I don't want to send out data from MainActivity instead I want to use Write activity to send data out. How can I do that?
The Code you are using is provided by google Bluetooth chat application and they write using this:
In your Activity
private void sendMessage(String message) {
// Check that we're actually connected before trying anything
if (bluetoothConnectionService.getState() != BluetoothConnectionService.STATE_CONNECTED) {
Toast.makeText(MainActivity.this, R.string.not_connected, Toast.LENGTH_SHORT).show();
return;
}
// Check that there's actually something to send
if (message.length() > 0) {
// Get the message bytes and tell the BluetoothConnectionService to write
byte[] send = message.getBytes();
bluetoothConnectionService.write(send);
// Reset out string buffer to zero and clear the edit text field
mOutStringBuffer.setLength(0);
}
}
In the service add these two methods
/**
* Write to the ConnectedThread in an unsynchronized manner
*
* #param out The bytes to write
* #see ConnectedThread#write(byte[])
*/
public void write(byte[] out) {
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (mState != STATE_CONNECTED) return;
r = mConnectedThread;
}
// Perform the write unsynchronized
r.write(out);
}
/**
* Write to the connected OutStream.
*
* #param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
// Share the sent message back to the UI Activity
mHandler.obtainMessage(Constants.MESSAGE_WRITE, -1, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}

Socket in service on Android writing to server but not reading

So I created a service in Android that contains a socket which I'm using to send and receive messages from a server. The problem is that the client can send messages to the servers with no problem, but it does not receives messages from the server even though I flushed the server.
Here are the snippets from the code related to the issue:
ServerMulti.java
public class ServerMulti {
ServerSocket srv;
Socket cliente;
static final int PTO=3000;
int cont=0;
Thread t;
Thread1 ha;
public ServerMulti() {
try{
srv=new ServerSocket(PTO);
System.out.println("Server Running on "+srv.getLocalPort());
atiendeClientes();
}catch(Exception e){
}
}
public void atiendeClientes(){
try{
while(true){
cliente=srv.accept();
cont+=1;
ha=new Thread1(cliente,cont);
t=new Thread(ha);
t.start();
}
}catch(Exception e){
e.toString();
}
}
public static void main(String x[]){
new ServerMulti();
}
}
Thread1.java
public class Thread1 implements Runnable{
Socket cliente;
int c;
DataOutputStream dos;
DataInputStream dis;
public Thread1(Socket _cliente,int _c) {
this.cliente=_cliente;
this.c=_c;
}
public void run(){
String cmd="";
try{
dos=new DataOutputStream(cliente.getOutputStream());
dis=new DataInputStream(cliente.getInputStream());
do{
cmd=dis.readUTF();
System.out.println("The client "+c+" says: "+cmd);
OutputStream os = client.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
if(cmd.equals("Admin 123")){
bw.write("true");
System.out.println("I sent true");
}else{
bw.write("false");
System.out.println("I got nothing");
}
bw.flush();
}while(!cmd.equals("fin"));
dis.close();
dos.close();
cliente.close();
System.out.println("Client "+c+" Disconected");
}catch(Exception e){
e.toString();
}
}
}
SocketService.java
public class SocketService extends Service {
public static final String SERVERIP = "192.168.0.13";
public static final int SERVERPORT = 3000;
DataOutputStream dos;
DataInputStream dis;
String asd = "";
Socket socket;
boolean mRun = false;
String incomingMessage;
InetAddress serverAddr;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
System.out.println("I am in Ibinder onBind method");
return myBinder;
}
private final IBinder myBinder = new LocalBinder();
//TCPClient mTcpClient = new TCPClient();
public class LocalBinder extends Binder {
public SocketService getService() {
System.out.println("I am in Localbinder ");
return SocketService.this;
}
}
#Override
public void onCreate() {
super.onCreate();
System.out.println("I am in on create");
}
public void IsBoundable(){
Toast.makeText(this,"I bind like butter", Toast.LENGTH_LONG).show();
}
public void transm(String msg){
try{
dos.writeUTF(msg);
}catch(Exception e){
e.toString();
}
}
public Boolean receive(){
try{
String a = dis.readUTF();
System.out.println(a);
if (a.equals("true")) {
return true;
}else{
return false;
}
}catch (Exception e){
e.toString();
}
return false;
}
#Override
public int onStartCommand(Intent intent,int flags, int startId){
super.onStartCommand(intent, flags, startId);
System.out.println("I am in on start");
// Toast.makeText(this,"Service created ...", Toast.LENGTH_LONG).show();
Runnable connect = new connectSocket();
new Thread(connect).start();
return START_STICKY;
}
class connectSocket implements Runnable {
#Override
public void run() {
mRun=true;
try {
//here you must put your computer's IP address.
Log.e("TCP Client", "C: Connecting...");
//create a socket to make the connection with the server
socket = new Socket(SERVERIP, SERVERPORT);
try {
//send the message to the server
dos=new DataOutputStream(socket.getOutputStream());
dis=new DataInputStream(socket.getInputStream());
Log.e("TCP Client", "C: Sent.");
Log.e("TCP Client", "C: Done.");
/* while (mRun) {
incomingMessage = dis.readUTF();
}*/
// Log.e("Hi", "Received Message: " + incomingMessage);
}
catch (Exception e) {
Log.e("TCP", "S: Error", e);
}
} catch (Exception e) {
Log.e("TCP", "C: Error", e);
}
}
}
#Override
public void onDestroy() {
super.onDestroy();
try {
socket.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
socket = null;
}
}
And this is what I use on the android activity Login.java
public class Login extends Activity {
EditText ed1, ed2;
MCom mcom;
boolean mIsBound;
SocketService mBoundService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
setGui(null);
startService(new Intent(Login.this, SocketService.class));
doBindService();
}
private ServiceConnection mConnection = new ServiceConnection() {
//EDITED PART
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
mBoundService = ((SocketService.LocalBinder)service).getService();
}
#Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
mBoundService = null;
}
};
private void doBindService() {
bindService(new Intent(Login.this, SocketService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
if(mBoundService!=null){
mBoundService.IsBoundable();
}
}
private void doUnbindService() {
if (mIsBound) {
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
}
#Override
protected void onDestroy() {
super.onDestroy();
doUnbindService();
}
public void setGui(View v){
ed1=(EditText)findViewById(R.id.editText);
ed2=(EditText)findViewById(R.id.editText2);
}
public void Ing (View v){
mBoundService.transm(ed1.getText().toString()+" "+ed2.getText().toString());
if(mBoundService.receive()==true){
mostSald();
Toast.makeText(this, "Welcome!", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "Not Valid Credentials", Toast.LENGTH_SHORT).show();
}
}
public void exit (View v){
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
public void showBalance(){
Intent i= new Intent(this, Balance.class);
startActivity(i);
}
}
It always goes to the last else since it appears that is not receiving anything from the server plus the variable "a" in the method receive it always stays empty, but in the server console I get the "I sent true" message.
Any ideas? Thanks in advance :)

Service Socket Disconnect on Background->Foreground switch

I am writing an IRC Client. The socket connection to the IRC Server is handled via a service. I have managed to stabilize all the UI elements of the Activities in question during the orientation change, but somehow the socket that is maintained by the service is being closed during the change.
Here is what I believe to be the relevant code. Please let me know if you need to see more.
//This is the Service in question
public class ConnectionService extends Service{
private BlockingQueue<String> MessageQueue;
public final IBinder myBind = new ConnectionBinder();
public class ConnectionBinder extends Binder {
ConnectionService getService() {
return ConnectionService.this;
}
}
private Socket socket;
private BufferedWriter writer;
private BufferedReader reader;
private IRCServer server;
private WifiManager.WifiLock wLock;
private Thread readThread = new Thread(new Runnable() {
#Override
public void run() {
try {
String line;
while ((line = reader.readLine( )) != null) {
if (line.toUpperCase().startsWith("PING ")) {
SendMessage("PONG " + line.substring(5));
}
else
queueMessage(line);
}
}
catch (Exception e) {}
}
});
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(MessageQueue == null)
MessageQueue = new LinkedBlockingQueue<String>();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
return myBind;
}
#Override
public boolean stopService(Intent name) {
try {
socket.close();
wLock.release();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.stopService(name);
}
#Override
public void onDestroy()
{//I put this here so I had a breakpoint in place to make sure this wasn't firing instead of stopService
try {
socket.close();
wLock.release();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.onDestroy();
}
public void SendMessage(String message)
{
try {
writer.write(message + "\r\n");
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public String readLine()
{
try {
if(!isConnected())
return null;
else
return MessageQueue.take();
} catch (InterruptedException e) {
return "";
}
}
public boolean ConnectToServer(IRCServer newServer)
{
try {
//create a new message queue (connecting to a new server)
MessageQueue = new LinkedBlockingQueue<String>();
//lock the wifi
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "LockTag");
wLock.acquire();
server = newServer;
//connect to server
socket = new Socket();
socket.setKeepAlive(true);
socket.setSoTimeout(60000);
socket.connect(new InetSocketAddress(server.NAME, Integer.parseInt(server.PORT)), 10000);
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//run basic login scripts.
if(server.PASS != "")
SendMessage("PASS " + server.PASS);
//write nickname
SendMessage("NICK " + server.NICK);
//write username login
SendMessage("USER " + server.NICK + " 0 * :Fluffy IRC");
String line;
while ((line = reader.readLine( )) != null) {
if (line.indexOf("004") >= 0) {
// We are now logged in.
break;
}
else if (line.indexOf("433") >= 0) {
//change to alt Nick
if(!server.NICK.equals(server.ALT_NICK) && !server.ALT_NICK.equals(""))
{
server.NICK = server.ALT_NICK;
SendMessage("NICK " + server.NICK);
}
else
{
queueMessage("Nickname already in use");
socket.close();
return false;
}
}
else if (line.toUpperCase().startsWith("PING ")) {
SendMessage("PONG " + line.substring(5));
}
else
{
queueMessage(line);
}
}
//start the reader thread AFTER the primary login!!!
CheckStartReader();
if(server.START_CHANNEL == null || server.START_CHANNEL == "")
{
server.WriteCommand("/join " + server.START_CHANNEL);
}
//we're done here, go home everyone
} catch (NumberFormatException e) {
return false;
} catch (IOException e) {
return false;
}
return true;
}
private void queueMessage(String line) {
try {
MessageQueue.put(line);
} catch (InterruptedException e) {
}
}
public boolean isConnected()
{
return socket.isConnected();
}
public void CheckStartReader()
{
if(this.isConnected() && !readThread.isAlive())
readThread.start();
}
}
//Here are the relevant portions of the hosting Activity that connects to the service
//NOTE: THE FOLLOWING CODE IS PART OF THE ACTIVITY, NOT THE SERVICE
private ConnectionService conn;
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
conn = ((ConnectionService.ConnectionBinder)service).getService();
Toast.makeText(main_tab_page.this, "Connected", Toast.LENGTH_SHORT)
.show();
synchronized (_serviceConnWait) {
_serviceConnWait.notify();
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
conn = null;
}
};
#Override
protected void onSaveInstanceState(Bundle state){
super.onSaveInstanceState(state);
state.putParcelable("Server", server);
state.putString("Window", CurrentTabWindow.GetName());
unbindService(mConnection);
}
#Override
protected void onDestroy()
{
super.onDestroy();
if(this.isFinishing())
stopService(new Intent(this, ConnectionService.class));
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_tab_page);
localTabHost = (TabHost)findViewById(R.id.tabHostMain);
localTabHost.setup();
localTabHost.setOnTabChangedListener(new tabChange());
_serviceConnWait = new Object();
if(savedInstanceState == null)
{//initial startup, coming from Intent to start
//get server definition
server = (IRCServer)this.getIntent().getParcelableExtra(IRC_WINDOW);
server.addObserver(this);
AddTabView(server);
startService(new Intent(this, ConnectionService.class));
}
else
{
server = (IRCServer)savedInstanceState.getParcelable("Server");
String windowName = savedInstanceState.getString("Window");
//Add Needed Tabs
//Server
if(!(windowName.equals(server.GetName())))
AddTabView(server);
//channels
for(IRCChannel c : server.GetAllChannels())
if(!(windowName.equals(c.GetName())))
AddTabView(c);
//reset each view's text (handled by tabChange)
if(windowName.equals(server.GetName()))
SetCurrentTab(server.NAME);
else
SetCurrentTab(windowName);
ResetMainView(CurrentTabWindow.GetWindowTextSpan());
//Rebind to service
BindToService(new Intent(this, ConnectionService.class));
}
}
#Override
protected void onStart()
{
super.onStart();
final Intent ServiceIntent = new Intent(this, ConnectionService.class);
//check start connection service
final Thread serverConnect = new Thread(new Runnable() {
#Override
public void run() {
if(!BindToService(ServiceIntent))
return;
server.conn = conn;
conn.ConnectToServer(server);
server.StartReader();
if(server.START_CHANNEL != null && !server.START_CHANNEL.equals(""))
{
IRCChannel chan = server.FindChannel(server.START_CHANNEL);
if(chan != null)
{
AddTabView(chan);
}
else
{
server.JoinChannel(server.START_CHANNEL);
chan = server.FindChannel(server.START_CHANNEL);
AddTabView(chan);
}
}
}
});
serverConnect.start();
}
private boolean BindToService(Intent ServiceIntent)
{
int tryCount = 0;
bindService(ServiceIntent, mConnection, Context.BIND_AUTO_CREATE);
while(conn == null && tryCount < 10)
{
tryCount++;
try {
synchronized (_serviceConnWait) {
_serviceConnWait.wait(1500);
}
}
catch (InterruptedException e) {
//do nothing
}
}
return conn != null;
}
Im not entirely certain what I am doing wrong there. Obviously there's something I'm missing, haven't found yet, or haven't even thought to check. What happens though is that after the orientation change my Send command gives me this message and nothing happens:
06-04 22:02:27.637: W/System.err(1024): java.net.SocketException: Socket closed
06-04 22:02:27.982: W/System.err(1024): at com.fluffyirc.ConnectionService.SendMessage(ConnectionService.java:90)
I have no idea when the socket is getting closed, or why.
Update
I have changed the code so that rather than binding to the service and using that to start it, instead I call startService and stopService at appropriate points as well as binding to it, on the thought that the service was being destroyed when the binding was lost. This is working exactly like it was before I changed it. The socket still closes on an orientation change, and I have no idea why.
Update :- Code and description
I added the code changes recently made for Start/Stop service and START_STICKY. I also recently read a very good article explaining how the orientation change process flow works and why its NOT a bad idea to add the android:configChanges="orientation|screenSize" line to your manifest. So this fixed the orientation issue, but its still doing the same thing if I put the activity into background mode, and then bring it back to the foreground. That still follows the same Save/Destroy/Create process that the orientation does without that manifest line...and it still closes my socket, and I still don't know why.
I do know that it doesn't close the socket until the re-create process...I know this because the message queue will display messages that were received while the app was in the background, but once I bring it back forward it closes the socket and nothing else can be sent or received.
'Socket closed' means that you closed the socket and then continued to use it. It isn't a 'disconnect'.
You need to put something into that catch block. Never just ignore an exception. You might get a surprise when you see what the exception actually was.
NB Socket.isConnected() doesn't tell you anything about the state of the connection: only whether you have ever connected the Socket. You have, so it returns true.

How to run a method in specific intervals from a thread within a service...?

I am working with the Bluetooth chat example and I am trying to send "dummy" data in specific intervals from a thread that's active when the Bluetooth device is connected. Is it a good idea to start/stop another service to call a method in the original service every so often? How would I implement this?
private class ConnectedThread extends Thread {
static private final String TAG = "PhoneInfoConnectedThread";
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket, String socketType) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
Log.d(TAG, "In and out streams created");
} catch (IOException e) {
Log.e(TAG, "temp sockets not created " + e.getMessage());
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
// this is where we will spend out time when connected to the accessory.
public void run() {
// Keep listening to the InputStream while connected
while (true) {
// do whatever
}
}
// Write to the connected OutStream.
public void write(byte[] buffer) {
if (mmOutStream == null) {
Log.e(TAG, "ConnectedThread.write: no OutStream");
return;
}
try {
Log.d(TAG, "ConnectedThread.write: writing " + buffer.length
+ " bytes");
mmOutStream.write(buffer);
// Share the sent message back to the UI Activity
// mHandler.obtainMessage(PhoneInfoActivity.MESSAGE_WRITE, -1,
// -1, buffer).sendToTarget();
Log.d(TAG, "ConnectedThread.write: sent to calling activity");
} catch (IOException e) {
Log.e(TAG, "Exception during write" + e.getMessage());
}
}
public void cancel() {
try {
Log.d(TAG, "ConnectedThread.cancel: closing socket");
if (mmSocket != null)
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "ConnectedThread.cancel: socket.close() failed"
+ e.getMessage());
}
}
}
May this example help you.
MyTimerTask myTask = new MyTimerTask();
Timer myTimer = new Timer();
myTimer.schedule(myTask, 2000, 1000);
class MyTimerTask extends TimerTask {
public void run() {
Log.v("TAG","Message");
}
}
for more information see this

Java ServerSocket and Android LocalServerSocket

I have implemented my own android service as follows
public class MyService extends Service {
private static final String TAG = "MyService";
private Server mServer;
private LocalServerSocket server;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Log.d(TAG, "onCreate");
mServer = new Server();
mServer.start();
}
#Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
if(server != null){
try {
server.close();
} catch (IOException e) {
Log.d(TAG, "exception in server close");
e.printStackTrace();
}
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStart");
return START_STICKY;
}
class Server extends Thread {
#Override
public void run() {
try {
server = new LocalServerSocket("my.socket");
while (true) {
LocalSocket receiver;
try{
receiver = server.accept();
}catch(SocketException e){
Log.d(TAG, "SocketException");
break;
}
catch(IOException e){
Log.d(TAG, "IOException");
break;
}
if (receiver != null) {
Log.d(TAG, "Got Data in receiver");
}
receiver.close();
}
} catch (IOException e) {
Log.d(TAG, "one more");
e.printStackTrace();
}
}
}
}
The problem I am facing is that, if my LocalServerSocket is blocking in accept(), then a call to server.close() in OnDestroy() will not throw a SocketException. Hence, next time I start the service, I get "address already in use exception". If instead of LocalServerSocket, I use java.net.Socket, then i get the required behavior. I would like to know why LocalServerSocket behaves differently from Java Sockets. In my case, how do I come out of the while loop.
I had the same problem and "solved" it this way. The thread run() method is checking for "!isInterrupted()". The method "stopSocketServer()" which I added to my Listener-Thread marks the thread for interrupt() and then made a connect request to itself to trigger the accept() method.
/**
* Executed if thread is started.
*/
public void run() {
try {
// leave while loop if thread is marked for interrupt.
while (!isInterrupted()) {
LocalSocket clientSocket = serverSocket.accept();
if (!isInterrupted()) {
threadPool.execute(new ClientProcessor(clientSocket));
}
}
} catch (IOException e) {
if (!isInterrupted()) {
Log.e(TAG, "socket listener terminated", e);
}
} finally {
try {
if (serverSocket != null) {
serverSocket.close();
}
if (threadPool != null) {
threadPool.shutdownNow();
}
Log.i(TAG, "socket listener stopped");
} catch (IOException e) {
}
}
}
public void stopSocketServer() {
if (serverSocket != null) {
try {
// mark thread as interrupted
interrupt();
// now send connect request to myself to trigger leaving accept()
LocalSocket ls = new LocalSocket();
ls.connect(serverSocket.getLocalSocketAddress());
ls.close();
} catch (IOException e) {
Log.e(TAG, "stopSocketServer failed", e);
}
}
}
From the code you've posted it looks like your LocalServerSocket server will remain null forever and onDestroy() won't close it. Also, closing the socket normally shouldn't throw IOException - but the accept() will do so if the socket is closed concurrently.

Categories