Non static method issue - android

After running a code inspection through android studio, it highlight that the MainHandler should be static. I move the class to static but now it complain that
"Non-Static method remainingSecondsChanged(int) cannot be referenced from a static context"
public class CountDownView extends FrameLayout {
private static void remainingSecondsChanged(int newVal) {
mRemainingSecs = newVal;
if (mListener != null) {
mListener.onRemainingSecondsChanged(mRemainingSecs);
}
if (newVal == 0) {
// Countdown has finished.
setVisibility(View.INVISIBLE);
if (mListener != null) {
mRemainingSecondsView.setText(null);
mRemainingSecondsView.setBackgroundResource(R.drawable.bracket_view_finder);
mListener.onCountDownFinished();
}
} else {
Locale locale = getResources().getConfiguration().locale;
String localizedValue = String.format(locale, "%d", newVal);
mRemainingSecondsView.setText(localizedValue);
// Schedule the next remainingSecondsChanged() call in 1 second
mHandler.sendEmptyMessageDelayed(SET_TIMER_TEXT, 1000);
}
}
public void startCountDown(int sec) {
if (sec < 0) {
return;
}
if (sec == 0) {
cancelCountDown();
}
mRemainingSecondsView.setBackgroundResource(R.drawable.bracket_count_down);
setVisibility(View.VISIBLE);
remainingSecondsChanged(sec);
}
private static class MainHandler extends Handler {
#Override
public void handleMessage(Message message) {
if (message.what == SET_TIMER_TEXT) {
remainingSecondsChanged(mRemainingSecs - 1);
}
}
}
private static final MainHandler mHandler = new MainHandler();
}
Any idea how to fix it ?

First... Why's Studio showing that message?
Background
Each Handler is associated with a Thread, and all Handler objects on the same Thread share a common Looper object, where they post and read their messages. Thing is... when these objects are non-static well... non-static inner classes hold an implicit reference to their outer class. So the Handler will hold a reference to your Activity, and if this Handler has a delayed message, your Activity will be unable to be garbage collected until this message is processed.
You can read more about it here.
Solution
As for your problem. The first thing you already did, which is make your Handler a static inner class. Now, create a WeakReference to your outer class (Could be an Activity or I believe in this case, your CountDownView).
Now try changing your Handler to something like this (Instead of Activity you could reference your CountDownView):
private static class MainHandler extends Handler {
private final WeakReference<YourActivity> mActivity;
public MainHandler(YourActivity activity) {
mActivity = new WeakReference<YourActivity>(activity);
}
#Override
public void handleMessage(Message message) {
YourActivity activity = mActivity.get();
if (activity != null) {
if (message.what == SET_TIMER_TEXT) {
activity.remainingSecondsChanged(mRemainingSecs - 1);
}
}
}
}
And instantiate it like this:
// this is a reference to your Activity, or your CountDownView, wherever your method is.
private final MainHandler mHandler = new MainHandler(this);

This StackOverflow post here Explains why the inner classes should be static and it is the pretty much same reason why the code analyzer complaints about it,Suppose If you want the members of the containing class to be accessible from your inner class you can make it non static

I am not android programmer but maybe instead of creating inner class which extends Handler than you can create private field like this:
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
//call your non static method here
}
}

Change the constructor of the MainHandler to receive a callback interface
public MainHandler(Callback cb){
this.mCallBack = cb;
}
Then at handleMessage call the callback interface to perform the method
public void handleMessage(Message message) {
if (message.what == SET_TIMER_TEXT) {
mCallBack.someMethod();1);
}
}
At fragment declare interface
public interface Callback
{
void someMethod();
}
Make your fragment implement it.
private final MainHandler mHandler = new MainHandler(this);
Then at the implementation call
remainingSecondsChanged(mRemainingSecs - 1);
This is not the best way to do it but its the fastest with your current design.

Related

get handler return null in LooperThread

