I have a subclass checkLoginTask in my Activity LoginActivity (this activity is for the login of a user) . This subclass is called from in the onPostExecute() from a class that extends AsynTask.
I want to destroy the activity LoginActivty if theLoginOk == "ok" and start the activity MainActivity. I used finish() but I got a error Non-Static method "finish()" cannot be referenced from a static context
I tried with final Activity activity = this; but does not worked.
this is the method on my Avtivity LoingPage
public static void checkLoginTrue(JSONObject jsonObject, Context context){
if(jsonObject != null) {
Intent intent = new Intent(context, MainActivity.class);
try {
JSONObject student = jsonObject.getJSONObject("status");
String theId = student.getString("id");
String theLoginOk = student.getString("login");
Log.i("JSON login", theLoginOk);
if (theLoginOk.equals("ok")) {
intent.putExtra("id", theId);
intent.putExtra("login", theLoginOk);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} else {
// something
}
} catch (JSONException e) {
Log.w("error", e.getMessage());
}
}
}
How can I solve this?
here no need for static method. if you want practice for calling static method in activity class, Create onr Util class in that create static methods and call from activity override methods.
like
public class Utill
{
public static void checkLoginTrue(JSONObject jsonObject, Context context, Class<? extends Activity> myClass){
if(jsonObject != null) {
Intent intent = new Intent(context, myClass);
try {
JSONObject student = jsonObject.getJSONObject("status");
String theId = student.getString("id");
String theLoginOk = student.getString("login");
Log.i("JSON login", theLoginOk);
if (theLoginOk.equals("ok")) {
intent.putExtra("id", theId);
intent.putExtra("login", theLoginOk);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} else {
// something
}
} catch (JSONException e) {
Log.w("error", e.getMessage());
}
}
}
}
then call
Utils.checkLoginTrue(jsonObject, this, MainActivity.class);
in your activity any override non-static and/or static method.
Use Broadcast receiver to finish activity or eventbus to avoid leaks in memory, singletons should not exists in android!
Example:
public class FinishableActivity extends AppCompatActivity {
public static final String ACTION_FINISH = FinishableActivity.class.getName() + ".FINISH";
public static final String EXTRA_ACTIVITY_CLASS = "EXTRA_ACTIVITY_CLASS";
private FinishBroadcastListener finishReceiver;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
finishReceiver = new FinishBroadcastListener()
.register(this);
}
#Override
protected void onDestroy() {
finishReceiver.unregister(this);
finishReceiver = null;
super.onDestroy();
}
public static void show(Context context, Class<? extends Activity> cls) {
context.startActivity(new Intent(context, cls) {{
addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REORDER_TO_FRONT | FLAG_ACTIVITY_BROUGHT_TO_FRONT);
}});
}
public static void hide(Context context, Class<? extends Activity> cls) {
context.sendBroadcast(new Intent(ACTION_FINISH) {{
putExtra(EXTRA_ACTIVITY_CLASS, cls);
}});
}
class FinishBroadcastListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = (intent == null) ? "" : intent.getAction();
action = (action == null) ? "" : action;
if (ACTION_FINISH.contentEquals(action)) {
onFinishCalled((Class<? extends Activity>) intent.getSerializableExtra(EXTRA_ACTIVITY_CLASS));
}
}
public FinishBroadcastListener register(Context context) {
context.registerReceiver(this, new IntentFilter(ACTION_FINISH));
return this;
}
public void unregister(Context context) {
context.unregisterReceiver(this);
}
}
private void onFinishCalled(Class<? extends Activity> cls) {
if (cls == null) {
return;
} else {
if (cls.equals(getClass())) {
finish();
}
}
}
}
Your finish() didn't work when you tried because you need an actual activity object to call it on. Static methods do not run on objects. Thats why they can't use this.
You must pass your activity object reference to the static method and then finish() it. If you have already passed it as Context context then cast it to activity first. Example:
//if your context is actually activity reference, use line below
//if not, add another Activity argument to the method
//if you cant get to the activity to pass it as argument, save it in a static reference somewhere, during ocCreate for example, and you can access it globally
Activity activity = (Activity) context;
//correct way to use finish()
activity.finish();
Related
I initialize the interface SMSListener in my MainActivity's onCreate but it is null in my overridden onReceive function. Am I incorrectly using the public interface variable in my onReceive? I have properly initialized the variable whenever I have tested it outside of the overridden function.
SmsReceiver:
public class SmsReceiver extends BroadcastReceiver {
public interface OnCustomReceiveSMS {
void OnReceiveSMS(String inNumber, String inText);
}
public OnCustomReceiveSMS SMSListener;
//constructor
public SmsReceiver(){
this.SMSListener = null;
}
//register sms listener
public void SetCustomEventListener(OnCustomReceiveSMS eventListener){
this.SMSListener = eventListener;
this.SMSListener.OnReceiveSMS("test1", "test2");
}
#Override
public void onReceive(Context context, Intent intent) {
//THIS IS ALWAYS FALSE EVEN AFTER INITIALIZED
if(this.SMSListener != null){
Toast.makeText(context, "SMSListener is NOT null", Toast.LENGTH_SHORT).show();
this.SMSListener.OnReceiveSMS("test3", "test4");
}else{
Toast.makeText(context, "SMSListener is NULL", Toast.LENGTH_SHORT).show();
}
}
}
MainActivity:
public class MainActivity extends AppCompatActivity {
SmsReceiver smsReceiverObj;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//initialize SMS receiver and register event listener
this.smsReceiverObj = new SmsReceiver();
this.smsReceiverObj.SetCustomEventListener(new SmsReceiver.OnCustomReceiveSMS() {
#Override
public void OnReceiveSMS(String inNumber, String inText) {
Toast.makeText(getApplicationContext(), "test event listener fired", Toast.LENGTH_SHORT).show();
}
});
}
}
The first test in SetCustomEventListener (test1, test2) works just fine immediately after initializing the interface variable. When I try using it in onReceive function later I always get the "SMSListener is NULL" debug message.
The problem might be a sticky broadcast, which will call onReceive method before you even setCustomEventListener, better way to do it is to initialize it in constructor
public class SmsReceiver extends BroadcastReceiver {
public interface OnCustomReceiveSMS {
void OnReceiveSMS(String inNumber, String inText);
}
public OnCustomReceiveSMS SMSListener;
//constructor
public SmsReceiver(OnCustomReceiveSMS eventListener){
this.SMSListener = eventListener;
this.SMSListener.OnReceiveSMS("test1", "test2");
}
#Override
public void onReceive(Context context, Intent intent) {
//THIS IS ALWAYS FALSE EVEN AFTER INITIALIZED
if(this.SMSListener != null){
Toast.makeText(context, "SMSListener is NOT null", Toast.LENGTH_SHORT).show();
this.SMSListener.OnReceiveSMS("test3", "test4");
}else{
Toast.makeText(context, "SMSListener is NULL", Toast.LENGTH_SHORT).show();
}
}
}
And in your activity
this.smsReceiverObj = new SmsReceiver(new SmsReceiver.OnCustomReceiveSMS() {
#Override
public void OnReceiveSMS(String inNumber, String inText) {
Toast.makeText(getApplicationContext(), "test event listener fired", Toast.LENGTH_SHORT).show();
}
});
EDIT
Problem is you are trying to register it in Manifest, remove receiver from manifest and register it inside the MainActivity , It will work like a charm
this.smsReceiverObj = new SmsReceiver(new SmsReceiver.OnCustomReceiveSMS() {
#Override
public void OnReceiveSMS(String inNumber, String inText) {
Toast.makeText(getApplicationContext(), "test event listener fired", Toast.LENGTH_SHORT).show();
}
});
registerReceiver(this.smsReceiverObj,new IntentFilter());
I have created an application in which when I turn on bluetooth a toast is shown and a new activity starts. This is my broadcast receiver class:
public class BroadCast extends BroadcastReceiver {
String prefs="myPrefs";
String count="myCount";
static int counter=0;
Intent i;
#Override
public void onReceive(Context arg0, Intent arg1) {
String bluth = arg1.getAction();
if (bluth.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
if(arg1.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_ON){
SharedPreferences sp = arg0.getSharedPreferences(prefs, Context.MODE_PRIVATE);
Editor ed = sp.edit();
ed.putInt(count, counter);
ed.commit();
counter++;
Toast.makeText(arg0, "Bluetooth on " + sp.getInt(count, 0), Toast.LENGTH_LONG).show();
i = new Intent(arg0, Indicators.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
arg0.startActivity(i);
Indicators.on.setVisibility(View.VISIBLE);
} else if (arg1.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_OFF) {
} else if (arg1.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_TURNING_OFF) {
} else if (arg1.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_TURNING_ON) {
}
}
}
}
Now there is no problem. The activity is starting but in the above code when I put
Indicators.on.setVisibility(View.VISIBLE);
And run the app, It crashes!
Actually on is a textview obj which I have defined in Indicators class as follows:
public class Indicators extends Activity {
static TextView on, off, opening, closing;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.textviewbluetooth);
opening = (TextView)findViewById(R.id.textView1);
on = (TextView)findViewById(R.id.textView2);
closing = (TextView)findViewById(R.id.textView3);
off = (TextView)findViewById(R.id.textView4);
opening.setVisibility(View.INVISIBLE);
on.setVisibility(View.INVISIBLE);
off.setVisibility(View.INVISIBLE);
closing.setVisibility(View.INVISIBLE);
}
}
How should I remove this error?
class YourActivity extends xxxx {
private static YourActivity mInst;
public static YOurActivity instance() {
return mInst;
}
/// Do your task here.
public void setViewText(xxxx) ;
#Override
public void onStart() {
...
mInst = this;
}
#Override
public void onStop() {
...
mInst = null;
}
}
And in your BroadcastReceiver:
YOurActivity inst = YOurActivity.instance();
if(inst != null) { // your activity can be seen, and you can update it's context
inst.setViewText...
}
Put this line
on.setVisibility(View.VISIBLE);
Inside the Activity -> onCreate() method.
Do not use static references to the Activity class members like TextViews from outside the Activity itself as it might have been destroyed, or not have been created yet. This is bad practice in general.
Edit: Add an extra to the Activity starter intent if you need a flag to show the indicator.
I have a fragment HostEditFragment which is loaded up by activity HostEditActivity. When I finish editing in the fragment I'd like to call a method on MainActivity. I'm trying to do it with an Interface and intent at the moment but it starts a new MainActivity and doesn't seem to work.
Just wondering if there's a better way of doing this.
I think it's creating a new MainActivity rather than using the existing one as SfnViewerFragment is coming back as null. I need it to be the existing MainActivity and SfnViewerFragment.
Here's some skeletal code so you can see what I've tried.
HostEditFragment:
public class HostEditFragment extends Fragment {
OnViewerEditedListener callback;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
callback = (OnViewerEditedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnViewerEditedListener");
}
}
public void saveHost() {
//...
callback.onViewerEdited(id);
}
public interface OnViewerEditedListener {
public void onViewerEdited(Long id);
}
}
HostEditActivity:
public class HostEditActivity extends ActionBarActivity implements HostEditFragment.OnViewerEditedListener {
public void onViewerEdited(Long id) {
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("id", id);
startActivity(intent);
}
}
MainActivity:
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Uri data = getIntent().getData();
Uri viewerUri;
if (data != null) {
//....
} else {
Long id = getIntent().getLongExtra("id", -1);
if (id != -1) {
onViewerEdited(id);
}
}
public void onViewerEdited(Long id) {
SfnViewerFragment sfnViewerFragment = (SfnViewerFragment) getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":0");
sfnViewerFragment.recreateWebView(id);
viewPager.setCurrentItem(0, true);
}
}
I have 2 classes which are GcmMessageHandler and Control (its an activity class, shows some graphics). When i handle the gcm message, i want to refresh control class (but if its front)
public class GcmMessageHandler extends IntentService {
String mes;
private Handler handler;
public GcmMessageHandler() {
super("GcmMessageHandler");
}
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
handler = new Handler();
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = gcm.getMessageType(intent);
mes = extras.getString("title");
showToast();
Log.i("GCM", "Received : (" +messageType+") "+extras.getString("title"));
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
public void showToast(){
handler.post(new Runnable() {
public void run() {
if(mes.equals("Control")){
}else{
Toast.makeText(getApplicationContext(),mes , Toast.LENGTH_LONG).show();
}
}
});
}
}
In this part:
if(mes.equals("Control")){ }
if the control activity class is resume, i want to refresh it. How can i do this?
You can use a BroadcastReceiver in order to notify your activity about any changes. So register a BroadcastReceiver in your activity first:
public class MainActivity extends Activity {
public static String REFRESH_ACTIVITY = "com.domain.action.REFRESH_UI"
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// do UI updates
}
};
#Override
public void onResume() {
super.onResume();
// do UI updates
IntentFilter filter = new IntentFilter();
filter.addAction(REFRESH_ACTIVITY);
this.registerReceiver(broadcastReceiver, filter);
}
#Override
public void onPause() {
super.onPause();
this.unregisterReceiver(broadcastReceiver);
}
...
}
Then send the broadcast to perform the UI update from any location:
if (mes.equals("Control")) {
Intent intent = new Intent();
intent.setAction(MainActivity.REFRESH_ACTIVITY);
sendBroadcast(intent);
}
Maybe you could use an observer design pattern.
Let the GcmMessageHandler hold the Control activity as an observer and then notify it when needed.
public class GcmMessageHandler extends IntentService {
String mes;
private Handler handler;
private Control mObserver
public GcmMessageHandler() {
super("GcmMessageHandler");
}
public void attachObserver(Control ctrl) {
mObserver = ctrl;
}
Then you just add a method to the Control class that can be called from the GcmMessageHandler class.
if(mes.equals("Control")){
mObserver.update(); // example
}else ...
It would be more slick if you first defined an observer interface:
public interface IObserver {
public abstract void update();
}
and had your Control class implement that. This way your GcmMessageHandler class could have a list of observers:
public class GcmMessageHandler extends IntentService {
String mes;
private Handler handler;
private List<IObserver> mObservers;
public GcmMessageHandler() {
super("GcmMessageHandler");
}
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
handler = new Handler();
mObservers = new ArrayList<IObserver>();
}
public void attachObserver(Control ctrl) {
mObservers.add(ctrl);
}
private void notify() {
for(IObserver observer : mObservers)
observer.update();
}
And of course if the Control class is the one holding the GcmMessageHandler object your just call the attach method from Control like this:
myGcmMessageHandler.attachObserver(this);
I have to use a BroadcastReceiver in a class that I will have to call in an Activity. Obviously, I have to necessarily register the BroadcastReceiver and then I wrote this code:
public class MyClassName {
Context context;
BroadcastReceiver batteryInfoReceiverLevel;
public void CheckBatteryLevel() {
Log.d("App", "I'm in the CheckBatteryLevel");
context.registerReceiver(batteryInfoReceiverLevel, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
batteryInfoReceiverLevel = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Apps", "I'm in the onReceive");
int level= intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0);
if(level <=100) {
//Do something
}
else if(level >=100) {
//Do something
}
}
};
}
}
When I run the code the application crashes giving "Error receiving broadcast Intent { act=android.intent.action.BATTERY_CHANGED flg=0x60000010 (has extras) } and the crash line is
context.registerReceiver(batteryInfoReceiverLevel, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
How can i fix?
There are two problems here:
ρяσѕρєя K has pointed out the first one:
Initialize your context by adding a parameter to the method CheckBatteryLevel() or to the constructor
of MyClass
public class MyClass(Context ctx) {
context = ctx;
}
Second, you have to call registerReceiver(..) AFTER you have initialized the BroadcastReceiver. Or it will be null and not registered.
All in all this should do it:
public class MyClassName {
BroadcastReceiver batteryInfoReceiverLevel;
public void CheckBatteryLevel(Context ctx) {
Log.d("App", "I'm in the CheckBatteryLevel");
batteryInfoReceiverLevel = new BroadcastReceiver() { // init your Receiver
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Apps", "I'm in the onReceive");
int level= intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0);
if(level <=100) {
//Do something
} else if(level >=100) {
//Do something
}
}
};
// register your Receiver after initialization
ctx.registerReceiver(batteryInfoReceiverLevel,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
}
application crashes giving "Error receiving broadcast Intent
Because context is null you should need to initialize context before calling registerReceiver. for initialization use Class constructor or pass to CheckBatteryLevel method from calling Activity. :
public void CheckBatteryLevel(Context aContext) {
context =aContext;
//....your code here...
}