Calling a child thread method from parent thread - android

I have started a child thread from my parent thread (main/UI thread). And from this child thread I start another thread (grandchild?). Now I want to be able to pass a string from my main thread to my grandchild thread so I can call a method in the grandchild thread using this string.
As I am new to Java and threads this confuses me. I have looked at message handlers etc. but don't know if that is the way to go or not as I can't find an example that I understand.

Normally we don’t and cannot pass values among threads in java. We share values and objects among threads. There is a very subtle difference among sharing and passing values among threads. If You somehow pass a value to a Thread then that Thread will have exclusive right over it i.e thread will have its own copy of the value and we don’t need to worry about unsynchronized code or thread safety of that variable. We normally use this type of concept
in concurrent system using message passing.
Please see: https://en.wikipedia.org/wiki/Message_passing
But in Java We normally share values among multiple threads. And there is no relationships among threads i.e is there is no child or grand child threads. There are only deamon and non-deamon threads (http://www.javaworld.com/jw-04-1996/jw-04-threads.html).
So if you have to share some value between grand child and main thread. you have to make a single Object which is available/share among them. Please see the below example :
public class GranDChildThread {
/**
* Please note there are no relation ships among thread.
* Simply put, a thread is a program's path of execution.
* All the three threads have access to shared String
*/
public static String sharedString = new String("its a wonderfull life");
public static void main(String[] args) {
// this is my main Thread
System.out.println("Main Thread: I have access to
sharedString : " + sharedString);
Thread childThread = new Thread(new Runnable() {
#Override
public void run() {
// this is child thread
System.out.println("Child Thread:
I have access to sharedString : " + sharedString);
Thread grandChildThread = new Thread(new Runnable() {
#Override
public void run() {
// this grand Child
System.out.println("Grand Child Thread:
I have access to sharedString : " + sharedString);
}
});
}
});
}
}

Here is the simplest example. Using setters and getters can come handy.
import android.os.Bundle;
import android.util.Log;
public class MyExtendedThread extends Thread{
private String mData;
public MyExtendedThread(String dataStringIwantToPass){
this.mData = dataStringIwantToPass;
}
#Override
public void run() {
//DO SOMETHING WITH mData
//for example:
while(true){
if(mData != null)
Log.i("mData: ", mData);
Thread.sleep(2000);//sleep it few seconds :)
}
}
public String getData() {
return mData;
}
public void setData(String mData) {
this.mData = mData; //you might want to change the value at some point of time
}
}
Here we inherit the Thread class to our custom class that will have setters and getters and argumented constructor. Thats pretty straight forward. We will use the setter to change the value of the string at any time we want.
#Override
public void onCreate(Bundle savedInstanceState ) {
final String data = "this is string";
Thread theThreadStartedFromUIthread = new Thread(new Runnable(){
MyExtendedThread myOtherThread = new MyExtendedThread(data);
#Override
public void run() {
// Do some stuff
myOtherThread.start();// the other (grandchild) thread has started
//here i want to change the value of mData, assuming the thread is still running
myOtherThread.setData("Alright, I've changed you.");
}});
};
}
Is it helpful?

Related

Replacing global variable and synchronized block with realm

I rephrased the question in order not to confuse people on what I am really doing. The example used in the original question was way too simplified.
My project is client/server based. The android app is the client. To properly simply the situation, we can think about that I have two intents/activities and one background thread. Activity A is login . Activity B is where the rest of the app is. The background thread is a socket thread, and it needs to be kept up all the time until user exits the app, or network connection is interrupted.
A state machine is implemented to handle the app states, and this state machine is required by all activities, and the socket thread.
Singleton easily meets the requirement of my design, but there will be a lot of synchronized block and wait statement. I wonder is it possible to use realm to achieve the same goal
Original Question
I am new to Realm Java (Android) development. In my current code, I have a bunch of global variables and using them in a few AsyncTask or background threads.
I'll use some code here to demostrate my example
//Class holding global variable
public class GlobalInfo{
public static String info;
}
//Class changing the global variable
class A{
void doSomething(){
String info = GlobalInfo.info;
info = "start";
synchronized(info){
...... //do something
info = "done";
info.notifyAll();
}
}
}
//background thread waiting for info to be "done". Neglecting the class holding it
void doSomethingAfterDone(){
String info = GlobalInfo.info;
synchronized(info){
while(!info.Equals("done")){
info.wait();
}
//do something
}
}
Assume that when doSomethingAfterDone() is called, the method doSomething() is still running. Therefore, the doSomethingAfterDone() will be waiting for doSomething() to notify before exiting the while loop.
Is it possible to use Realm to replace them? For example, using a realm transaction + a listener waiting for change, rather than applying synchronized block on the global variable and wait for its notification?
I found Realm.waitForChange() will block the execution until there is a changed made to it. However, do all changes that apply to any objects registered or copied to realm returns true for this statement, regardless what get changed?
I know that I can pass String between intents, but I want to know if it is feasible that realm can do the job.
Well you generally don't need global variables at all. You can just write to the Realm on the background thread, and listen for change on the UI thread.
//Class holding global variable
//public class GlobalInfo{
//public static String info;
//}
//Class changing the global variable
class A{
void doSomething(){
//String info = GlobalInfo.info;
//info = "start";
//synchronized(info){
try(Realm realm = Realm.getDefaultInstance()) {
realm.executeTransaction(new Realm.Transaction() { // assuming background thread
#Override
public void execute(Realm realm) {
//!! do something with Realm
}
});
}
new Thread(new Runnable() { // could be merged to this background thread
#Override
public void run() {
doSomethingAfterDone();
}
}).start();
//info = "done";
//info.notifyAll();
//}
}
}
//background thread waiting for info to be "done". Neglecting the class holding it
void doSomethingAfterDone(){
//String info = GlobalInfo.info;
//synchronized(info){
//while(!info.Equals("done")){
// info.wait();
//}
try(Realm realm = Realm.getDefaultInstance()) {
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
//do something
}
});
}
//}
}

