Variable in Runnable - android

I create a Runnable in my class :
private Runnable monRun = new Runnable() {
public void run() {
Log.i("PLAY", "" + play);
if(play) {
/* [...] */
}
}
};
Here, play is an instance variable of my class.
But, when I call my Runnable :
handler.postDelayed(monRun, 100);
the variable play is captured in Runnable and if I changed value in an other method of my class, play will not be changed in my Runnable

Variables in per-object implementations and lambda expressions always get copied, cause in the meanwhile those variables may even get out of scope and just die. Make them copy a reference to an object then.
I suggest you to enclose your variable play in an object, and pass that object to the Runnable:
class ObjectToPass {
boolean play;
public synchronized boolean getPlay() {
return play;
}
public synchronized void setPlay(boolean play) {
this.play = play;
}
}
... // play is a ObjectToPass
private Runnable monRun = new Runnable() {
public void run() {
Log.i("PLAY", "" + play.getVar());
if(play.getVar()) {
/* [...] */
}
}
};
The synchronized keyword is to avoid problems with thread safety on the play member. If the Runnable is called in the same thread you can (and you should) just avoid synchronized.
I also suggest you to pass a reference to the ObjectToPass via the constructor of a class conforming to Runnable, instead of using the per-object implementation. This will help you handle data better:
class MyRunnable implements Runnable {
private ObjectToPass play;
public MyRunnable(ObjectToPass play) {
this.play = play;
}
#Override public void run() {
...
}
}

This is happening because you have play instance variable in your main thread and you are updating this variable in different thread.

Related

Mockito: Runnable.run() of Runnable parameter passed to a method is not called

I am testing with Mockito. I Have a callback interface:
interface Callback {
void onMessageRetrieved(String message);
void onRetrievalFailed(String error);
}
Then, I have a method that accepts Runnable object that calls that Callback method:
Firstly, interactor.run() calls this method that calls postMessage:
#Override
public void run() {
final String message = mMessageRepository.getWelcomeMessage();
if (message == null || message.length() == 0) {
notifyError();
return;
}
postMessage(message);
}
private void postMessage(final String msg) {
mMainThread.post(new Runnable() {
#Override
public void run() {
mCallback.onMessageRetrieved(msg);
}
});
}
But line mCallback.onMessageRetrieved(msg); is never executed and so I get:
Wanted but not invoked:
callback.onMessageRetrieved(
"Welcome, friend!"
);
Why is run() not executed?
I am working with the project from this articles. This is my Test class:
public class ExampleUnitTest {
private MessageRepository mMessageRepository;
private Executor mExecutor;
private MainThreadImpl mMainThread;
private WelcomingInteractor.Callback mMockedCallback;
#Before
public void setUp() {
mMessageRepository = mock(MessageRepository.class);
mExecutor = mock(Executor.class);
mMainThread = mock(MainThreadImpl.class);
mMockedCallback = mock(WelcomingInteractor.Callback.class);
}
#Test
public void testWelcomeMessageFound() throws Exception {
String msg = "Welcome, friend!";
when(mMessageRepository.getWelcomeMessage()).thenReturn(msg);
WelcomingInteractorImpl interactor = new WelcomingInteractorImpl(
mExecutor,
mMainThread,
mMockedCallback,
mMessageRepository);
interactor.run();
Mockito.verify(mMessageRepository).getWelcomeMessage();
Mockito.verifyNoMoreInteractions(mMessageRepository);
Mockito.verify(mMockedCallback).onMessageRetrieved(msg);
}
}
Here:
mMainThread.post(new Runnable()
But in your unit test, you have:
mExecutor = mock(Executor.class);
mMainThread = mock(MainThreadImpl.class);
That post() call receives a Runnable object. And I assume that your impl class runs Runnable.run() in some thread.
But: within your unit test, you are mocking all those elements.
You have to understand: mMainThread = mock(MainThreadImpl.class); doesn't create a real MainThreadImpl object. It returns something that looks like an object of that class; but this is a mock. It is completely decoupled from your actual implementation. When you do mMainThread.poll() ... nothing will happen. That run method is never executed. Because the mock object does nothing about that parameter when you invoke poll() on it.
In other words: you have to configure all your mocks. For example you can use an ArgumentCaptor and capture the Runnable object given to the post() method.
But of course, as that will be just some instance of an anonymous inner class, this will not help too much.
Long story short: you should step back; and do some more reading how/why you use mock objects...

Will handler inside a method leak memory?

I know handler declared in a class may leak memory since it holds a reference to its outer class. In this case, we should use static nested class with weak reference.
But What if a handler is declared inside a method. I faced below case and not sure is it a correct implementation. Could someone please explain or give me a hint? I even don't know what I should search for.
private void methodA(){
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
methodB();
}
}, 10*1000);
private void methodB(){
//textView holds a reference to a activity
textView.setText("hello");
}
It can under certain conditions. If the runnable passed is an anonymous or inner class, as in your example, it holds an implicit reference to 'this' and prevents 'this' from being garbage collected until the runnable is processed off the queue (so if your method never runs, like if your handler thread gets stopped without clearing the queue, it will leak).
In the case where you are worried about the conditions for a memory leak occurring or hanging onto objects too long, then you need to make your runnable a static class that has a weak reference initialized in the constructor, something like:
private static MyRunnable implements Runnable
{
private final WeakReference<MyClass> myClass_weakRef;
public MyRunnable(MyClass myClassInstance)
{
myClass_weakRef = new WeakReference(myClassInstance);
}
#Override
public void run()
{
MyClass myClass = myClass_weakRef.get();
if(myClass != null)
myClass.methodB();
}
}
private void MethodA()
{
Handler handler = new Handler();
handler.postDelayed(new MyRunnable(this), 10*1000);
}
Creating a Handler inside your method isn't a special case. It falls under the same circumstances, in that the Message you post will live in the message queue until it's processed.