public class LooperThread extends Thread {
private Handler handler = null;
public Handler getHandler() {
return handler;
}
#Override
public void run() {
Looper.prepare();
handler = new Handler();
Looper.loop();
}
}
class Helper {
private static LooperThread databaseThread = null;
static {
databaseThread = new LooperThread();
databaseThread.start();
}
public void postRunable(Runnable r) {
databaseThread.getHandler().post(r);
databaseThread.getHandler().sendMessage(new Message());
}
}
//ui thread.
class UIActivity extends Activity {
private Helper helper = new Helper();
public void onCreate(Bundle savedInstanceState) {
helper.postRunnable(new Runnable() {
public void run() {
//work asyn,like query from db.
}
});
}
}
sometimes call databaseThread.getHandler().post(r); ,it return null,sometime are not,why this?as usual,handler should be initial by static block.
You are some times getting a null Handler because calling databaseThread.start(); in the the static initializer only ensures that the thread will be started at some point in the future this means thats creating a race condition between the handler getting created inside the new thread and getHandler() being called in the old one. Having a thread with a background looper is a very common pattern in Android so there is a class to help us with this.
First get rid of your LooperThread class and use the SDK's HandlerThread instead.
Your Helper class should now look like
class Helper {
private static final HandlerThread databaseThread;
private static final Handler dbHandler;
static {
databaseThread = new HandlerThread("database thread");
databaseThread.start();
// If you have called HandelerThread#start()
// HandlerThread#getLooper() will block until the looper is initialized and Looping
dbHandler = new Handler(databaseThread.getLooper());
}
public void postRunable(Runnable r) {
dbHandler.post(r);
}
}
The getHandler method returns null because the view is not attached:
public Handler getHandler() {
if (mAttachInfo != null) {
return mAttachInfo.mHandler;
}
return null;
}
mAttachInfo is set in dispatchAttachedToWindow and nulled in dispatchDetachedFromWindow.
Instead of mapView.getHandler().post() you can use directly mapView.post() (which seems to use getHandler().post() or ViewRootImpl.getRunQueue().post()).

This Handler class should be static or leaks might occur: [duplicate]

I'm developing an Android 2.3.3 application with a service. I have this inside that service to communicate with Main activity:
public class UDPListenerService extends Service
{
private static final String TAG = "UDPListenerService";
//private ThreadGroup myThreads = new ThreadGroup("UDPListenerServiceWorker");
private UDPListenerThread myThread;
/**
* Handler to communicate from WorkerThread to service.
*/
private Handler mServiceHandler;
// Used to receive messages from the Activity
final Messenger inMessenger = new Messenger(new IncomingHandler());
// Use to send message to the Activity
private Messenger outMessenger;
class IncomingHandler extends Handler
{
#Override
public void handleMessage(Message msg)
{
}
}
/**
* Target we publish for clients to send messages to Incoming Handler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
[ ... ]
}
And here, final Messenger mMessenger = new Messenger(new IncomingHandler());, I get the following Lint warning:
This Handler class should be static or leaks might occur: IncomingHandler
What does it mean?
If IncomingHandler class is not static, it will have a reference to your Service object.
Handler objects for the same thread all share a common Looper object, which they post messages to and read from.
As messages contain target Handler, as long as there are messages with target handler in the message queue, the handler cannot be garbage collected. If handler is not static, your Service or Activity cannot be garbage collected, even after being destroyed.
This may lead to memory leaks, for some time at least - as long as the messages stay int the queue. This is not much of an issue unless you post long delayed messages.
You can make IncomingHandler static and have a WeakReference to your service:
static class IncomingHandler extends Handler {
private final WeakReference<UDPListenerService> mService;
IncomingHandler(UDPListenerService service) {
mService = new WeakReference<UDPListenerService>(service);
}
#Override
public void handleMessage(Message msg)
{
UDPListenerService service = mService.get();
if (service != null) {
service.handleMessage(msg);
}
}
}
See this post by Romain Guy for further reference
As others have mentioned the Lint warning is because of the potential memory leak. You can avoid the Lint warning by passing a Handler.Callback when constructing Handler (i.e. you don't subclass Handler and there is no Handler non-static inner class):
Handler mIncomingHandler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
// todo
return true;
}
});
As I understand it, this will not avoid the potential memory leak. Message objects hold a reference to the mIncomingHandler object which holds a reference the Handler.Callback object which holds a reference to the Service object. As long as there are messages in the Looper message queue, the Service will not be GC. However, it won't be a serious issue unless you have long delay messages in the message queue.
Here is a generic example of using a weak reference and static handler class to resolve the problem (as recommended in the Lint documentation):
public class MyClass{
//static inner class doesn't hold an implicit reference to the outer class
private static class MyHandler extends Handler {
//Using a weak reference means you won't prevent garbage collection
private final WeakReference<MyClass> myClassWeakReference;
public MyHandler(MyClass myClassInstance) {
myClassWeakReference = new WeakReference<MyClass>(myClassInstance);
}
#Override
public void handleMessage(Message msg) {
MyClass myClass = myClassWeakReference.get();
if (myClass != null) {
...do work here...
}
}
}
/**
* An example getter to provide it to some external class
* or just use 'new MyHandler(this)' if you are using it internally.
* If you only use it internally you might even want it as final member:
* private final MyHandler mHandler = new MyHandler(this);
*/
public Handler getHandler() {
return new MyHandler(this);
}
}
This way worked well for me, keeps code clean by keeping where you handle the message in its own inner class.
The handler you wish to use
Handler mIncomingHandler = new Handler(new IncomingHandlerCallback());
The inner class
class IncomingHandlerCallback implements Handler.Callback{
#Override
public boolean handleMessage(Message message) {
// Handle message code
return true;
}
}
With the help of #Sogger's answer, I created a generic Handler:
public class MainThreadHandler<T extends MessageHandler> extends Handler {
private final WeakReference<T> mInstance;
public MainThreadHandler(T clazz) {
// Remove the following line to use the current thread.
super(Looper.getMainLooper());
mInstance = new WeakReference<>(clazz);
}
#Override
public void handleMessage(Message msg) {
T clazz = mInstance.get();
if (clazz != null) {
clazz.handleMessage(msg);
}
}
}
The interface:
public interface MessageHandler {
void handleMessage(Message msg);
}
I'm using it as follows. But I'm not 100% sure if this is leak-safe. Maybe someone could comment on this:
public class MyClass implements MessageHandler {
private static final int DO_IT_MSG = 123;
private MainThreadHandler<MyClass> mHandler = new MainThreadHandler<>(this);
private void start() {
// Do it in 5 seconds.
mHandler.sendEmptyMessageDelayed(DO_IT_MSG, 5 * 1000);
}
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DO_IT_MSG:
doIt();
break;
}
}
...
}
I am not sure but you can try intialising handler to null in onDestroy()
I'm confused.
The example I found avoids the static property entirely and uses the UI thread:
public class example extends Activity {
final int HANDLE_FIX_SCREEN = 1000;
public Handler DBthreadHandler = new Handler(Looper.getMainLooper()){
#Override
public void handleMessage(Message msg) {
int imsg;
imsg = msg.what;
if (imsg == HANDLE_FIX_SCREEN) {
doSomething();
}
}
};
}
The thing I like about this solution is there is no problem trying to mix class and method variables.
If you're using Kotlin, simply remove the inner keyword when declaring the nested class.
Nested classes in Kotlin are static by default, declaring them with the inner makes them not-static.
Change your nested Handler subclass declaration from
class myService : Service() {
inner class IncomingHandler : Handler(Looper.getMainLooper()) {
/////
}
}
to
class myService : Service() {
class IncomingHandler : Handler(Looper.getMainLooper()) {
/////
}
}

