I want to display a toast message in a static class but the is an issue of Toast message parameter passing context of application. Pleas help me, how to display the toast message in static class. Please recommend me the change that I have need to do, I will be very thankful to you. Here is a portion of my code.
public class MainActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.training_four_position);
mEndlessRunnable = (Runnable) new UpdateRunnable();
mEndlessRunnable.run();
}
private static class UpdateRunnable implements Runnable {
private int mState;
public UpdateRunnable(Handler handler, Button[] buttons) {
mHandler = handler;
mButtons = buttons;
}
public void run() {
switch (mState) {
case 0:
mState = 1;
break;
case 1:
mState = 0;
// Here is the issue in my toast message
Toast.makeText(CONTEXT, "Toast message.",Toast.LENGTH_LONG).show();
break;
}
mHandler.postDelayed(this,1000));
}// End of run()
}//End of class UpdateRunnable
} //End of MainActivity
you can try to make a separate method for your toast
public void showToast(String message){
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}//end showToast
and then call that in your inner class.
You can pass your Activity's Context to your UpdateRunnable class in constructor and use it then in your run() function.
However if you are showing Toast from an inner class then that inner class, probably, shouldn't be a static class at all. You can remove static keyword and use your Activity's getContext() in run() then.
Why do you want your inner class static?
Well, one of the way is to use a static variable in your activity.
public static Context myContext;
then update it in onCreate..
onCreate()
{
myContext = getApplicationContext();
}
Other way is to pass the context in the constructor of your class...
I guess getParent() or getApplicationContext() should do the work pass the parameter to the class and have a local context object .Let me know if it fails
Related
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.
I have an activity class (outer class), a static broadcastreceiver class (inner static class) and a service class. The service and the activity communicate with messages and handlers. When an action that the service is monitoring is triggered, the broadcastreceiver is called. After it's done I want to call a method inside the service to remove the element processed from the "items_to_be_processed_queue". To do that I thought to use the method that I have in my MainActivity that sends a message to the service triggering the remove method (I have this method in MainActivity because it's possible to remove manually an item from the "items_to_be_processed_queue" by pressing a button). The thing is I keep getting two kind of errors depending on what I do (I'll show you a bit of code first):
public class MainActivity extends Activity {
Messenger messenger;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
messenger = new Messenger(binder);
}
public void onServiceDisconnected(ComponentName className) {
messenger = null;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
....
}
//Button click implementation
public void removeItem(View view) {
Message msg = Message.obtain(null, MyService.REMOVE_ITEM);
msg.replyTo = new Messenger(new ResponseHandler());
Bundle b = new Bundle();
b.putInt("data", Integer.valueOf(etNumber.getText().toString()));
msg.setData(b);
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void removeItem(int i) {
Message msg = Message.obtain(null, MyService.REMOVE_ITEM);
msg.replyTo = new Messenger(new ResponseHandler());
Bundle b = new Bundle();
b.putInt("data", i);
msg.setData(b);
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
protected static class ResponseHandler extends Handler {
Boolean result;
#Override
public void handleMessage(Message msg) {
int respCode = msg.what;
switch(respCode) {
case MyService.ADD_ITEM: {
result = msg.getData().getBoolean("respData");
}
case MyService.REMOVE_ITEM: {
result = msg.getData().getBoolean("respData");
}
}
}
}
public static class MyBroadcastReceiver extends BroadcastReceiver {
.........
#Override
public void onReceive(Context context, Intent intent) {
........
Case 0: new MainActivity().removeItem(id); //Where id is the position of the item
Case 1: MainActivity.this.removeItem(id);
}
......
So in the case 0 I get no compiling errors but at run time I get a NullPointerException at messenger.send(msg) inside removeItem(int i) method. In case 1 I get the compiling error "No enclosing instance of the type MainActivity is accessible in scope".
What am I doing wrong and what could I do? I even tried to put the removeItem methond inside the broadcastreceiver but I still got run time errores. Thanks in advance for any answer.
Case 0:
You should never create an object of Activity class It will give you a null context. Look at #Raghav Sood's answer here Creating an object of Activity class
Case 1:
You can not call a non-static method from an inner static class. If you want to call removeItem in MyBroadcastReceiver make it static. Since it seems you are not using any instance variables that should not be a problem.
You cannot create activity like that because Android is handling Activity lifeCycle so it won't be anygood..
I can suggest diffrent approach.. Maybe i am missing something because i didn't fully understood your code but this is more architecture problem and less code
Lets say that you hold your DataList In a static way... In that case you can access from Activity and From service as well.. You can't access an activity in the way you want.
class Utils {
private static List<Integer> myList;
static {
myList<Integer> = new Vector<Integer>();//Create new instance of vectore which is thread safe
}
public void getMyList()..;
public List<Integer> setMyList..;
}
In this way you will have direct access to your data structure an you won't have to deal to much with sync between those 2.
EDIT: You can add methods to remove and add or something.. This can be used by
Utils.getMeyList();//Or all other method you need
Hope that make sense..
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
First the format of Toast.makeText():
public static Toast makeText (Context context, CharSequence text, int duration)
the first argument is Context, the function getApplicationContext() also return the current context, everything is ok, but IMO, the getApplicationContext() can also be replaced with this, just as follows:
public class ContextMenuResourcesActivity extends Activity {
/** Called when the activity is first created. */
private Button b1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
b1 = (Button)findViewById(R.id.button1);
final int l = Toast.LENGTH_LONG;
final String s1 = "some string";
b1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Toast t1 = Toast.makeText(this, s1, l);
t1.show();
}
});
}
}
IMO this stands for the class ContextMenuResourcesActivity, which extends Context, so it can replace the first argument which demands for Context, but I failed, can anyone explain why?
When you create a new OnClickListener, you are creating a anonymous class which implements a particular interface. Thus, this does not refer to the Activity, since you are actually in another object.
Here's some more info on the subject Anonymous classes vs delegates
Iin this case this is indicating OnClickListener instance, to create view, or other UI stuff, you need to get context, this can be done by following different methods:
getApplicationContext();
ContextMenuResourcesActivity.this;
v.getContext();
new OnClickListner() is an anonymous class that implements onclick interface and this refers to the instance of the anonymous class. Rather use "Your_Activity_Name.this" to refer to the current context of your activity.
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();
}