I have an Android app with three threads, the main thread and two worker threads. The threads need to communicate with each other regularly.
I had originally gone about doing this in a horrible way that everyone here would yell at me for. I saved instances of the thread in each thread and called methods of the class from the other threads if a thread needed that functionality. It worked, but I knew it wasn't right.
Since that was wrong, I went back through and changed each instance of a thread to an instance of the thread's handler, and each thread function call I replaced with a handler.sendMessage call.
Now the program doesn't work. It just freezes, and I have no idea whats going on. When using the debug perspective, I step through the main thread but all I get is the function
boolean hasMessages(Handler h, int what, Object object)
{
...
}
from the MessageQueue. The other threads are looping in their run() function which doesn't do anything exciting. None of my logs are printing. I am at a loss for what is happening and I don't know what steps I should take next to continue debugging it. All I changed was adding handlers and sending messages. Can you guys suggest any next steps I should take for debugging?
Edit: Here is some code, I'm having no luck
Main Activity:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
connectionStatusTextView = (TextView) findViewById(R.id.connectionStatus);
imageView = (ImageView) findViewById(R.id.imageView);
commandView = (TextView)findViewById(R.id.commandView);
focusView = (TextView)findViewById(R.id.focusView);
mApplication = ((myApplication) this.getApplication());
ConnectedThread connectedThread = new ConnectedThread(mHandler, mApplication);
VoiceRecognitionThread voiceThread = new VoiceRecognitionThread(mApplication, this);
connectedThread.setHandlers(mHandler, voiceThread.getHandler());
voiceThread.setHandlers(mHandler, connectedThread.getHandler());
connectedThread.start();
voiceThread.start();
}
ConnectedThread and VoiceRecognitionThread both extend HandlerThread. They both create a class level Handler which handles messages sent to those threads. getHandler returns a reference to those handlers.
Just use a HandlerThread and feed it with messages via its handler object:
HandlerThread thread1 = new HandlerThread("Thread Name");
thread1.start();
handler1 = new MyHandler(thread1.getLooper());
// pass message for thread 1
handler1.sendmessage()
// and same for threads 2 and 3
Note that if you plan your threads to be long running, a far better
solution would be to use an IntentService.
IntentService are services and, as such, are by far less susceptible to
Android reclamation then resources gets low.
Related
I have a socket server that uses an ExecutorService to create a new thread for each new socket. I also have a static instance of a class that makes database calls that all threads use.
My server is used for online chess matches. When a user makes a move, the move is sent to the server and an entry is made in the DB with general information about the move (including the ID of the match). Every 10 seconds or so, if the match's other client also has an active socket to the server, it will ask the server to fetch all new data about the match.
It works, but as you can imagine gets pretty inefficient if a non-trivial number of players are connected. What I want is a way for a thread to peek into the thread pool and find another thread based off an ID (The ID of the client for whom the thread is used), then call a method on that thread to send a message to the opposing player.
I've been looking all over, and I've had no luck. Is such a thing possible? If it is, is it advisable? Even if it's a bit risky code-wise, I'm willing to take extra steps to mitigate the risk for the enormous resource-saving benefits.
Like I said in my comment, your question is confusing; if all you're trying to do is to notify the opponent when a player makes a move, the simplest implementation is to use a BlockingQueue. The Javadoc even has code examples, so it should be fairly easy to implement. In your case, whenever a player makes a move, you put an item in the queue, that the consumer picks up and notifies the opponent that is participating in the same game. You don't need to mess with low level thread constructs, and if you're even thinking of finding threads based on ids from a pool, you're doing it all wrong.
The BlockingQueue would work, but it involves busy wait, so I'm not a big fan of it. Instead, you can use the Observer design pattern; the JDK already has support for this. Following is an example that I made up:
public class Main extends Observable implements Observer {
private final int numCores = Runtime.getRuntime().availableProcessors();
private final ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(numCores);
public Main() {
addObserver(this);
}
public static void main(String[] args) throws InterruptedException {
new Main().execute();
}
private void execute() {
for (int i = 0; i < 5; ++i) {
this.setChanged();
this.notifyObservers(i);
try {
Thread.sleep(1000l);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
executor.shutdown();
}
#Override
public void update(Observable o, Object arg) {
System.out.printf("Received notification on thread: %s.\n", Thread.currentThread().getName());
executor.submit(() -> System.out.printf("Running in thread: %s, result: %s.\n",
Thread.currentThread().getName(), arg));
}
}
Received notification on thread: main.
Running in thread: pool-1-thread-1, result: 0.
Received notification on thread: main.
Running in thread: pool-1-thread-2, result: 1.
Received notification on thread: main.
Running in thread: pool-1-thread-3, result: 2.
Received notification on thread: main.
Running in thread: pool-1-thread-4, result: 3.
Received notification on thread: main.
Running in thread: pool-1-thread-5, result: 4.
Last but not the least, if you really want to take it up a notch, use messaging. You didn't mention if you're using a framework (again, lack of information on your part), but Spring supports messaging, so does Akka, Play and Camel.
You may create the ExecutorService supplying your own ThreadFactory able to create your istantiate your own class that extends Thread and has a reference to the ThreadFactory itself. The ThreadFactory should trak all created Thread and be able to identify them by their ID. Such a way, each Thread will be able to query the ThreadFactory for some ID.
I have programmed a structure that works like this:
Activity discoveryActivity - UI thread
↕ Calls through interface
Service discoveryService - Bound service running on UI thread
↕ Actions through Handler.post(↑) or functions (↓)
Runnable connectionThread - Socket networking
At some point the connectionThread needs a String to continue.
So I make a call with Handler.post(..) to the discoveryService which
notifies the discoveryActivity to show an AlertDialog
The user needs about 20 seconds to input the data and will confirm the input.
Problem 1: What will the thread do in the meantime?
Now I need to make my way down to the Thread again.
Getting to discoveryService is easy
Problem 2: How can I get the thread working again without restarting? The thread is in a complex loop with a few Sockets right now!
My first idea was to keep the thread running
// Inside run()
while(stringWrapper.get() == null) {
Thread.sleep(500);
}
// Outside run()
void setStr(String s) { stringWrapper.set(s); }
But that is inefficient
Then I read about wait() and notify()
I tried that on the thread itself and on the StringWrapper (A simple class that holds a reference to a String)
I am helpless right know and I think wait() and notify() are the right way to go?
Can you give me a hint where I should implement these and on which object they would be called?
TL;DR: I want to let a thread pause until it receives data
Not 100% sure what you're trying to accomplish, but you may be able to use a SettableFuture (from Google Guava library) to solve your issue.
private final SettableFuture<String> stringFuture = SettableFuture.create();
// Inside run()
// This will block your thread until stringFuture is set, or until the given timeout has expired.
final String string = stringFuture.get(1, TimeUnit.MINUTES);
// Outside run()
public void setStr(final String s) {
stringFuture.set(s);
}
I am developping an Android application which is supposed to manage a simple TCP connection through the Socket class. However, due to the fact that we cannot use network on the UI thread, I have to detach all network communication to a separate thread.
Basically, I have:
My activity, the layout of which contains a TextView. The TextView is suppose to hold the connection log: messages I send, and those I receive from the server.
My Runnable connection class, to which I associated a socket, and a few others methods to handle message reception. Everything in there runs in a separate thread.
Now, the tricky part is connecting the two. Since the messages do not arrive on the same thread as the UI runs, I cannot update the UI from the "network thread". If I do, I get an expectable...
CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Now, this means that instead of "sending" the messages to the TextView, I should wait for them in the Activity. Basically, in my onCreate...
public void onCreate(Bundle savedInstanceState) {
private MyConnectionClass connection;
super.onCreate(savedInstanceState);
// Set up the activity, the UI listeners, and so on...
TextView myTextView = (TextView)findViewById(/* ... */);
String serverMessage;
while((serverMessage = connection.waitForMessage()) != null)
myTextView.setText(myTextView.getText() + "\n" + message);
}
Here, we can assimilate MyConnectionClass to a Socket around which I added a few methods (it does not inherit Socket once implemented). Basically, waitForMessage() blocks until a message is received, and returns it when it arrives.
However, the problem here is that the waiting is done on the UI thread, and since I'm in onCreate, my activity hangs and never shows up.
I've tried a few solutions such as the Observable class and the Observer interface, but it does not eliminate the problem, since notifyObservers is called by the network thread, meaning that the UI update (done in Observer.update()) fails (CalledFromWrongThreadException).
I also tried waiting on another thread started by the activity, but quickly realised I would get the result as above... Besides, I'm not sure I really need to create again another new thread.
Considering that the UI thread is the only one which can modify the TextView, and since I cannot really afford to "freeze" my UI, is there a way I could have my network thread update the UI's TextView asynchronously when messages arrive?
In your Activity Oncreate Method or any appropriate method, where you need to start the network operation, add this line.
new NetworkOperation().execute("");
Add this class
private class NetworkOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
// Do your network connection
return "Value";
}
#Override
protected void onPostExecute(String result) {
TextView txt = (TextView) findViewById(R.id.YOURTEXTVIEW);
txt.setText("Executed"); // txt.setText(result);
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(Void... values) {}
}
I've a Service that is called from an Activity with this code:
startService(new Intent(AMC_Activity.this,CallService.class));
Service is running good for about 20-30 minutes, but after that service stop running, I know that I can use 'foreground' service, but by using that I should show a notification, so, is there any other way to prevent service stop running?
I am not sure but i think you are starting your service from UI thread and after that you are putting your in application background so after sometime your activity instance getting lost and that UI thread also killed at that time.
Solution
Create a new Thread and start service with that Thread instead of UI Thread, because service is doing work on that Thread whoever Thread is invoking it.
//This code will be in class body.
private Thread thread1 = new Thread(){
public void run(){
startService(new Intent(AMC_Activity.this,CallService.class));
}
}
//Now this code will be call when you are going to start the service, i.e. Under onCreate()
thread1.start();
It may helpful to you.
If you use a TaskManager App on your device you should take care that it doesn't kill your app and/or service too.
in my class I have an inline thread in the constructor that loads objects from a remote site:
Thread readSite = new Thread(new Runnable() {
public void run() {
site.loadStuff();
}
});
readSite.start();
I want to display a 'loading' message until the thread is finished. So before the above code I show a loading message.
After the above code I show the screen in which I would like to continue.
The code looks like this:
showLoadingView(); //tells the user it is waiting
Thread readSite = new Thread(new Runnable() {
public void run() {
site.loadStuff();
}
});
readSite.start();
showStuffView(); //works with the data retrieved from the site instance
Now, the main thread of course continues and the showStuffView() is directly executed.
I can now let the main thread wait for the readSite Thread, but then the user cannot accept the connection request ('is it ok to use airtime?') that is shown to the user (because the responsible thread is asleep I guess).
On the other side, I cannot execute the showStuffView() from the readSite Thread.
I hope you guys can explain how to wait for this thread. I looked into synchronized, but couldn't really find a nice solution.
I think this is a common problem with threads and this particular problem you can solver with boolean variable. but for general purpose i think observer pattern is good.