Handlers and memory leaks in Android

Please have a look at the code below:
public class MyGridFragment extends Fragment{
Handler myhandler = new Handler() {
#Override
public void handleMessage(Message message) {
switch (message.what) {
case 2:
ArrayList<HashMap<String,String>> theurls = (ArrayList<HashMap<String,String>>) message.obj;
urls.addAll(theurls);
theimageAdapter.notifyDataSetChanged();
dismissBusyDialog();
break;
}
}
}
}
When I use handler like this I get a warning "handler should be static, else it is prone to memory leaks." Can someone tell me what is the best way to do this?
I recently updated something similar in my own code. I just made the anonymous Handler class a protected inner class and the Lint warning went away. See if something like the below code will work for you:
public class MyGridFragment extends Fragment{
static class MyInnerHandler extends Handler{
WeakReference<MyGridFragment> mFrag;
MyInnerHandler(MyGridFragment aFragment) {
mFrag = new WeakReference<MyGridFragment>(aFragment);
}
#Override
public void handleMessage(Message message) {
MyGridFragment theFrag = mFrag.get();
switch (message.what) {
case 2:
ArrayList<HashMap<String,String>> theurls = (ArrayList<HashMap<String,String>>) message.obj;
theFrag.urls.addAll(theurls);
theFrag.theimageAdapter.notifyDataSetChanged();
theFrag.dismissBusyDialog();
break;
}//end switch
}
}
MyInnerHandler myHandler = new MyInnerHandler(this);
}
You may have to change where I put "theFrag." as I could only guess as to what those referenced.
Here's a somewhat useful little class I made that you can use. Sadly it's still quite verbose because you can't have anonymous static inner classes.
import java.lang.ref.WeakReference;
import android.os.Handler;
import android.os.Message;
/** A handler which keeps a weak reference to a fragment. According to
* Android's lint, references to Handlers can be kept around for a long
* time - longer than Fragments for example. So we should use handlers
* that don't have strong references to the things they are handling for.
*
* You can use this class to more or less forget about that requirement.
* Unfortunately you can have anonymous static inner classes, so it is a
* little more verbose.
*
* Example use:
*
* private static class MsgHandler extends WeakReferenceHandler<MyFragment>
* {
* public MsgHandler(MyFragment fragment) { super(fragment); }
*
* #Override
* public void handleMessage(MyFragment fragment, Message msg)
* {
* fragment.doStuff(msg.arg1);
* }
* }
*
* // ...
* MsgHandler handler = new MsgHandler(this);
*/
public abstract class WeakReferenceHandler<T> extends Handler
{
private WeakReference<T> mReference;
public WeakReferenceHandler(T reference)
{
mReference = new WeakReference<T>(reference);
}
#Override
public void handleMessage(Message msg)
{
if (mReference.get() == null)
return;
handleMessage(mReference.get(), msg);
}
protected abstract void handleMessage(T reference, Message msg);
}
Per the ADT 20 Changes, it looks like you should make it static.
New Lint Checks:
Check to make sure that Fragment classes are instantiatable. If you accidentally make a
fragment innerclass non-static, or forget to have a default constructor, you can hit runtime
errors when the system attempts to reinstantiate your fragment after a configuration change.
Look for handler leaks: This check makes sure that a handler inner class does not hold an
implicit reference to its outer class.
If you read docs about AccountManager or PendingIntent, you will see that some methods take Handler as one of arguments.
For example:
onFinished - The object to call back on when the send has completed, or null for no callback.
handler - Handler identifying the thread on which the callback should happen. If null, the callback will happen from the thread pool of the process.
Imagine the situation. Some Activity calls PendingIntent.send(...) and put the non-static inner subclass of Handler. And then activity is destroyed. But inner class lives.
Inner class still holds a link to destroyed activity, it cannot be garbage-collected.
If you're not planning to send your handler to such methods, you have nothing to worry about.
I run into the same issue and I find that it is one of this topics with many questions and few answeres. My solution is simple and I hope it can help someone:
/* BEFORE */
private Handler mHandler= new Handler() {
#Override public void handleMessage(Message msg) {
this.doSomething();
};
};
We can create a static Handler subclass that simply runs a Runnable. The actual handler instance will know what to do through the runnable that will have access to instance variables.
/* AFTER */
static class RunnableHandler extends Handler {
private Runnable mRunnable;
public RunnableHandler(Runnable runnable) {
mRunnable = runnable;
}
#Override public void handleMessage(Message msg) {
mRunnable.run();
};
}
private RunnableHandler mHandler = new RunnableHandler(new Runnable() {
#Override public void run() {
this.doSomething();
} });
The warning is gone while the funcionality is the same.
A simple solution for this case might be:
Handler handler=new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message message) {
//do your stuff here
return false;
} });

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

