Maintain socket to server while in different Android Activities - java

Im new to Android programming, my app is supposed create a socket in order to maintain constant contact with a server (get status and updates etc) while the user changes to different activities while using the app in general.
Im wondering how its possible for the user to change to different activity classes while still have a constant connection to the server.
I though maybe in main activity to create some background handler that always runs even if the player changes to a different activity.
That handler would be the entity that would maintain contact with the server, like a sort of background task, and also communicate status to show in whatever activity that happen to be running at the time.
something like
OnCreate(....)
{
handler=new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
tick();
handler.postDelayed(this,1000);
}
},1000);
}
void tick()
{
communicate with server
}
But what if the user changes to a different activity, does the handler still run? Can the socket still receive data from server even when a different activity is running if i set up some kind of socket call back that calls a function when it gets data, but that call back would be in the main activity, how can it get called if another activity is active?
Also how to communicate new information gotten from the socket to any activity that happens to be running as to update its UI. I would imagine having a data structure that all activities can access, that is populated by the thread or whatever is communicating with the server.
It seems pretty complicated, anybody have example or know the standard way to do it?
Thanks

This works for me, but I'm pretty sure there are better ways to keep the socket connection alive when changing activities, like using services(as I have read but not yet tried). You can have a look at an example of services here: Services Example
In my Main Activity (Where I create socket)
public static Socket socket;
public static Socket getSocket(){
return socket;
}
public static synchronized void setSocket(Socket socket){
MainActivity.socket = socket;
}
public class ClientThread implements Runnable {
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
setSocket(socket);
if(socket!=null){
Intent goToNextActivity = new Intent(getApplicationContext(), SecondActivity.class);
startActivity(goToNextActivity);
}
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
In my second activity, I just call it like this to use the same socket I created (for example)
MainActivity.getSocket().getOutputStream().write(String.valueOf(multiplier).getBytes());
Works well for me!

Related

How to prevent main thread from blocking when I am listening on bluetooth devices in a Xamarin Android app?

I have an app that I need to function as a bluetooth server, it will listen on incoming bluetoooth connections and print the message sent from those devices. I have managed to make some progress though I fear that I have might made a mistake calling a blocking method in the main thread of my app, that is the User Interface thread. When I call clientSocket= serverSocket.Accept(); everything in my app stops, i use a switcher to call the method that has the above line, the switcher shows like its turning on but hangs due to a method that imolements a blocking call till a bluetooth device connects to the socket. How can I avoid that effect on the main thread of my app because I believe once a bluetooth device connects to the app then the blocking call will be removed and the switcher will resume to being checked. I have thought about using a new thread to accept the socket but how will I display the data received from the device to a UI TextView element I have in my app since manipulation of TextViews and other UI is not allowed from a non-UI thread, Thank you
server_switch.Click += (o, e) =>
{
//check the check status of the switch and start and disable gatt accordingly
Switch myswitch = o as Switch;
if (myswitch.Checked)
{
Log.Debug("Check Status Enabled", myswitch.Checked.ToString());
myswitch.Checked = true;
//switch the adapter mode and request for visibility
switch (_adapter.ScanMode)
{
case ScanMode.Connectable:
MakeVisibleFor300Seconds();
break;
case ScanMode.None:
MakeVisibleFor300Seconds();
break;
case ScanMode.ConnectableDiscoverable:
//do nothing, adapter in required mode
Log.Debug("Adapter Mode",
"Connectable Discoverable:" +
(_adapter.ScanMode == ScanMode.ConnectableDiscoverable).ToString());
break;
}
//create a new thread and run
var newThread= new SocketListener(display_data, serverSocket);
newThread.Start();
}
}
else
{
//the switch is disabled
Log.Debug("Check Status Enabled", myswitch.Checked.ToString());
}
};
Class for accepting new connections
//create a new class for listening on connections and displaying message to the textview
public class SocketListener : Thread
{
private TextView _data;
private BluetoothServerSocket mysocket;
private Stream output, input;
//declare default ctor for reflections
public SocketListener()
{
}
//declare the custom ctor
public SocketListener(TextView display, BluetoothServerSocket socket)
{
mysocket = socket;
_data = display;
}
//override run and implement a blocking call
public override void Run()
{
//NB: This implements a blocking call till a device connects
BluetoothSocket source_device = mysocket.Accept();
//get the input and output streams
output = source_device.OutputStream;
input = source_device.InputStream;
//check if data is available and write it to our object
StreamReader reader = new StreamReader(input);
string dat="";
string line;
while ((line = reader.ReadLine()) != null)
{
dat += line;
}
_data.Text = dat;
}
}
All the stuff about android, java, C#, xamarin, bluetooth, etc. is irrelevant. This question is essentially asking how to build a socket server application for a small number of clients, where "small" here means that you have the luxury of spawning one thread per client. (If you were to serve a large number of clients, then you would have to resort to a threadpool, but in your case that would be an unnecessary complication.)
The way we build a socket server application for a small number of clients is as follows:
One thread (the "Accept" thread) does nothing but an endless loop where it invokes serverSocket.Accept().
When a socket connection is established, the "Accept" thread creates a "Session" thread for the connected socket. So, we have one "Session" thread per client.
Each "Session" thread receives packets from a client and sends packets back to the client. When a "Session" thread has something to useful to show to the user, the "Session" thread "posts" a message to the GUI thread, which means that it sends it in a thread-safe way. Different GUI systems support different means of accomplishing this; I am not sure about Xamarin, perhaps with MessagingCenter.Send().