Android: Calling non-static methods from a static Handler class

Given this code:
public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
public static final int MESSAGE_NOT_CONNECTED = 1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
}
// -------------------------------------------------
public final void setStatus(int Rid) {
final ActionBar actionBar = getActionBar();
actionBar.setSubtitle(Rid);
}
// -------------------------------------------------
static Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_NOT_CONNECTED:
setStatus(R.string.title_not_connected);
break;
}
}
}
}
I am getting the compile error: Cannot make a static reference to the non-static method setStatus(int) ...
Which makes sense, because getActionBar() in setStatus() is a non-static method.
I made the Handler class static because of the warning: This Handler class should be static or leaks might occur.
The question: how do I properly access the setStatus() method from within the static handler?
EDIT: new handler code is the answer.
static class hHandler extends Handler {
private final WeakReference<MainActivity> mTarget;
hHandler(MainActivity target) {
mTarget = new WeakReference<MainActivity>(target);
}
#Override
public void handleMessage(Message msg) {
MainActivity target = mTarget.get();
If(target == null) {
return;
}
switch (msg.what) {
case MESSAGE_NOT_CONNECTED:
target.setStatus(R.string.title_not_connected);
break;
}
}
}
Try using a WeakReference, as described in this article.
Since you are now using a WeakReference, mTarget.get() might return null. In your edited code, you are not checking if target is null before executing target.setStatus(R.string.title_not_connected). So this may throw a NullPointerException if the weakreference object has been GC'ed.
In my activity's onDestroy method I call:
this.myHandler.removeCallbacksAndMessages(null);
This does not get rid of the "This Handler class should be static or leaks might occur" warning, but I believe it destroys the message hence stopping the leak. My handler class is an inner non-static class of my activity. My activity has an instance of MyHandler myHandler.
When I do this, the handler's handleMessage method isn't called, which I assume means that the message containing the handler, which contained a reference to the activity was destroyed. Am open for comments as I haven't tested it with any leak testing tools. Here is where I copied the idea: http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html answerer: CyrilJanuary 15, 2013 at 7:50 AM