Android how to runOnUiThread in other class?

In my application, in MainActivity, there is a thread which works fine. But when I call another class to get data from the server I can't run on a thread. See code example below.
class MainActivity extends Activity implements Runnable {
public void onCreate() {
new Thread(this).start();
}
public void run() {
//here is code for download data from server after completion this and in handler i m call other class in setdata() method....
}
public void setData() {
new CheckData(this);
}
}
class CheckData {
public CheckData(Context context) {
context.runUIonthread(){//cant call as runUIthread............
}
}
See the article Communicating with the UI Thread.
With Context in hand, you can create a Handler in any class. Otherwise, you can call Looper.getMainLooper(), either way, you get the Main UI thread.
For example:
class CheckData{
private final Handler handler;
public Checkdata(Context context){
handler = new Handler(context.getMainLooper());
}
public void someMethod() {
// Do work
runOnUiThread(new Runnable() {
#Override
public void run() {
// Code to run on UI thread
}
});
}
private void runOnUiThread(Runnable r) {
handler.post(r);
}
}
Here's a solution if you don't want to pass the context:
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
// code goes here
}
});
Activity is a class that extends Context. So there is no need to pass both context and activity. You may pass activity as context and then you can use the context to run on UI thread as follows:
((Activity) context).runOnUiThread(new Runnable() {
public void run() {
//Code goes here
}
});
Word of Caution: Only use this when you're sure that context is an activity context, and it's not a good practice to assume that.
class MainActivity extends Activity implements Runnable{
public void oncreate(){
new Thread(this).start();
}
public void run(){
//here is code for download data from server after completion this and in handler i m call other class in setdata() method....
}
public void setdata();
{
new checkData(this,MainActivity.this);
}
}
class checkData{
public void checkdata(Context context,MainActivity mainactivity){
mainactivity.runUIonthread()..is works fine for me.....
}
}
You might want to take a look at AsyncTask. Even though it's not the best solution, it will help you get started.
http://developer.android.com/reference/android/os/AsyncTask.html
EDIT
I don't see why using an AsyncTask is not a solution for you but anyway. You can hold a Handler class that is initialized in the UI thread. Then using this Handler you can post back messages to the UI in the form of a runnable. So all you need to do is instantiate a new Handler object when you are in the UI thread (before you start your new one) and then share that with your other class. When you are done, you can use that instance to post a message back to the UI thread using the post method. Check out the documentation of the Handler class for more details:
http://developer.android.com/reference/android/os/Handler.html
If someone's looking for an Rx based solution:
Observable.just(true)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(aBoolean -> {
// cool stuff comes here
});

Categories

Resources