What does running on main thread mean in android

I'm trying to connect to a PC server (using Hercules) through TCP from an android app (client) but I'm really lost and don't know where to go. None of the tutorials are fully working for me, most of them can allow me to send messages from client to server but not vice versa.
I read about connections not supposed to be run from the "main thread" but what does that mean?
Also any examples of a TCP connection from android would be great.
Thanks!
I suspect that the "main thread" in this context means that thread that is managing the user interface. If you do anything much in this thread, you run the risk of Android killing your app because it appears to have hung.
Personally, I don't think it's a huge problem to have the user interface thread block for a few milliseconds to do a TCP operation. You'd need to make sure that you code the operation to have sensible timeouts, so you don't end with a dead app because the remote server takes too long to respond.
The official way to handle situations like this is to define the network operations in services, or in separate threads, and have the user interface thread communicate with those services or threads using short-lived operations.
This process is documented with examples here:
https://developer.android.com/training/basics/network-ops/connecting
Main thread in android is responsible to create and display UI on screen
to perform task related to connection strictly need to use background thread otherwise UI become laggy.
There are two method available to perform background Task
Runnable:
new Thread(new Runnable() {
public void run() {
..... // code here
}
}).start();
Android AsyncTask: https://developer.android.com/reference/android/os/AsyncTask
Like #Kevin Boone said, Main thread means UI thread in Android.
You can't do networking operations in the Main thread, otherwise you will get NetworkOnMainThreadException. You can create a new thread and then pass result back to the Main thread using Handler. Code could look like this:
public class MyActivity extends AppCompatActivity implements FetchDataUseCase.Listener {
private FetchDataUseCase fetchDataUseCase;
private TextView textView;
private Button dataButton;
public void onCreate() {
textView = findViewById(R.id.textView);
dataButton = findViewById(R.id.dataButton);
dataButton.setOnClickListener(v -> getDataFromNetwork());
fetchDataUseCase = new FetchDataUseCase(this);
}
void getDataFromNetwork() {
fetchDataUseCase.fetchDataAndNotify();
// start async operation! and receive result in onDataFetched()
}
#Override
public void onDataFetched(String data) {
// now you are in Main thread
// do something with data
textView.setText(data);
textView.setVisibility(View.VISIBLE);
}
#Override
public void onError() {
textView.setText("ERROR!!!");
textView.setVisibility(View.VISIBLE);
}
}
public class FetchDataUseCase {
public interface Listener {
void onDataFetched(String data);
void onError();
}
private final Listener listener;
private final Handler handler = new Handler(Looper.getMainLooper());
public FetchDataUseCase(Listener listener) {
this.listener = listener;
}
public void fetchDataAndNotify() {
new Thread(() -> {
String myData = "";
try {
// your networking operation
// where you receive some data
} catch (Exception e) {
handler.post(() -> listener.onError();
} finally {
// close stream, file, ...
}
// pass it back to Listener in Ui Thread
handler.post(() -> listener.onDataFetched(myData);
}).start();
}
}
read ThreadPoster: Multi-Threading in Android
And don't use AsyncTask =)) Async task is deprecated
Also, you need to add permision to your AndroidManifest file.
<uses-permission android:name="android.permission.INTERNET"/>
Hope it will help you)) Good luck!