This Handler class should be static or leaks might occur: IncomingHandler

I'm developing an Android 2.3.3 application with a service. I have this inside that service to communicate with Main activity:
public class UDPListenerService extends Service
{
private static final String TAG = "UDPListenerService";
//private ThreadGroup myThreads = new ThreadGroup("UDPListenerServiceWorker");
private UDPListenerThread myThread;
/**
* Handler to communicate from WorkerThread to service.
*/
private Handler mServiceHandler;
// Used to receive messages from the Activity
final Messenger inMessenger = new Messenger(new IncomingHandler());
// Use to send message to the Activity
private Messenger outMessenger;
class IncomingHandler extends Handler
{
#Override
public void handleMessage(Message msg)
{
}
}
/**
* Target we publish for clients to send messages to Incoming Handler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
[ ... ]
}
And here, final Messenger mMessenger = new Messenger(new IncomingHandler());, I get the following Lint warning:
This Handler class should be static or leaks might occur: IncomingHandler
What does it mean?
If IncomingHandler class is not static, it will have a reference to your Service object.
Handler objects for the same thread all share a common Looper object, which they post messages to and read from.
As messages contain target Handler, as long as there are messages with target handler in the message queue, the handler cannot be garbage collected. If handler is not static, your Service or Activity cannot be garbage collected, even after being destroyed.
This may lead to memory leaks, for some time at least - as long as the messages stay int the queue. This is not much of an issue unless you post long delayed messages.
You can make IncomingHandler static and have a WeakReference to your service:
static class IncomingHandler extends Handler {
private final WeakReference<UDPListenerService> mService;
IncomingHandler(UDPListenerService service) {
mService = new WeakReference<UDPListenerService>(service);
}
#Override
public void handleMessage(Message msg)
{
UDPListenerService service = mService.get();
if (service != null) {
service.handleMessage(msg);
}
}
}
See this post by Romain Guy for further reference
As others have mentioned the Lint warning is because of the potential memory leak. You can avoid the Lint warning by passing a Handler.Callback when constructing Handler (i.e. you don't subclass Handler and there is no Handler non-static inner class):
Handler mIncomingHandler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
// todo
return true;
}
});
As I understand it, this will not avoid the potential memory leak. Message objects hold a reference to the mIncomingHandler object which holds a reference the Handler.Callback object which holds a reference to the Service object. As long as there are messages in the Looper message queue, the Service will not be GC. However, it won't be a serious issue unless you have long delay messages in the message queue.
Here is a generic example of using a weak reference and static handler class to resolve the problem (as recommended in the Lint documentation):
public class MyClass{
//static inner class doesn't hold an implicit reference to the outer class
private static class MyHandler extends Handler {
//Using a weak reference means you won't prevent garbage collection
private final WeakReference<MyClass> myClassWeakReference;
public MyHandler(MyClass myClassInstance) {
myClassWeakReference = new WeakReference<MyClass>(myClassInstance);
}
#Override
public void handleMessage(Message msg) {
MyClass myClass = myClassWeakReference.get();
if (myClass != null) {
...do work here...
}
}
}
/**
* An example getter to provide it to some external class
* or just use 'new MyHandler(this)' if you are using it internally.
* If you only use it internally you might even want it as final member:
* private final MyHandler mHandler = new MyHandler(this);
*/
public Handler getHandler() {
return new MyHandler(this);
}
}
This way worked well for me, keeps code clean by keeping where you handle the message in its own inner class.
The handler you wish to use
Handler mIncomingHandler = new Handler(new IncomingHandlerCallback());
The inner class
class IncomingHandlerCallback implements Handler.Callback{
#Override
public boolean handleMessage(Message message) {
// Handle message code
return true;
}
}
With the help of #Sogger's answer, I created a generic Handler:
public class MainThreadHandler<T extends MessageHandler> extends Handler {
private final WeakReference<T> mInstance;
public MainThreadHandler(T clazz) {
// Remove the following line to use the current thread.
super(Looper.getMainLooper());
mInstance = new WeakReference<>(clazz);
}
#Override
public void handleMessage(Message msg) {
T clazz = mInstance.get();
if (clazz != null) {
clazz.handleMessage(msg);
}
}
}
The interface:
public interface MessageHandler {
void handleMessage(Message msg);
}
I'm using it as follows. But I'm not 100% sure if this is leak-safe. Maybe someone could comment on this:
public class MyClass implements MessageHandler {
private static final int DO_IT_MSG = 123;
private MainThreadHandler<MyClass> mHandler = new MainThreadHandler<>(this);
private void start() {
// Do it in 5 seconds.
mHandler.sendEmptyMessageDelayed(DO_IT_MSG, 5 * 1000);
}
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DO_IT_MSG:
doIt();
break;
}
}
...
}
I am not sure but you can try intialising handler to null in onDestroy()
I'm confused.
The example I found avoids the static property entirely and uses the UI thread:
public class example extends Activity {
final int HANDLE_FIX_SCREEN = 1000;
public Handler DBthreadHandler = new Handler(Looper.getMainLooper()){
#Override
public void handleMessage(Message msg) {
int imsg;
imsg = msg.what;
if (imsg == HANDLE_FIX_SCREEN) {
doSomething();
}
}
};
}
The thing I like about this solution is there is no problem trying to mix class and method variables.
If you're using Kotlin, simply remove the inner keyword when declaring the nested class.
Nested classes in Kotlin are static by default, declaring them with the inner makes them not-static.
Change your nested Handler subclass declaration from
class myService : Service() {
inner class IncomingHandler : Handler(Looper.getMainLooper()) {
/////
}
}
to
class myService : Service() {
class IncomingHandler : Handler(Looper.getMainLooper()) {
/////
}
}

