Replacing global variable and synchronized block with realm - android

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
}
});
}
//}
}

Related

Android: questions about manually handling configuration changes while thread runs

I am trying to update my app to handle configuration changes (especially screen turning) manually.
I have some questions about what happens when changes happen during a Thread execution.
I have created an abstract class I call ThreadTask which uses Threads and Handlers to the main thread's looper to send updates to the main thread. This is my implementation of AsyncTask but with threads, I prefer this to using AsyncTask because I have more control over it.
It also has two methods to register an observer to the above events, it uses this interface:
public interface TaskObserver {
void pre_execute();
void on_progress(ProgressData progress);
void finished(Object result);
void cancelled(Object result);
}
The abstract members that the subclass must implement are :
abstract Object do_in_background();
and some concrete members are:
synchronized void add_observer(TaskObserver observer){
_observers.add(observer);
}
synchronized void remove_observer(TaskObserver observer){
_observers.remove(observer);
}
synchronized void post_execute(Object result) {
int observers = _observers.size();
for (int idx = 0; idx < observers; idx++) {
_observers.get(idx).finished(result);
}
}
///plus all the other methods of the interface
So when I implement a concrete class it would go something like this:
public class MyThreadTask extends ThreadTask{
#Override
Object do_in_background() {
progress.primary_max = 5;
for (int cur = 0 ; cur < 5 ; cur++) {
progress.primary = cur;
publish();
Thread.Sleep(3000);
}
}
}
and I updated the activity that calls this like so:
static final string TAG ="my_main_activity";
MyDataFragment _data; //this is a datafragment, a fragment with retaininstancestate , and a public `MyThreadTask task` variable
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (_data == null) {
_data = (MyDataFragment)getFragmentManager().findFragmentByTag(TAG + "_data");
if (_data == null) {
_data = new MyDataFragment();
getFragmentManager().beginTransaction().add(_data, TAG + "_data").commit();
}
}
if (_data.task != null) {
_data.task.register(this);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if (_data.task != null) {
_data.task.remove(this);
}
}
this makes sure that I always have a reference to the correct thread
When I wish to start the task I do it like so:
button.setOnClickListener((v) -> {
if (_data.task != null) return; //to make sure only one thread starts at a time
_data.task = new MyThreadTask();
_data.task.register(this);
_data.task.start(); //this is not thread's start, it is mine, it does other things too
})
and when the thread finishes it calls void finished(Object result) which I handle like so:
void finished(Object result) {
try {
//get result;
} finally {
_data.task.remove(this);
_data.task = null;
}
}
here are my questions:
a) is declaring my observer methods as synchronized necessary? I did it just to make sure , but when the activity is destroyed and then recreated, does it happen on the same thread? is there a chance for example that a progress_update may happen while an observer is being removed during onDestroy?
b) what will happen if a thread finishes and calls post_execute(which is important) during a configuration change? will the update be lost?
c) If indeed the update is lost because it currently has no observers, is there a way, either in my implementation or a different one, to handle the above?
Thanks in advance for any help you can provide
The preferred way to keep a background task alive through a configuration change is by hosting it in a retained fragment. The same instance of the fragment will persist through the configuration change. When the fragment is paused, check the activity's isChangingConfigurations and cancel the task only if it's false.
I don't know if this is documented anywhere, but it seems that the entire configuration change is posted to the main thread so that nothing else can run between pausing the old activity and resuming the new one. If you were using an AsyncTask in a retained fragment, you would be assured that its onPostExecute could not run during the configuration change. With your approach, the task could easily complete when there is no observer.
Asynctask does not handle configuration changes that well. I think, instead of Asynctask you should use AsynctaskLoader which can handle the config changes easily and it behaves within the life cycle of activities/fragments.
When you run AsyncTask and if the android system kills your activity/fragment(during config changes or memory conservation) then your doInBackground() method still keeps on running in the background and this can lead to undesirable results.
Therefore, instead of using AsyncTask you can use AsynctaskLoader or if you are populating data from SQLite then you can use CursorLoader.
References:
Guideline to choose among AsyncTaskLoader and AsyncTask to be used in Fragment
https://developer.android.com/reference/android/content/AsyncTaskLoader.html

How to implement a "fire-and-forget" async call in Android?

I am reviewing/cleaning up some Android code. The code did some "asynchronous" network and data operations using this pattern:
new Thread() { public void run() { { ... runOnUiThread( { .. } ) }
A lot. With all the ugly consequences (no error checks, Sleeps, boolean finish variables...).
Till now, I ended up using (few) AsyncTasks and (more) Loaders as replacements.
Now I have stumbled upon a couple of "fire-and-forget" network communications: the code (currently, a Thread, as always) calls a web service posting some data.
I do not need to know if the data was received, and I do not need to know if there was any error.
Which is the best way of doing this? A Runnable or AsyncTask (static nested class, so I do not "leak" a reference to "this" activity?)
Or is there something better (more "lightweight" and cleaner?)
If you don't need to know when task execution is finished then you definitely don't need AsyncTask at all. Therefore the most lightweight solution is just a Thread. You can use Executor which will create threads for you. To get rid of nested classes you could predefine tasks. Sample:
Predefined task:
public static class TaskA implements Runnable{
private int someParam;
public TaskA(int someParam) {
this.someParam = someParam;
}
#Override
public void run() {
//
}
}
Static Executor
public static class FireAndForgetExecutor{
private static Executor executor = Executors.newFixedThreadPool(5);
public static void exec(Runnable command){
executor.execute(command);
}
}
And usage:
FireAndForgetExecutor.exec(new TaskA(10));
PS don't forget that a Thread is connected to the GC root! So if you pass heavy object like an activity or a bitmap into the task it could lead to memory leak.

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;

Calling a child thread method from parent thread

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?

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.

Categories

Resources