Android: Calling an activity from a Thread - android

My problem is probably going to be simple and awkward at the same time, but I am a little stuck.
I have a Main.java class, that extends Activity.
Inside that class, I do the following:
ringerServer = new Thread(new RingerServer());
ringerServer.start();
What I want to do is have the RingerServer thread running continously.
Inside that thread, I listen for a TCP connection. If I get one, I start another class, which sends and receives UDP packet.
public class RingerServer implements Runnable {
public static final int SERVERPORT = 4445; // Default port to connect to
#Override
public void run() {
try {
// Create a socket for handling incoming requests
ServerSocket server = new ServerSocket(SERVERPORT);
while (!VoIPCall.onCall) {
// Wait for an incoming connection
Socket clientSocket = server.accept();
// TODO: Display a message for the user to accept or decline
// For now, automatically accept the call
Intent myIntent = new Intent(null, VoIPCall.class);
// Put the IP as a parameter
myIntent.putExtra("inetAddress", clientSocket.getInetAddress());
startActivity(myIntent);
}
} catch (IOException e) {
Log.e("TCP", "S: Error", e);
}
}
}
My problem has to do with the lines:
Intent myIntent = new Intent(null, VoIPCall.class);
myIntent.putExtra("inetAddress", clientSocket.getInetAddress());
startActivity(myIntent);
Those lines would work fine inside an Activity but it doesn't to complain as it is a Thread, it doesn't know about the Activity class, because it doesn't extend it, but implements Runnable.
I am not sure how I can make my program keep running the RingerServer but have the main thread go to VoIPCall class. Any ideas please?
I really appreciate your help.
Thank you very much,
Jary

You should move your thread into a Service rather than an Activity. I recommend starting off by reading the Processes and Threads section of the Android Dev Guide. Then checkout the API docs for Service, which will help you get started creating one.

Related

Use of Handler in AsyncTask

