I'm trying to use this article to create asynchronous UDP socket.
So I've this code:
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UdpThread
extends HandlerThread {
private static final String TAG = "UDP";
private final Handler uiHandler, workerHandler;
private final DatagramSocket socket = new DatagramSocket();
public UdpThread(final Handler uiHandler, final String hostname, final int port) throws SocketException {
super(TAG);
this.uiHandler = uiHandler;
start();
workerHandler = new Handler(getLooper(), new Handler.Callback() {
#Override
public boolean handleMessage(final Message msg) {
/*
if (msg.what == port && msg.obj == hostname) {
final InetSocketAddress address = new InetSocketAddress(hostname, port);
Log.d(TAG, "Connecting to " + address);
try {
socket.connect(address);
} catch (SocketException se) {
throw new RuntimeException(se);
}
}
*/
msg.recycle(); //java.lang.IllegalStateException: This message cannot be recycled because it is still in use.
return true;
}
});
workerHandler.obtainMessage(port, hostname).sendToTarget();
}
}
But when I run the code, I get the mentioned java.lang.IllegalStateException: This message cannot be recycled because it is still in use. when trying to recycle the message. Why is that and how to solve it and prevent memory leaks?
Well first of all lets see how Message recycle() method works.
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
recycleUnchecked();
}
So you are getting IllegalStateException if it is in use
isInUse() just checks flag and looks like:
boolean isInUse() {
return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
}
And when we try to read about that flag we see description:
If set message is in use.
This flag is set when the message is enqueued and remains set while it
is delivered and afterwards when it is recycled. The flag is only
cleared when a new message is created or obtained since that is the
only time that applications are allowed to modify the contents of the
message.
It is an error to attempt to enqueue or recycle a message that is
already in use.
So what we have
You cant recycle message until its "in use"
It is "in use" until new message obtained or created
How to solve the problem
There is method recycleUnchecked() inside Message class to recycle message object even if it is in use.Thats what you need! Description of it:
Recycles a Message that may be in-use.
Used internally by the MessageQueue and Looper when disposing of
queued Messages.
Worst thing that it uses internally and has package access. Good thing that it uses internally when you call:
handler.removeMessages(int what)
So I guess final solution is:
replace
msg.recycle();
to
try {
msg.recycle(); //it can work in some situations
} catch (IllegalStateException e) {
workerHandler.removeMessages(msg.what); //if recycle doesnt work we do it manually
}
You shouldn't call msg.recycle() yourself, message is recycled automatically by Looper after it has been dispatched/processed (after your handleMessage() returns), see source code.
Try to use AsyncTask to delete the message when the handler thread finish to proceed it.
//[..]
//synchronized with the handler thread
#Override
public boolean handleMessage(final Message msg) {
new MessageDestructor().execute(msg);
return true;
}
//[..]
private class MessageDestructor extends AsyncTask<Message, Void, Void> {
Message msg;
#Override
protected String doInBackground(Message... params) {
msg = (Message) params[0];
return null;
}
#Override
protected void onPostExecute(Void result) {
msg.recycle(); //synchronized with the main thread
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
Related
i am making an android socket app to communicate with the server for creating accounts, and i noticed i have to do this in AsyncTask sub class, even when i seperate it to another class without UI,but i am terribly confused how can i use AsyncTask on this, is there any one expert here who can help me please?
this is the code:
public class AccountCreator extends Activity {
public AccountCreator(){
super();
}
// for I/O
ObjectInputStream sInput; // to read from the socket
ObjectOutputStream sOutput; // to write on the socket
Socket socket;
public static String LOGTAG="Lifemate";
public String server = "localhost";
public String username = "user";
public String password = "rezapassword" ;
public int port = 1400;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(LOGTAG,"oncreate called");
this.start();
}
AccountCreator(String server, int port, String username,String password) {
this.server = "localhost";
this.port = 1400;
this.username = username;
Log.i(LOGTAG,"first accountcreator called");
}
public boolean start() {
// try to connect to the server
//this method returns a value of true or false when called
try {
socket = new Socket(server, port);
}
// if it failed not much I can so
catch(Exception ec) {
// display("Error connectiong to server:" + ec);
Log.i(LOGTAG,"Error connectiong to server:" + ec);
return false;
}
String msg = "Connection accepted " + socket.getInetAddress() + ":" +
socket.getPort();
// display(msg);
Log.i(LOGTAG, msg);
/* Creating both Data Stream */
try
{
sInput = new ObjectInputStream(socket.getInputStream());
sOutput = new ObjectOutputStream(socket.getOutputStream());
}
catch (IOException eIO) {
// display("Exception creating new Input/output Streams: " + eIO);
Log.i(LOGTAG,"Exception creating new Input/output Streams: " +
eIO);
return false;
}
// creates the Thread to listen from the server
// Send our username to the server this is the only message that we
// will send as a String. All other messages will be ChatMessage objects
try
{
sOutput.writeObject(username);
sOutput.writeObject(password);
}
catch (IOException eIO) {
// display("Exception doing login : " + eIO);
Log.i(LOGTAG,"Exception doing login : " + eIO);
disconnect();
return false;
}
// success we inform the caller that it worked
return true;
}
// private void display(String msg) {
// TextView screenprint = (TextView)findViewById(R.id.systemmessages);
// screenprint.setText(msg);
// }
private void disconnect() {
Log.i(LOGTAG,"reached disconnect");
try {
if(sInput != null) sInput.close();
}
catch(Exception e) {} // not much else I can do
try {
if(sOutput != null) sOutput.close();
}
catch(Exception e) {} // not much else I can do
try{
if(socket != null) socket.close();
}
catch(Exception e) {} // not much else I can do
}
public void Begin() {
Log.i(LOGTAG,"it begun");
int portNumber = 1400;
String serverAddress = server;
String userName = username;
String newpassword = password;
AccountCreator accountcreator = new AccountCreator(serverAddress, portNumber,
userName,password);
if(!accountcreator.start())
return;
}
}
i was trying to put whole code in Async, i dont know if was i right, do i need to do that also or just some parts of it?
In brief, AsyncTask contains a few methods which may be helpful:
onPreExecute:
This method is the first block of code executed when calling asyncTask.execute(); (runs on mainUIThread).
doInBackground:
Here you put all the code which may suspend you main UI (causes hang for your application) like internet requests, or any processing which may take a lot of memory and processing. (runs on background thread), contains one parameter taken from the asyncTask.execute(ParameterType parameter);
onPostExecute
Runs after doInBackground(). Its parameter is the return value of the doInBackground function, and mainly you put the changes in UI need to be done after the connection is finished (runs on mainUIThread)
You have to declare another class within the class you have already created.
class SomeName extends Async<Void, String, Void>{
protected void OnPreExecute(){
// starts the task runs on main UI thread
// Can be used to start a progress dialog to show the user progress
}
#Override
protected Void doInBackground(Void... params){
// does what you want it to do in the background
// Connected to the server to check a log-in
return result;
}
protected void OnPostExecute(Void result){
// finishes the task and can provide information back on the main UI thread
// this would be were you would dismiss the progress dialog
}
}
I use a worker thread to read text from a url. My thread is as follow. In the first time running, I am sure thread running is finished as I can check sdcard_readstr is null.
In the second time running, when I call thread_download.start();, then the program crashed.
What could be wrong? Thanks
public class DownloadingThread extends AbstractDataDownloading {
#Override
public void doRun() {
// TODO Auto-generated method stub
try {
// Create a URL for the desired page
URL url = new URL(SDcard_DetailView.textfileurl);
// Read all the text returned by the server
BufferedReader in = new BufferedReader(new
InputStreamReader(url.openStream()));
do{
sdcard_readstr = in.readLine();
}while(sdcard_readstr!=null);
in.close();
} catch (MalformedURLException e) {
} catch (IOException e) {
}
}
}
public abstract class AbstractDataDownloading extends Thread{
private final Set<ThreadCompleteListener> listeners
= new CopyOnWriteArraySet<ThreadCompleteListener>();
public final void addListener(final ThreadCompleteListener listener) {
listeners.add(listener);
}
public final void removeListener(final ThreadCompleteListener listener) {
listeners.remove(listener);
}
private final void notifyListeners() {
for (ThreadCompleteListener listener : listeners) {
listener.notifyOfThreadComplete(this);
}
}
#Override
public final void run() {
try {
doRun();
} finally {
notifyListeners();
}
}
public abstract void doRun();
}
EDIT1:
In my thread complete notification, I use runOnUiThreadto use the UI components.
Is that causing problem?
public void notifyOfThreadComplete(Thread thread) {
// TODO Auto-generated method stub
if(downloadingStopbuttonispressed == false){//background process completed
textfileurl = null;
this.runOnUiThread(new Runnable() {
public void run() {
Wifibutton = (Button) findViewById(R.id.Wifiscanning);
Wifibutton.setText("Load another day's data");
final MenuItem refreshItem = optionsMenu.findItem(R.id.airport_menuRefresh);
refreshItem.setActionView(null);
}
});
}
}
I called thread start in onResume() as
#Override
protected void onResume() {
super.onResume();
if(textfileurl != null){
Wifibutton.setText("Stop Data Loading");
buttonStatus = "loading";
setRefreshActionButtonState(true);
thread_download.start();
}
}
EDIT2:
My LogCat image is attached.
My solution is here . I can't reuse the same instance of the Thread object in the second time. I need to create a new instance to call the Thread in the second time. So Thread is suitable for single time running process, for multiple time running process I should use AsyncTask. Even AsyncTack is only for one time execution and for multiple time execution, we should use as new MyAsyncTask().execute(""); I don't understand why people downvote with no reason given. I couldn't find the link in my first search.
My Android app should do the following:
The MainActivity launches another thread at the beginning called UdpListener which can receive UDP calls from a remote server. If it receives a packet with a content "UPDATE", the UdpListener should notify the MainActivity to do something.
(In the real app, the use case looks like this that my app listens on the remote server. If there is any new data available on the remote server, it notifies every client (app) by UDP, so the client knows that it can download the new data by using HTTP).
I tried to simulate this in an JUnit test. The test contains an inner class which mocks the MainActivity as well as it sends the UDP call to the UdpListener:
public class UdpListener extends Thread implements Subject {
private DatagramSocket serverSocket;
private DatagramPacket receivedPacket;
private boolean running = false;
private String sentence = "";
private Observer observer;
private static final String TAG = "UdpListener";
public UdpListener(Observer o) throws SocketException {
serverSocket = new DatagramSocket(9800);
setRunning(true);
observer = o;
}
#Override
public void run() {
setName(TAG);
while (isRunning()) {
byte[] receivedData = new byte[1024];
receivedPacket = new DatagramPacket(receivedData, receivedData.length);
try {
serverSocket.receive(receivedPacket);
}
catch (IOException e) {
Log.w(TAG, e.getMessage());
}
try {
sentence = new String(receivedPacket.getData(), 0, receivedPacket.getLength(), "UTF-8");
if ("UPDATE".equals(sentence)) {
notifyObserver();
}
}
catch (UnsupportedEncodingException e) {
Log.w(TAG, e.getMessage());
}
}
}
private boolean isRunning() {
return running;
}
public void setRunning(boolean running) {
this.running = running;
}
#Override
public void notifyObserver() {
observer.update();
}
}
This is the corresponding test:
#RunWith(RobolectricTestRunner.class)
public class UdpListenerTest {
private MainActivityMock mainActivityMock = new MainActivityMock();
#Before
public void setUp() throws Exception {
mainActivityMock.setUpdate(false);
}
#After
public void tearDown() throws Exception {
mainActivityMock.setUpdate(false);
}
#Test
public void canNotifyObserver() throws IOException, InterruptedException {
UdpListener udpListener = new UdpListener(mainActivityMock);
udpListener.setRunning(true);
udpListener.start();
InetAddress ipAddress = InetAddress.getByName("localhost");
DatagramSocket datagramSocket = new DatagramSocket();
DatagramPacket sendPacket = new DatagramPacket("UPDATE".getBytes(), "UPDATE".length(), ipAddress, 9800);
datagramSocket.send(sendPacket);
datagramSocket.close();
assertTrue(mainActivityMock.isUpdate());
udpListener.setRunning(false);
}
private class MainActivityMock implements Observer {
private boolean update = false;
#Override
public void update() {
update = true;
}
public boolean isUpdate() {
return update;
}
public void setUpdate(boolean update) {
this.update = update;
}
}
}
The good thing is that my concept works. But, this test doesn't. That means it only does when I stop with a breakpoint at this line datagramSocket.close(); and wait for about a second. Why this happens is clear. But how can I do that automatically? I thought about using wait() but I have to invoke notify() from the other thread for that. The same problem with CountDownLatch. I'm not sure how to solve that without changing UdpListener.
You could write a simple loop with a specified timeout.
try {
long timeout = 500; // ms
long lastTime = System.currentTimeMillis();
while(timeout > 0 && !mainActivityMock.isUpdate()) {
Thread.sleep(timeout);
timeout -= System.currentTimeMillis() - lastTime;
lastTime = System.currentTimeMillis();
}
} catch(InterruptedException e) {
} finally {
assertTrue(mainActivityMock.isUpdate());
}
By the way - you should declare your running attribute to volatile.
one solution would be to use a blocking queue with size 1 for storing your received results.
The request for isUpdate (which would take an element from the blocking queue) would block until the update package(or any other package) is put into the queue.
is case you want all your calls to be non-blocking you could use a Future for receiving your result. Future.get() would block ontil your result is received.
I seem to be having trouble with updating a TextView from a thread. I have a GameConnection class (which manages a socket connection) which I want to use across activities. It calls a local "onMessage", which then uses the target handler to call dispatch Message. The "Handler" in this case, is in my GameBrowser activity.
Here's code from the GameConnection class.
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
String message = "".intern();
// as a newline character is read, we interpret it as a message
while ((message = in.readLine()) != null && isConnected){
onMessage(message);
}
As said above, a local method "onMessage" method handles dispatching of the message.
private void onMessage(String message){
... // create message from String
handler.dispatchMessage( msg );
}
However, when I get the response in the GameBrowser class, I get a CalledFromWrongThreadException . Initially, I was using a callback method, which of course wasn't working. So, after some research, I've found that I have to use a Handler, but I can't seem to get it right.
public class GameBrowser extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(C.tag, "GameBrowser.onCreate addr:" + this);
handler = new Handler(new HandlerCallback());
connection.addMessageListener(handler);
connection.connect();
txtGameLabel = (TextView)findViewById( R.id.txtGamesLabel);
setContentView(R.layout.game_browser);
}
private class HandlerCallback implements Callback{
#Override
public boolean handleMessage(Message msg) {
if (txtGameLabel == null){
txtGameLabel = (TextView)findViewById( R.id.txtGamesLabel);
}
String message = msg.getData().getString("message");
Log.d(C.tag, "GameBrowser recieved message " + message);
txtGameLabel.setText("Data: " + message);
return true;
}
}
}
I figured out what I was doing wrong. Instead of calling the handler from the socket thread, I used a callback, then used Runnable to post to the handler in the GameConnection class. When onMessage executes "run", which executes "updateTextField", we're back in the main thread.
#Override
public void onMessage(final String message) {
handler.post(new Runnable(){
#Override
public void run() {
updateTextField(message);
}
});
}
private void updateTextField(String message){
if (txtGameLabel == null)
txtGameLabel = (TextView)findViewById( R.id.txtGamesLabel);
txtGameLabel.setText(message);
}
In Handler, we can pass some data from a background thread to the UI thread like this:
private void someBackgroundThreadOperation() {
final String data = "hello";
handler.post(new Runnable() {
public void run() {
Log.d(TAG, "Message from bg thread: " + data);
}
}
}
If we use the above, we cannot then use Handler.removeCallbacks(Runnable r), because we won't have references to any of the anonymous runnables we created above.
We could create a single Runnable instance, and post that to the handler, but it won't allow us to pass any data through:
private void someBackgroundThreadOperation() {
String data = "hello";
handler.post(mRunnable); // can't pass 'data' through.
}
private Runnable mRunnable = new Runnable() {
public void run() {
Log.d(TAG, "What data?");
}
}
We can however use the Handler.removeCallbacks(mRunnable) method then, since we have a reference to it.
I know I can setup some synchronization myself to get the second method working, but I'm wondering if Handler offers any utility for passing data through to a single referenced Runnable, almost like in the example above?
The closest I can think of from browsing the docs is to use something like:
private void someUiThreadSetup() {
mHandler = new Handler(new Callback() {
#Override
public boolean handleMessage(Message msg) {
String data = (String)msg.obj;
return false;
}
});
}
private void someBackgroundThreadOperation() {
String data = "please work";
Message msg = mHandler.obtain(0, data);
mHandler.sendMessage(msg);
}
private void cleanup() {
mHandler.removeMessages(0);
}
Is this the proper way of doing it?
Thanks
IMHO, the pattern you seek is packaged as the AsyncTask class.