static method calls Toast.makeText

I have a thread running in C++, it will call my UI thread's (Java) static method when some condition's satisfied. When the static method was called, I want a Toast to show on my UI. What I have tried are:
1
static void myMethod(){
Toast.makeText(context, "message", Toast.LENGTH_SHORT).show();
(I have a static context reference in global scope)
}
RESULT:
E/AndroidRuntime( 1331): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
2
static void myMethod(){
runOnUiThread(new Runnable(){
public void run(){
Toast.makeText(Context, "message", Toast.LENGTH_SHORT).show();
}
});
RESULT:
Can not compile: Cannot make a static reference to the non-static method runOnUiThread(Runnable) from the type Activity
Can anybody throw some light on this? Many thanks to you.
I think you are calling this method from a different thread than the UI thread and this causes an Exception. I have just tried declaring a static method in my Application class that would do the same as your first code. It worked - but of course only when called from main UI thread.
If you would like to be able to call the static method from a different thread, then you will need to create a handler on the UI thread to display the Toast. Something like this:
private static final int MSG_SHOW_TOAST = 1;
private static Handler messageHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == MSG_SHOW_TOAST) {
String message = (String)msg.obj;
Toast.makeText(App.this, message , Toast.LENGTH_SHORT).show();
}
}
};
private static void displayMessage() {
Message msg = new Message();
msg.what = MSG_SHOW_TOAST;
msg.obj = "Message to show";
messageHandler.sendMessage(msg);
}
The context in my sample is retrieved from App.this, which is the Application class. You can replace this with your Activity, or your static global context.
static Activity thisActivity = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
thisActivity = this;
}
public static void showMsg()
{
Toast.makeText(thisActivity, "message" , Toast.LENGTH_SHORT).show();
}
Try this instead, as described in this post:
public class SampleActivity extends Activity {
/**
* Instances of static inner classes do not hold an implicit
* reference to their outer class.
*/
private static class MyHandler extends Handler {
private final WeakReference<SampleActivity> mActivity;
public MyHandler(SampleActivity activity) {
mActivity = new WeakReference<SampleActivity>(activity);
}
#Override
public void handleMessage(Message msg) {
SampleActivity activity = mActivity.get();
if (activity != null) {
// ...
}
}
}
private final MyHandler mHandler = new MyHandler(this);
/**
* Instances of anonymous classes do not hold an implicit
* reference to their outer class when they are "static".
*/
private static final Runnable sRunnable = new Runnable() {
#Override
public void run() { }
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Post a message and delay its execution for 10 minutes.
mHandler.postDelayed(sRunnable, 600000);
// Go back to the previous Activity.
finish();
}
}
I had to use a slightly different method to get the context.
Previously created global Application class:
package com.com.YourAppName;
import android.app.Application;
public class YourAppName_app extends Application {
//declarations, getters, setters, etc...
}
A static method inside your Activity/FragmentActivity where you want the Toast:
public class Home extends FragmentActivity {
static YourAppName_app app;
private static void yourStaticMethod() {
app = ((YourAppName_app)getApplicationContext()); //can also call this in onCreate
Toast.makeText(app, "Your Toast message", Toast.LENGTH_LONG)
.show();
}

Categories

Resources