I'm developping an App that uses Wifi/Tcp connection to communicate with a Robot. For the moment I'm using a single thread to manage the tcp connection using a TcpClient class and a "ConnectTask extends AsyncTask" in my MainActivity.
So far this is what I have :
TcpClient.java
private OnMessageReceived mMessageListener = null;
private int bufferSize = 5000;
public ByteBuffer bf;
private BufferedInputStream inFromServer;
private BufferedOutputStream outFromClient;
.
.
.
public void run() {
mRun = true;
try {
//here you must put your computer's IP address.
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
Log.e("TCP Client", "C: Connecting...");
//create a socket to make the connection with the server
Socket socket = new Socket(serverAddr, SERVER_PORT);
try {
Log.i("Debug", "inside try catch");
//receives the message which the server sends back
inFromServer = new BufferedInputStream(socket.getInputStream());
outFromClient = new BufferedOutputStream(socket.getOutputStream());
bf = ByteBuffer.allocate(bufferSize);
while (mRun) {
// Log.i("Debug", "inside while mRun");
bf.order(ByteOrder.LITTLE_ENDIAN);
for (int i=0;i<5000;i++) {
int b = inFromServer.read();
if (b == -1) {
break;
}
bf.put((byte) b);
}
if ( bf != null && mMessageListener != null) {
//call the method messageReceived from MyActivity class
// Log.i("Debug","Message received !");
mMessageListener.messageReceived(bf);
mMessageListener.updateBatteryLvl();
}
bf.position(0);
}
}
.
.
.
And this is my ConnectTask in MainActivity :
public class ConnectTask extends AsyncTask<Void, ByteBuffer, TcpClient> {
#Override
protected TcpClient doInBackground(Void... params) {
//we create a TCPClient object and
mTcpClient = new TcpClient(new TcpClient.OnMessageReceived() {
#Override
//here the messageReceived method is implemented
public void messageReceived(ByteBuffer message) throws IOException {
//this method calls the onProgressUpdate
byte[] resultat = new byte[4000];
resultat = message.array();
updateBatteryLvl();
message.clear();
I'm not using any Handlers in tcpclient or connecttask, but I have seen some tutorials using them for Tcp Connection and I was wondering why are they using it ? I already tested the connection with the Robot and I receive the data it sends perfectly fine.
Are Handlers used like semaphores if u have multithreads writing in the same file for exemple ?
Are Handlers used like semaphores if u have multithreads writing in
the same file for exemple ?
More or less, yes.
Handlers can only be created (call its contructor) in a Thread with a Looper (main thread is a thread with a looper).
Then, you can post Runnables and Messages to be run (sometime in the future) by the handler. These runables/messages are enqueued by the hanlder, and dispatched to be run on the thread they were created. So basically, if you run stuff in differente threads, and want to perform some action without worring of race conditions (or need these actions to be run on a specific thread, like when you need to update the UI), you can post "operations" in the handler, and thats all.
In your case, with the AsyncTask, it does the same, doing the work in a separated thread, and commiting the result to the MAIN THREAD. If you need to manage differente threads, and commit the result to single, not MAIN THREAD, you'll need to use a handler.
But as you describe what you're doing, it is no needed.
You can not do long running operation in the UI thread (main thread) or you'll get "application not responding" (ANR).
So you have to use multithreading and Android framework provides infrastructure for easier data synchronization with the main thread (Android UI toolkit is not thread-safe).
Your choice may lead to problems, because:
AsyncTask should only be used for operations that take quite few seconds.
AsyncTasks are executed serially on a single background thread (from API 11). So long running worker can block others.
AsyncTasks do not respect lifecycle of your host Activity (you may get memory leaks).
Priority in the killing list is low.

Android Thread vs AsyncTask vs IntentService called from BLE onCharacteristicChanged()

I have an Android app from which I receive BLE data (every 62ms via notifications). The app can save data via a BufferedWriter to a file. Upon each onCharacteristicChanged() callback, I call either an AsyncTask, Thread or an IntentService to do a file write if the user enabled file save.
The AsyncTask seems to work fine. But the docs say execute must be invoked on the UI thread, and I'm calling it from the BLE callback. Is that a problem? And how should I fix it?
Using Thread causes this error: GKI_exception out of buffers https://code.google.com/p/android/issues/detail?id=65455 (except my code is not scanning but receiving notifications) and if the file save is long, I need to power cycle the Nexus 7 (the app and BLE become totally unresponsive). Why does the Thread not work and how can I fix it?
The IntentService never goes to the onHandleIntent(). What are the issues here?
Here is some code:
...
_context = this.getApplicationContext();
...
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
...
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
...
int mode = 1;
if (mode==0) // Asynctask
new doFileWriteTask().execute(strBuild.toString());
else if (mode==1) // Thread
{
final String str = strBuild.toString();
new Thread(new Runnable() {
public void run() {
try {
_writer.write(str);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
else if (mode==2) // intentService
{
Intent mServiceIntent = new Intent(_context, writeFileService.class);
mServiceIntent.putExtra("foo", strBuild.toString());
startService(mServiceIntent);
}
}
...
};
private class doFileWriteTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... strings) {
try {
_writer.write(strings[0]);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private class writeFileService extends IntentService {
public writeFileService() {
super("writeFileService");
}
#Override
protected void onHandleIntent(Intent workIntent) {
String dataString = workIntent.getStringExtra("foo");
try {
_writer.write(dataString);
} catch (Exception e) {
e.printStackTrace();
}
}
}
...
But the docs say execute must be invoked on the UI thread, and I'm calling it from the BLE callback. Is that a problem? And how should I fix it?
The framework triggers the AsyncTask callback methods on the same thread it was called from (presumed to be the main thread). It doesn't really affect the background work, but you could see problems if you started trying to use onPostExecute() and the like. AsyncTask probably isn't the best choice to be called from a thread that you don't have control over.
Why does the Thread not work and how can I fix it?
I can't say exactly why you are still seeing errors, through spawning a series of private unsynchronized threads will probably lead to other headaches. If you want to use a single worker thread, a better choice would be to use a single HandlerThread that you can post to from your event callbacks using a Handler, something like:
…
_workerThread = new HandlerThread("Worker");
_workerThread.start();
_handler = new Handler(_workerThread.getLooper(), new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
String str = (String) msg.obj;
_writer.write(str);
return true;
}
});
…
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
…
Message msg = Message.obtain(_handler, 0, strBuild.toString());
_handler.sendMessage(msg);
…
}
That solution is quite a bit more code, but given the frequency of writes this is probably the most efficient choice.
The IntentService never goes to the onHandleIntent(). What are the issues here?
You should pretty much never implement a top level Android component (activity, service, content provider, receiver) as an inner class, because they have to be declared in your manifest as well (and the XML syntax for inner classes is ugly). If your service does not have a matching entry in the manifest, then you will never see it start. You might want to have a look at the docs on using services.
At a minimum, a Service written as an inner class must be public static to work. Otherwise the framework cannot see it and cannot instantiate it using a default constructor (non-static inner classes mess with the constructor). Unless you are calling startService() inside of a try/catch right now, I'm surprised it isn't crashing when you attempt this.
IntentService is probably the simplest of your three choices because it is the most decoupled and the framework will handle queueing up work and tearing down the threads when all the incoming work is done.

Handlers and multiple Activities

Ok, I am new to android, I'm trying to create an app that interfaces with an arduino via bluetooth. I've seen the sample BluetoothChat and seen how it's using an Handler to communicate between the "service", the threads spawned by it and the MainActivity.
My problem is that I have more than one Activity that needs to use the Bluetooth Service.
For each Activity I have an Handler like this:
mHandler = new Handler(){
#Override
public void handleMessage(Message message) {
switch (message.what){
case BtService.CHANGE_STATE:
if (message.arg1 == BtService.STATE_CONNECTING){
Intent i = new Intent (MainActivity.this,ConnectedActivity.class);
startActivity(i);
}
break;
}
}
};
and in the service constructor I've got this:
private BtService(){
btm = BluetoothAdapter.getDefaultAdapter();
mHandler= new Handler(Looper.getMainLooper());
}
and when I need to send a message I do this:
private synchronized void setState(int state){
mHandler.obtainMessage(CHANGE_STATE, state, -1).sendToTarget();
mState = state;
}
but the messages aren't received in the various other Handlers.
In here is stated that "all of the Handler objects for a particular thread receive the same message." so I can't understand the problem.
Do I need, every time an activity is started, to pass to the service the Handler declared in that Activity to have it receive messages? This seems to work, but it dosen't seem to be a good practice for me.
If you want send the message in all application you should use BroadcastReceiver, I this this is the best way in your case.
Intent intent = new Intent(ApplicationConstants.MY_MESSAGE);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
Receive message in any activity(you cand use this in more then one activity)
BroadcastReceiver connectionUpdates = new BroadcastReceiver() {
#Override
public void onReceive(Context arg0, Intent intent) {
...//TODO here
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(
connectionUpdates ,
new IntentFilter(ApplicationConstants.MY_MESSAGE));
Hope this is helpfull
Cheers,
Instead of having each activity connect through bluetooth, you can extend the Application layer and use that to maintain thread(s) to retrieve and manage the data collected over the bluetooth connection. Then just use a handler in each activity to have them refresh against the data gathered in the Application layer, if needed.
My only Activity with the btAdapter and socket is the first activity to actually need bluetooth information (after menus and bt config activities).
In my first activity onRusume() looks something like this with comments explaining..:
#Override
public void onResume() {
super.onResume();
Log.d(TAG, "...onResume - try connect...");
// Set up a pointer to the remote node using it's address.
BluetoothDevice device = btAdapter.getRemoteDevice(address);
// Two things are needed to make a connection:
// A MAC address, which we got above.
// A Service ID or UUID. In this case we are using the
// UUID for SPP.
try {
btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
errorExit("Fatal Error", "In onResume() and socket create failed: " + e.getMessage() + ".");
}
// Discovery is resource intensive. Make sure it isn't going on
// when you attempt to connect and pass your message.
btAdapter.cancelDiscovery();
// Establish the connection. This will block until it connects.
Log.d(TAG, "...Connecting...");
try {
btSocket.connect();
Log.d(TAG, "....Connection ok...");
} catch (IOException e) {
try {
btSocket.close();
} catch (IOException e2) {
errorExit("Fatal Error", "In onResume() and unable to close socket during connection failure" + e2.getMessage() + ".");
}
}
// Create a data stream so we can talk to server.
Log.d(TAG, "...Create Socket...");
/**
* **Here I am kicking off the thread in the application that retrieves all data
* needed by all my activities. Then it stores the information in its member
* variables. Each activity then refreshes as often as needed, gets the data from
* the application layer it needs and does some logic on it.**
*/
if(mConnectedThread == null) {
mConnectedThread = app.new ConnectedThread(btSocket);
mConnectedThread.start();
}
// This kicks off the handler for this activity that refreshes the activity every
// xxxx ms and checks the data retrieved from bt in the application layer.
startUpdatingTicketView();
}
That is pretty much the core of how i got it to work for me.
Just an additional note... I also tried doing this with the bt communication managed in a background service and could not get it working well. I forget exactly what the issues I was running into were and it is quite possible using a service would work as well, but I did not end up going this route.
Good luck.

How can i design tcp messages listener in my Android client?

i'm a newbie for Android.
I'm working on a client(android)-server(java) arcitecture application for my project. I have questions..
My 4-5 activities will send tcp messages to server and get response to do something to their own. So i need a background listener for these messages and then do something in these 4-5 activities. Where can i implement this listener thread to response my different actitivies. Is it a good way to write 5 AsyncTask in subclass of these Activites to messaging Server?
I think 1 thread can do the work; but how can i bind the activites..
Is it the service that im talking about? But i dont want to do something when my app destroys.
I have written a very similar application and use a singleton to do the work. When your activity is created, call Listener.getInstance() to get the instance of the Listener. If it has not been created, create it.
In the Listener object, create a thread to do all the socket communication. When a message becomes available, post it back to the main GUI thread using a handler (or some other synchronization mechanism).
public class Listener implements Runnable, Callback
{
String ipAddress;
int ipPort;
private listener = null;
Handler handler;
public Listener
{
handler = new Handler(this);
}
public Listener getInstance()
{
if (listener == null)
listener = new Listener()
return listener;
}
public void connect()
{
thread = new thread();
thread.run(this);
}
public void run()
{
socket = new Socket();
socket.connect(new InetSocketAddress(ipAddress, ipPort));
//do your thread/socket work...
//when a message is available via the socket, post the message back to the main GUI thread using a handler.
Message msg = new Message();
//fill the msg with data
handler.sendMessage(msg);
}
#Override public boolean handleMessage(Message msg)
{
//hand message to current activity
}
}
A great socket example can be found here:http://thinkandroid.wordpress.com/2010/03/27/incorporating-socket-programming-into-your-applications/
As an alternative, you could do all this work in a service. I just chose this path when I started. It has worked well for me.

Thread only loops once

ive been thinking about this for hours and im not closer to an solution!
My thread just stops looping when im fetching a message from an server for some reason, and works perfectly when im not doing it.
This works and prints refreshing every second:
public class ChatRoom extends Activity implements OnClickListener, Runnable {
private Thread t = new Thread(this);
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chatroom);
Button send = (Button) findViewById(R.id.send);
send.setOnClickListener(this);
Intent receiver = getIntent();
String host = receiver.getStringExtra("Host");
int port = receiver.getIntExtra("Port", 4456);
try
{
socket = new Socket(host, port);
this.receive = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
this.send = new PrintWriter(this.socket.getOutputStream(), true);
}
catch(IOException ioe) { System.out.println(ioe); }
t.start();
}
public void run()
{
String message = "";
while(true)
{
try
{
// message = receive.readLine(); BufferedReader
t.sleep(1000);
}
//catch(IOException ioe) { System.out.println(ioe); }
catch (NullPointerException npe) { System.out.println(npe); }
catch (InterruptedException e) { System.out.println(e); }
System.out.println("Refreshing...");
}
}
And when i use my commented code, it actually works and i get a message from the server but it loops just once! Why is that?
Output:
Server Message
Refreshing...
I get no Exception or errors, but i had an error before with some similar code that said that i cant change UI on other threads. So ive been looking at some runOnUiThread but it didnt make it better, and i dont know why it should :(
The method BufferedReader.readLine() blocks until a newline character is received. If there is no newline in your receiver stream it will block forever.
A few things here:
Swap from System.out.println("string"); to Log.d("tagname","string"); then look on DDMS for output lines.
I don't think you're creating a thread properly, and you certainly aren't providing any interface to kill it, which may cause issues when you test it. I would separate the thread into a new file, say NameOfThread:
//File "NameOfThread"
public class NameOfThread extends Thread{
//any fields you want here to mess with e.g.
private String message;
private boolean running;
public NameOfThread(){
message = "";
running = true;
}
#Override
public void run(){
while(running){
//do stuff
}
}
public void setRunning(boolean run){
running = run;
}
}
//When you want to call it
NameOfThread varThread = new NameOfThread();
varThread.start();
//when you want to kill the thread
varThread.setRunning(false);
You may think 'why bother with this whole running variable junk, I don't need it.' but how else will this thread end gracefully? There is another method of killing the thread properly, which is using InterruptedException and your cleanup code goes there, but that's just an alternative.
Try doing this first, then you'll need to sort out the message itself (the method you're using currently isn't great since readLine() will block until a line is received (meaning you'll get "Refreshing..." when you get a new line rather than once per second.
You're surely getting some exceptions thrown, you just can't see them cause you're trying to print them on the standard output, which is missing on Android. Your exception is handled correctly and the code finishes. To properly get the exception information use Logs, or just throw a RuntimeException. Hope this helps.

Categories

Resources