Is it right if I read view on other thread,Android UI

Android can't update view direct on non-ui thread,but if I just read/get some information for ui?
For example I have a method updateModel() like
void updateModel() {
dailyReport.log.setValue(editLog.getText().toString());
dailyReport.plan.setValue(editPlan.getText().toString());
dailyReport.question.setValue(editQuestion.getText().toString());
}
Is it a problem if I run this method on non-ui thread.
Example below helped me solve this problem. Hope this will help you too
runOnUiThread(new Runnable() {
#Override
public void run() {
//do your job
}
});
Is it a problem if I run this method on non-ui thread?
With the assumption that dailyPlan is a model class and its methods do not modify the UI, then no, it is not a problem, Android will not complain and you will not receive any runtime errors. However, I would not follow this approach as in general it's a bad practice to access directly one threads data from another thread - you never know who is modifying what, read/write issues can occur and so on. These are usually solved by synchronizing the data, but if you put synchronized code in UI thread you made things even worse!
For your kind of problem, why don't you pass the data from UI controls to the thread that uses above logic? When you create it, pass the 3 strings:
editLog.getText().toString()
editPlan.getText().toString()
editQuestion.getText().toString()
Example:
private EditText editLog;
private EditText editPlan;
private EditText editQuestions;
private void activityMethodThatStartsThread() {
String log = editLog.getText().toString();
String plan = editPlan.getText().toString();
String questions = editQuestions.getText().toString();
DailyReportModel model = new DailyReportModel(log, plan, questions);
model.start();
}
public class DailyReportModel extends Thread {
private String log;
private String plan;
private String questions;
public DailyReportModel(String log, String plan, String questions) {
super();
this.log = log;
this.plan = plan;
this.questions = questions;
}
void updateModel() {
dailyReport.log.setValue(log);
dailyReport.plan.setValue(plan);
dailyReport.question.setValue(questions);
}
}
Yes you can Update the UI from a Non UI thread. There are two ways of doing this.
1) Do this with activity object (easy option get and Update)
2) Do this using Message Handler (a bit difficult and Update only)
Going for the 1st one all you need to do is Pass the Activity into the constructor. Here is Thread snippet
public class MyThread extends Thread {
private Activity _activity;
public MyThread(Activity activity) {
this._activity = activity;
}
#Override
public void run() {
super.run();
//do all what you want. and at the end to Update the Views Do this
if(!this._activity.isFinishing())
{ // executed if the activity is not finishing
this._activity.runOnUiThread(new Runnable() {
#Override
public void run() {
//set the public variables UI Variables like this
dailyReport.log.setValue(this._activity.editLog.getText().toString());
dailyReport.plan.setValue(this._activity.editPlan.getText().toString());
dailyReport.question.setValue(this._activity.editQuestion.getText().toString());
});
}
}
}
Now in the Activity
MyThread thread = new MyThread(this);
thread.start;

CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views

I'm doing a manipulation in database in an IntentService, and in the Activity im showing a CustomProgressBar, but I want to show also the percentage value. So, for that I get the percentage value in the IntentService and set this value in a static method in the Activity. But the error show up:
CalledFromWrongThreadException: Only the original thread that created
a view hierarchy can touch its views.
I dont want to do this operation in an AsyncTask becaus I don't want to block the UI, so I'm using a IntentService.
Here is how I am doing this.
MyIntentService.java
public class MyIntentService extends IntentService
{
#Override
public void onHandleIntent(Intent intent)
{
updateDatabase();
}
public void updateDatabase()
{
resetPercentage(cursor.getCount * 2)
do
{
// do operation for updating the database
// here I update the view everytime a new item is inserted in DB.
int updatedReturn = MyActivity.updatePercentageValue(percentage());
}
while(...)
}
public void resetPercentage(int elementsNum)
{
mUpdatePercentage = 0;
mMaxItems = elementsNum;
}
public int incrementPercentageCounter()
{
return ++mPercentageCounter;
}
public int percentage()
{
int value = (mPercentageCounter/mMaxItems)*100;
return (value > 100) ? 100 : value;
}
}
MyActivity.java
public class MyActivity extends Activity
{
private TextView mMyTextView;
#Override
public void onCreate(Bundle bundle)
{
super.onCreate(bundle);
mMyTextView = (TextView) findViewById(R.id.textview);
}
public static int updatePercentageValue(int percentageValue)
{
mMyTextView.setText("" + percentageValue + " %");
return 1;
}
}
Any Idea of how can I solve this problem or do this operation using my IntentService so the UI wont be blocked.
Obs: I want to keep using IntentService also because a lot of things is done, and I dont want to change all over again.
Thanks!
An AsyncTask won't block the UI. You should probably use it. The kind of thing you're trying to do is exactly what it's good for. The AsyncTask doesn't need to exist outside of your Activity, it's short-lived work (relatively), and your work needs to update this UI. An AsyncTask seems more appropriate than a Service here.
Doing things in an async task is specifically to not block the UI thread. It even has an on progress method to do exactly what you want to do wih updating the UI. Gven that you don't want to do that, but you need to look into the running method.
Looking at this code I am somewhat confused as to how it works since you are accessing a member variable in a static method.

Can a Runnable return a value?

Is it possible for a Runnable to return a value? I need to do some intensive work on an Editable and then return it back. Here is my mock code.
public class myEditText extends EditText {
...
private Editable workOnEditable() {
final Editable finalEdit = getText();
Thread mThread = new Thread(new Runnable() {
public void run() {
//do work
//Set Spannables to finalEdit
}
});
mThread.start();
return finalEdit;
}
...
}
So obviously my first problem is I'm trying to change finalEdit, but it has to be final in order to access it in and out of the thread, right? What's the correct way to do this?
In Java, a Runnable cannot "return" a value.
In Android specifically, the best way to handle your type of scenario is with AsyncTask. It's a generic class so you can specify the type you want to pass in and the type that is returned to the onPostExecute function.
In your case, you would create an AsyncTask<Editable, Void, TypeToReturn>. Something like:
private class YourAsyncTask extends AsyncTask<Editable, Void, Integer> {
protected Long doInBackground(Editable... params) {
Editable editable = params[0];
// do stuff with Editable
return theResult;
}
protected void onPostExecute(Integer result) {
// here you have the result
}
}
The following exists simply to point out the use of "pseudo-closures" in Java, as unsuitable as they may be in this case.
Java allows pseudo-closures through mutable-types stored in final variables.
See Java's pseudo-closures by Christopher Martin skip to the "Faking it" section. He introduces a mutable-type ValueHolder<T>:
private static class ValueHolder<T> {
T value;
}
...
final ValueHolder<Integer> i = new ValueHolder<Integer>();
...
i.value = 42;
Happy coding.
You realize that the thread keeps working past the end of the workOnEditable() function, right? If you want a synchronous response, get rid of the thread. If not, use a Handler to pass the data back to the main thread.
I have made 2 utility methods around Runnable that enable you to post a runnable and block until you get the result.
You can take a look here: https://github.com/Petrakeas/HVTHandler/

Android - howto pass data to the Runnable in runOnUiThread?

I need to update some UI and do it inside of the UI thread by using runOnUiThread
Now the data for the UI comes from the other Thread, represented by data here.
How can i pass the data to the Runnable, so tht they can be used to update the UI?
Android doesn't seem to allow using data directly. Is there an elegant way to do this?
public void OnNewSensorData(Data data) {
runOnUiThread(new Runnable() {
public void run() {
//use data
}
});
}
My solution was creating a fioeld private Data sensordata inside of the runnable, and assigning data to it. This works only, if the original Data data is final.
public void OnNewSensorData(final Data data) {
runOnUiThread(new Runnable() {
private Data sensordata = data;
public void run() {
//use sensordata which is equal to data
}
});
}
The problem you found is that
Inner classes in Java capture ("close over") the lexical scope in which
they are defined. But they only capture variables that are declared "final".
If this is clear as mud, there's a good discussion of the details here:
Cannot refer to a non-final variable inside an inner class defined in a different method
But your solution looks fine. In addition, provided that data is final, you could simplify the code to this:
public void OnNewSensorData(final Data data) {
runOnUiThread(new Runnable() {
public void run() {
// use data here
data.doSomething();
}
});
}
If you want to avoid using an intermediate final variable (as described by Dan S), you can implement Runnable with an additional method to set Data:
public class MyRunnable implements Runnable {
private Data data;
public void setData(Data _data) {
this.data = _data;
}
public void run() {
// do whatever you want with data
}
}
You can then call the method like this:
public void OnNewSensorData(Data data) {
MyRunnable runnable = new MyRunnable();
runnable.setData(data);
runOnUiThread(runnable);
}
you could also make MyRunnable's constructor take in the Data instance as an argument:
public class MyRunnable implements Runnable {
private Data data;
public MyRunnable(Data _data) {
this.data = _data;
}
public void run() {
...
}
}
and then just say runOnUiThread(new MyRunnable(data));
I had a similar problem where I wanted to pass information into the thread. To solve it with the android system, I modifying corsiKa's answer in: Runnable with a parameter?
You can declare a class right in the method and pass the param as shown below:
void Foo(String str) {
class OneShotTask implements Runnable {
String str;
OneShotTask(String s) { str = s; }
public void run() {
someFunc(str);
}
}
runOnUiThread(new OneShotTask(str));
}
You'll need to update every time your program has new Data it wants to show. Your second code listing here is the standard way to accomplish this. There can be some catches if you're continuing to update Data in the thread. If this is the case consider blocking the thread until the UI finishes updating or copying the data to another Data object.
What's happening internally is that the JVM is copying the reference to the Data object for when the anonymous class will run. Data stored inside can still be changed. If your method requires additional changes to Data just use another variable (object reference) such as: final Data finalData = data;. You can also remove the line private Data sensordata = data; and use data directly in your run method.
It may not look elegant but this is the way Java passes object variables to anonymous classes. There is newer syntax in Java Language version 7 but Android is compatible with Java Language version 5 and 6.
Here is a typical case where service callback is called to update a UI status string (TextView textStatus). The service may be threaded.
The sample combines checking if thread redirection is needed and the actual redirection:
// service callbacks
public void service_StatusTextChanged(final String s) {
if( isOnUiThread() ) {
textStatus.setText(s);
} else {
runOnUiThread(new Runnable() {
#Override
public void run() {
textStatus.setText(s);
}
});
}
}
static public boolean isOnUiThread() {
return Thread.currentThread() == Looper.getMainLooper().getThread();
}
See also How to check if running on UI thread in Android?
public static Activity globalContext = null;
CommonSetting.globalContext = this;// put this in MainACtivity.onCreate()
public void createToastShort(final String message) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(CommonSetting.globalContext, message, Toast.LENGTH_SHORT).show();
}
});
}

Categories

Resources