Android how to update (UI thread) from other classes (really?)

you may know about Google Cloud Messaging
The problem is that when a gcm message triggers by the server, my application receives a bundle from google play services, this happen at GcmBroadcastReceiver.java. Here i can send this data to other classes in order to append some info from the server.. well. I got stuck when i try to update, for example, some views in the UI thread.
HOW I CAN DO THIS?
Imagine that MainActivity.java is the UI thread when i declare the views, etc.
I tried to create here a public static method which can be called directly by GcmBroadcastReceiver.java by this way: MainActivity.*updateUI*(args..), but it throws this exception:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Can anyone try to explain me this? i also know about asyncTask but i cant imagine how it works. I also find some pages explaining events that are fired by the UI thread it self like runnables that do some task in background. Im searching something like this:
MainActivity extends Activity{
...
protected void onCreate(Bundle blabla)..{
setContentView(R.layout.blabla);
registerSomeEvent(this);
}
private void handleEvent(Bundle ...){
... do stuff with the data provided in the UI thread
}
}
And here at GcmBroadcastReceiver, when gcm push some data, trigger that magic event in order to perform updates at the UI thread with some views like ListViews or TextView
One way is to use use LocalBroacastManager. For how to implement is, there is a great example on how to use LocalBroadcastManager?.
LocalBroadcast Manager is a helper to register for and send broadcasts of Intents to local objects within your process. The data you are broadcasting won't leave your app, so don't need to worry about leaking private data.`
Your activity can register for this local broadcast. From the GCMBroadcastReceiver, you send a local broadcast when you receive something in GcmBroadcastReceiver. Inside your Activity you can listen to the broadcast. This way if the activity is in the forefront/is active, it will receive the broadcast otherwise it won't. So, whenever you receive that local broadcast, you may do the desired action if activity is open. This is like saying to the activity that "Hey Activity, I've received a message. Do whatever you want with it".
If you want to do for the whole app, then you can make all your activities extend an abstract activity. And inside this abstract activity class you can register it for this 'LocalBroadcast'. Other way is to register for LocalBroadcast inside all your activities (but then you'll have to manage how you'll show the message only once).
You can use Handlers in your MainActivity in order to comunicate with UI Thread.
Communicating with the UI Thread
public class MainActivity extends Activity{
public static final int NEW_DATA_AVAILABLE = 0;
public static final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MainActivity.NEW_DATA_AVAILABLE:
String newData = msg.getData().getString(MyClass.DATA);
//Do some stuff with newData
break;
}
}
};
}
and in your non Activity class
public class MyClass implements Runnable{
Thread thread;
public final static String DATA = "new_data";
public MyClass(){
thread = new Thread(this);
thread.start();
}
#Override
public void run() {
while(true){
try{
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
Message msg = mHandler.obtainMessage(MainActivity.NEW_DATA_AVAILABLE);
Bundle bundle = new Bundle();
bundle.putString(DATA, "We have received new data");
msg.setData(bundle);
MainActivity.handler.sendMessage(msg);
}
}
}

How to destroy a thread in Java

I'm writing a client/server application in Java using sockets. In the server, I have a thread that accepts client connections, this thread runs indefinitely. At some point in my application, I want to stop accepting client connection, so I guess destroying that thread is the only way. Can anybody tell me how to destroy a thread?
Here's my code:
class ClientConnectionThread implements Runnable {
#Override
public void run() {
try {
// Set up a server to listen at port 2901
server = new ServerSocket(2901);
// Keep on running and accept client connections
while(true) {
// Wait for a client to connect
Socket client = server.accept();
addClient(client.getInetAddress().getHostName(), client);
// Start a new client reader thread for that socket
new Thread(new ClientReaderThread(client)).start();
}
} catch (IOException e) {
showError("Could not set up server on port 2901. Application will terminate now.");
System.exit(0);
}
}
}
As you can see, I have an infinite loop while(true) in there, so this thread will never stop unless somehow I stop it.
The right way to do this would be to close the server socket. This will cause the accept() to throw an IOException which you can handle and quit the thread.
I'd add a public void stop() method and make the socket a field in the class.
private ServerSocket serverSocket;
public ClientConnectionThread() {
this.serverSocket = new ServerSocket(2901);
}
...
public void stop() {
serverSocket.close();
}
public void run() {
while(true) {
// this will throw when the socket is closed by the stop() method
Socket client = server.accept();
...
}
}
Generally you don't. You ask it to interrupt whatever it is doing using Thread.interrupt().
A good explanation of why is in the Javadoc.
From the link:
Most uses of stop should be replaced by code that simply modifies some
variable to indicate that the target thread should stop running. The
target thread should check this variable regularly, and return from
its run method in an orderly fashion if the variable indicates that it
is to stop running. (This is the approach that the Java Tutorial has
always recommended.) To ensure prompt communication of the
stop-request, the variable must be volatile (or access to the variable
must be synchronized).
It should be noted that in all situations where a waiting thread doesn't respond to Thread.interrupt, it wouldn't respond to Thread.stop either.
For your specific situation you will have to call serverSocket.close, since it does not respond to Thread.interrupt.

Android: Thread Runnable and Handler.post issues - (Handler.postXX does not run on time when expected) within the Run method

I have a TCP Socket used as a TCP client which is used to read incoming data from a server constantly -- until the client or the server drops the connection. I don't know of any other way but use a while (true) loop in a different Runnable thread and in it (in the while loop) check for incoming data. The received data needs to be printed in an EditText.
The problem I am having is updating the text from Handler.post(...).
I know that:
In order to create TCP connections with Android 3.0 and above, I am required to place the TCP code either in a new Thread(...) or an AsyncTask because Strict mode has been enabled by default and I do not want to disable it.
I know that in order to update the UI from a new Thread in Android, I need to use Handler.post() if I use a Thread or the onProgressUpdate via publichProgress if I use AsyncTask and I know how to use all these but I am experiencing weird frustrating issues with both of them.
So, all I want to do is:
Listen to the server permanently
As soon as the server sends me a message, example: 'w' or 'a' or n', I immidiately display it on the EditText. You can think of it as a telnet session but I need "more"
precision than telnet as I want to process every single byte, even non-printable ones so I do not want to use readLine in anyway. I must read a byte at a time OR get a buffer of bytes and then process them separately by iterating through the buffer. I went with a byte at a time.
Here is the code I have and please pay attention to my comment above handle.response to see the problem I am having. I hope you can clear this out.
The code is very briefly coded and I have removed a lot of the error checking sections for this sample.
I have a new class called: ThreadClientInput:
public class ThreadClientInput implements Runnable {
InputStream inputStream;
MainActivity mainActivity;
Handler handler = new Handler();
int NextByte = 0;
public ThreadClientInput(MainActivity ma)
{
mainActivity = ma;
}
#Override
public void run()
{
////////////////////////////////////////////////////////////////
// Run the sensitive code that requires us to create this thread
try {
mainActivity.tcp_Client = new Socket("192.168.1.90", 23);
}
catch (Exception e){Log.e("EXEPTION:", e.getMessage().toString());return;}
////////////////////////////////////////////////////////////////
// Only try to get the inputStream if we have a successful connection
if (mainActivity.tcp_Client != null)
{
try
{
inputStream = mainActivity.tcp_Client.getInputStream();
}
catch (Exception e){Log.e("EXEPTION:", e.getMessage().toString()); return;}
}
/////////////////////////////////////////////
/////////////////////////////////////////////
// Update the text on the "Connect" button
handler.post(new Runnable()
{
#Override
public void run()
{ mainActivity.btn_Connect.setText("Connected");}
});
/////////////////////////////////////////////
/////////////////////////////////////////////
try
{
// I need to constantly read the data until we manually disconnect or
// the server drops the connection
while (true)
{
// Get the next byte
// I do not want to use "readline()" from a BufferedReader etc because I need to know exactly what's coming in
// I need to process every single byte
NextByte = inputStream.read();
if (NextByte > -1)
{
Log.e("in (While loop):", Character.toString((char)NextByte));
*** Here is the problem ****
// Update the EditText and this is where the problem starts
// if the server sends "1234", the Log.e() above will display everything correctly: "1234"
// however the handler.post below will run at the end of the last byte so the
// the EditText as well as the second Log.e below within the handle.post will display: "1444" or "4444" or "2444"
// So the handler.post does *not* run immediately even if I try handle.postAtFrontOfQueue()
// If the server sends "12345678", again, Log.e() above will display everything correctly: "12345678"
// however the handler.post below will run at the end of the last byte again
// and I will get "88888888" (most of the time) or "18888888"
//
handler.post(new Runnable()
{
#Override
public void run()
{
mainActivity.et_Response.setText(mainActivity.et_Response.getText() + Character.toString((char)NextByte));
Log.e("In handler.post:", Character.toString((char)NextByte));
}
});
}
}
}
catch (Exception e){Log.e("EXEPTION:", e.getMessage().toString());}
}}
I tried various variations including one with runOnUiThread and AsyncTask, with all I am getting same results. I am out, I have nothing. At this point of time I am just reading some documentation about Handle.post method to see if I can make sense.
I hope you have a solution and I know that "while (true)" isn't a good practice but I can break the loop from outside the thread with setting a flag and I don't know of any other way how to do this.
I am not sure how you are able to access NextByte from public void run() without defining it as final !?
If you want the handler to post message to the Activity UI thread, yo should create it within the activity class so it can access its Looper.
I can think of two solutions for your problem as follows:
1- To use a custom Runnable class where you pass to it the NextByte value as variable e.g.
handler.post(new MyRunnable(NextByte));
And MyRunnable can be something like:
class MyRunnable implements Runnable{
int byteData;
public MyRunnable(int byteData){
this.byteData = byteData;
}
public void run(){ // update the EditText}
}
2- To use handler.sendMessage(); and add the NextByte as the message argument e.g.
Message msg = new Message();
msg.arg1 = NextBye
handler.sendMessage(msg);
And your handler should be defined as following:
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
int nextByte = msg.arg1;
// update the EditText
}
};
Problem has been resolved.
This is what I did this.
In MainActivity.java which is the main file, in class MainActivity
public static class MyRunnable implements Runnable {
int currentByte = 0;
public MyRunnable(int b){
currentByte = b;
}
#Override
public void run()
{
mainActivity.et_Response.setText(mainActivity.et_Response.getText() + Character.toString((char)currentByte));
}
}
I have a statement mainActivity = this; in onCreate and then in ThreadClientInput.run
try {
while (true)
{
NextByte = inputStream.read();
// if the server drops the connection, break out the loop
if (NextByte < 0) break;
handler.post(new MainActivity.MyRunnable(NextByte));
}
}
catch (Exception e) {
Log.e("EXCEPTION", e.getMessage());
}
After this, handler.post is getting called correctly and at the correct and expected time. Full credit goes to iTech.

Categories