I'm performing some investigation of Realm threading and encountered issue.
In this simple example I have 2 Thread objects, one for writing and second one for reading. The reader Thread gets count of written objects always as 0, but inside writer scope the size() for items in DB is correct. When I relaunch app, the reader gets the first count ok before any insertions.
Thread writer = new Thread() {
#Override
public void run() {
while (mRunning) {
try {
Realm r = Realm.getInstance(context, "test_db");
r.beginTransaction();
TestData data = r.createObject(TestData.class);
r.commitTransaction();
Logger.e("WRITER THREAD COUNT: " +
r.where(TestData.class).findAll().size());
sleep(LATENCY);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
writer.setPriority(Thread.MAX_PRIORITY);
writer.start();
Thread reader = new Thread() {
#Override
public void run() {
while (mRunning) {
try {
Logger.e("READING THREAD COUNT: " + Realm.getInstance(context,
"test_db").where(TestData.class).findAll().size());
sleep(LATENCY);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
reader.setPriority(Thread.MAX_PRIORITY);
reader.start();
Is there something needed to do for this to work?
Thanks.
Emanuele from Realm here.
What you are describing is expected behavior :) Since the reader thread doesn't have a Looper, it has no way to receive notifications from the reader thread and will never update unless you manually execute a refresh.
In out repo we have several examples (not to mention unit tests) using threads with and without Looper, illustrating the current best practices.
Related
I am facing some problems trying to call main thread in my background thread.
Based on this post: Running code in main thread from another thread
The solution should be:
private void runOnMainThread() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// Do something
ottoBus.post(new MyObjectEvent(mMyObject));
// End do something
mMyObject = null;
}
});
}
However my background thread is still being able to read Bluetooth socket data between "Do something" and "End do something"
What am I missing here? Is it possible to lock the background thread, while "Do something" is being executed?
My code for reading socket data is following:
InputStream stream = null;
InputStreamReader reader = null;
BufferedReader bufferedReader = null;
String data = "";
try {
stream = mSocket.getInputStream();
byte[] bytes = new byte[20];
int numRead = 0;
while ((numRead = stream.read(bytes)) >= 0) {
String s = new String(bytes, 0, numRead);
if (mMyObject != null) {
fillData(s); // Can cause NPE
} else {
mMyObject = new MyObject();
fillData(s);
}
// This should be synchronised call
runOnMainThread();
Thanks.
You will need to use a Java pattern called wait/notify. Simply put: it defines two threads,
a producer and a consumer, so that the consumer, after initiating the producer, stops and waits until the producer thread has completed.
It goes like this:
static final object uiActionMonitor = new Object();
transient boolean uiCompleted;
void network_thread_run() {
int numRead = 0;
while ((numRead = stream.read(bytes)) >= 0) {
String s = new String(bytes, 0, numRead);
// This should be synchronised call
uiCompleted = false;
runOnMainThread();
synchronized(uiActionMonitor) { //<---------- wait for UI to complete
while (!uiCompleted) {
uiActionMonitor.wait();
}
}
}
And the UI code:
private void runOnMainThread() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// Do something
// End do something
uiCompleted = true;
synchronized(uiActionMonitor) { //<---------- release networking thread
uiActionMonitor.notifyAll();
}
}
});
}
Copy the synchronization logic exactly as is. This is where many developers get it wrong.
I must admit I fail to see why you need to block your networking thread while the UI thread is handling your message...
I find CountDownLatch to be the simplest way to accomplish this sort of thing. Here's a reusable method for running Runnables on the main thread and blocking on their completion:
private static final Handler mainHandler = new Handler(Looper.getMainLooper());
private static void runOnMainThreadBlocking(Runnable runnable) throws InterruptedException {
CountDownLatch completionSignal = new CountDownLatch(1);
mainHandler.post(new Runnable() {
#Override public void run() {
runnable.run();
completionSignal.countDown();
}
});
completionSignal.await();
}
I think you need to use locks or synchronized blocs. You can take a look into the java concurency documentation and more specificaly this and this part.
This way you can guaranty that on portion of the code won't be executed muliple times in parallel.
I want process the UI element while lopping.
This code is recoding streaming audio.
But code have some issues.
Application stop in while instruction. So, "Record Button" don't change.
Also, Application can user actions.(button click, etc)
I want that button is clickable and writing data to file same time.
Following the code:
PlayerActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
btnStartStopRecord.setText(R.string.button_record_stop);
try{
conn = new("Streaming URL").openConnection();
is = conn.getInputStream();
outstream = new FileOutputStream(new File(dataDir, fileName).getAbsolutePath());
int c;
while((c = is.read()) != -1) {
outstream.write(c);
}
} catch(Exception e){
e.printStackTrace();
error(e.toString());
}
}
});
The application freezes because you're executing expensive operations on the UI thread.
You need to use background thread.
See:
http://developer.android.com/guide/components/processes-and-threads.html
http://androidresearch.wordpress.com/2012/03/17/understanding-asynctask-once-and-forever/
for reference.
AsyncTask works fine in Android 4.x, but not for Android 2.3.6. I've step-by-step debugged Android 2.3.6 with a physical mobile device.
It hangs on here:
myTask = new GetDataFromServer();
GetDataFromServer is the class of AsyncTask.
What's going on?
Here under is my code, I only used 1 AsyncTask in my code and received messages from server.
that's all.
class GetDataFromServer extends AsyncTask<String, String, String>
{
protected void onPreExecute ()
{
progressDialog1=ProgressDialog.show(MainActivity.this, "Loading data", "Please wait...",true);
}
protected String doInBackground(String... params)
{
String resulttxt="";
try {
serverIp = InetAddress.getByName("192.168.1.123");
int serverPort=31000;
Socket clientSocket=new Socket(serverIp,serverPort);
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
bw.write(params[0]);
bw.flush();
BufferedReader br=new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
resulttxt=br.readLine();
if(resulttxt.contains("OK"))
{
publishProgress(resulttxt);
}
else
{
publishProgress(resulttxt);
clientSocket.close();
bw.close();
br.close();
return null;
}
resulttxt="";
resulttxt=br.readLine();
resulttxt=resulttxt.trim();
clientSocket.close();
} catch (IOException e) {
if(Status_txt!=null)
Status_txt.append( "Server is done.");
}
catch (NetworkOnMainThreadException e){
if(Status_txt!=null)
Status_txt.append( "NetworkOnMainThreadException");
}
return resulttxt;
}
protected void onProgressUpdate(String...inStr){
String[] strData=inStr[0].split("_");
String szTemp="Last Purchase Date: ";
szTemp+=strData[1];
szTemp+=" ,Valid days: ";
szTemp+=strData[2];
//Status_txt.setText(szTemp);
if(Status_txt!=null)
Status_txt.setText("You Are The Super User");
}
protected void onPostExecute(String data) {
tl_prediction2.removeAllViews();
if (data == null)
{
}
else {
if((data.contains("#")==true) || (data.contains("*")==true)
||data.contains("&")==true)
{
String[] arrayTmp=data.split("#");
for(Integer i=0;i<arrayTmp.length;i++)
{
String[] SubArrayTmp=arrayTmp[i].split("_");
tl_prediction2.addView(generateRow(4,SubArrayTmp));
}
}
}
progressDialog1.dismiss();
}
};
Since you haven't posted any code, I could only give you some random probable solutions:
May be your AsyncTask is taking a lot of time to download. Trying increasing its priority using android.os.Process.setThreadPriority(9) inside doInBackground()
Check if you have other previous running long AsyncTask in your code. AsyncTask by default operates on a single background thread. That means your AsyncTask task wouldn't be executed unless your previous AsyncTask are done. To allow parallel execution use executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params). You can read more here
Check for Internet and other permissions in Manifest. This is mostly where people make mistake.
AsyncTask works with ThreadPool. If there too many synctasks are executing, the later AsyncTask will be blocked by others. I think you can use the thread tool in DDMS to check the How many ayncTasks are executing.
Hi I have a service in Android that handles the HTTP method POST as specified below. Now, I need to call an Intent in
replaceResourceSegment()
method. It has a handler that takes nearly 90 seconds to complete the task. Within that time, control exits the handler block. But I want my program to continue within handler for POST. In short, I want my service to pause for sometime inside the POST handler, till my Intent (with handler) completes its execution and I need to delay sending the response of HTTP Post. Can some one guide me how to do this implementation?
if(method.equals("POST"))
{
conn.receiveRequestEntity((HttpEntityEnclosingRequest)request);
HttpEntity entity = ((HttpEntityEnclosingRequest)request).getEntity();
String content_type = ""+entity.getContentType();
JSONReceived = EntityUtils.toString(entity);
if(content_type.contains("json"))
{
Log.d(TAG,"Content received is: "+JSONReceived);
bufferedWriter = new BufferedWriter(new FileWriter(new File(getFilesDir()+File.separator+constants.UPDATED_SCRIPT_FILE)));
bufferedWriter.write(JSONReceived);
bufferedWriter.close();
try {
parseJSON(JSONReceived);
replaceResourceSegment(); //Call to an intent with startActivityForResult()
continueExecution(); //Continue the execution from here
} catch (IOException e) {
e.printStackTrace();
Log.d(TAG,"IOException line 157");
}
Code for sending response back:
HttpResponse postResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
postResponse.setEntity(new StringEntity("Got it"));
conn.sendResponseHeader(postResponse);
conn.sendResponseEntity(postResponse);
I managed to solve the problem by using a boolean variable with default value false. It will be checked periodically and keeps the control inside the POST method's handler.
android.os.SystemClock.sleep(30000); //Sleeps for 30 seconds and invoke busy waiting in a thread
Thread syncThread = new Thread(new LoopCheck());
syncThread.start();
synchronized(syncThread)
{
Log.d(TAG,"Inside synchronized blockk");
try
{
syncThread.wait();
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
The thread class is defined as below:
class LoopCheck extends Thread{
public LoopCheck(){
}
public void run(){
while(true)
{
try {
Thread.sleep(10000);
if(write)
{
write = false;
synchronized(syncThread)
{
syncThread.notify();
}
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Im having some trouble reading/writing to a tcp server for which im building an app. In a recent thread I was suggested to use a service instead but this is a project for school which suggested asyncTask so I might aswell go for that.
So the classes ive got are my activity class and async, nothing interesting is going on in activity but sending a string which is working so ill get on with the async one.
class ServerTask extends AsyncTask<Void, Void, Void>{
public static String ip = "10.0.2.2";
public static int port = 2002;
Socket socket;
public DataInputStream dis;
public DataOutputStream dos;
public String message;
#Override
protected Void doInBackground(Void... params) {
try {
socket = new Socket(ip, port);
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
} catch (Exception e) {
Log.i("AsyncTank", "Cannot create Socket");
}
while(socket.isConnected()){
read();
}
}
}
return null;
}
public void write(String message) {
try {
if (socket.isConnected()){
dos.writeUTF(message);
dos.flush();
} else {
Log.i("AsynkTask", "Socket appears to be closed");
}
} catch (Exception e) {
Log.i("AsynkTask", "Writing failed");
}
}
public String read() {
try {
if (socket.isConnected()) {
message = dis.readLine();
} else {
Log.i("AsyncTask", "Cannot read");
}
} catch (Exception e) {
Log.i("AsyncTask", "Cannot read from stream");
}
return message;
}
}
Things I do know, the server DOES get the messages but it doesnt update until I restart the server which leads me to believe that im not pushing a new line or something which makes it all appear as one line after its closed. This however might aswell be the server for which im not reponsible so ill have to read up in that.
The read part however does not want to work, im not sure on how to call the method to have it constantly listen and react to the servers sockt? I tried make a thread just before the return in doInBackGround but then the application starts works for a couple of seconds the force closes due to lack of memory? Do I need a thread to keep constantly listen?
The whole point of this as you might guess is to make a chat so the read method is eventually supposed to update a textView in my activity class. The send method is "working" but not as it should though this might be as I said earlier the server doing some funky buisness.
Another one, is it even possible to have the read as a method like I have or does something have to react when the server sends data and then call the method?
Edit
I have now moved the read part, or atleast some of it to doInBackGround so its now
dis = new BufferedReader(new InputStreamReader(socket.getInputStream()));
message = dis.readLine();
Log.i("AsynkTask", "Read : "+message+" this is doInBackGround!");
This along with a change to simply hardcode a printline in the server made me read that line in the client so im guessing its working realtively good for now.
How is it looking? Is it utter crap this code and should be done some other way? Got my functionality but never bad to learn to do it better so to speak :).
You should do both your writing and reading to the Socket in an AsyncTask's doInBackground() method, as both take time and could block the main (UI) thread. I don't know how you are calling your write() method above but you might also want to take a look at this question that might be related.