I start activity B from activity A.
A call-back method in a non activity class is invoked indicating that I should close Activity B.
How can I close activity B from the non activity class?
Please keep in mind that activity B is not always the same activity, but A is. For example, in my case A is the MainActivity and B is any number of other activities which I can launch from MainActivity.
TLDR; How do I close the current foreground activity from a non activity class.
you should use broadcast.
you can use a SuperActivity,and other activities extend from SuperActivity
register the broadcast in the SuperActivity,
if(intent.getAction.equals(your custom action))(
finish();
)
and B Activity extends SuperActivity
pass the Context to the non activity class as an argument, at the end of this method,use Context to send broadcast.
don't forget the broadcast should be unregistered when the B Activity is finish
Avoiding passing Activity Object to non Activity Class
you can use listener for this and only pass the listener object ... create
your custom listener and your non Activity class take this listener as a
parameter and then you make a superB activity for all your B Activities
that you want to finish and then your superB implement this listener and
all B Activityes override this listener method.
Example:
this is your custom listener
public interface CustomLisnter {
void finishBActivity();
}
at your superB Activity you implement this listener
public abstract SuperBActivity implements CustomLisnter{
}
then at your B Activity extends SuperBActivity and override finishBActivity() method.
public BActivity extends SuperBActivity{
//when ever in your code you call non Activity Class that has the callback
// pass this activity in its constrictor like this
SomeClassToFinishActivity mClass = new SomeClassToFinishActivity(this);
#override
public finishBActivity(){
//here you can finish activity
finish();
}
}
at your non Activity class that responsible for finish current BActivity
pass this listener to it.
public SomeClassToFinishActivity {
private CustomLisnter mListener;
public SomeClassToFinishActivity(CustomLisnter listener){
this.mListener = listener;
}
}
and in your callback that should finish the activity call this
private void yourCallBackMethodToFinishActivity(){
mListener.finishBActivity();
}
i hope that helps you .. let me know if you have a question.
Related
I have implemented a master-detail view. With two fragments being displayed side by side on a large 10-inch screen. Fragment A Displays a list of orders. When an order is selected the details of that order are displayed in Fragment B. In fragments B after processing the order items. I want to notify Fragment A to update the UI and colour the processed order in the list of orders.
The current method that I have tried was creating an interface in Fragment B implementing the interface in Fragment A. However, this method does not seem to work as when I try and set the instance of the interface in the onAttach method the application crashes as the context is still the context of Fragment A.
#Override
public void onAttach(#NonNull Context context)
{
super.onAttach(context);
if (context instanceof OnStockAddedListener)
{
onStockAddedListener = (OnStockAddedListener) this.getActivity();
} else
{
throw new ClassCastException(context.toString());
}
}
How can i go about doing this.
Your fragments are hosted in an Activity, and that activity is what's passed to onAttach(). So your activity needs to be responsible for dispatching communication between your fragments.
So, in FragmentB, you cast your Activity to your listener interface when you're attached:
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.onStockAddedListener = (OnStockAddedListener) context;
}
And you implement the interface in your Activity:
public class MyActivity implements OnStockAddedListener {
#Override
public void onStockAdded(Stock stock) {
FragmentA fragmentA = (FragmentA) getSupportFragmentManager()
.findFragmentByTag(/* insert tag here */);
fragmentA.handleStockAdded(stock);
}
}
And you receive these messages in FragmentA:
public class FragmentA {
public void handleStockAdded(Stock stock) {
// update ui, or whatever else you need
}
}
The main thing is to not think about FragmentA talking to FragmentB, or FragmentB talking to FragmentA. Instead, FragmentA and FragmentB both talk to the Activity, and the Activity can talk (as required) with either FragmentA or FragmentB. Everything flows through the activity.
I have a, what I thought was a, simple task. I have a list of achievements in a recyclerView in my MainActivity. Clicking on one of the achievements launches the AchievementDetailActivity. You do an action in the AchievementDetailActivity and it completes the achievement. When that happens, I need the thumbnail on the MainActivity to be the achievement icon and not the locked icon. What I thought was I could just use the LocalBroadcastManager to send and receive messages from one activity to another, but that isn't working. From everything I have read you are supposed to unregister the listener in your activity onPause and onStop lifecycle methods, however, if you unregister the listener in the onPause of MainActivity, it gets unregistered when the AchievementDetailActivity starts and nothing gets delivered to the MainActivity. I don't understand how you can use LocalBroadCastManager with receivers to send information between activities when they get unregistered as soon as you start a new activity. The following example shows it unregisters as soon as the second activity is started, so the first activity will never get the broadcast...
public class MainActivity extends AppCompatActivity {
public static final String ACTION = "update";
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("MAIN ACTIVITY", "RECEIVED EVENT");
}
}
public void onStart() {
super.onStart();
LocalBroadcastManager.getInstance(this).registerReceiver(receiver), new IntentFilter(ACTION));
}
public void onPause() {
Log.d("MAIN ACTIVITY", "REMOVING LISTENER");
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}
//.. The rest of MainActivity
}
public class SecondActivity extends AppCompatActivity {
#Override
public void onStart() {
super.onStart();
//initialize view and such
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getApplicationContext());
Intent intent = new Intent(MainActivity.ACTION);
intent.putExtra("Something", "somewhere");
manager.sendBroadcast(intent);
}
)};
}
If you run the above, obviously with the buttons and such, you will get a message that shows it unregisters the listener as soon as SecondActivity starts and the MainActivity will never get the message it is supposed to get when you click a button on the second activity.
Is there a way to send information from activity to activity, or because of the lifecycle events is that not possible? Everything I read said LocalBroadcastManager was the right way to do it, but it gets unregistered so, how can it? Please help, this is driving me nuts. Thank you.
If you want to use your LocalBroadcastManager to fetch results, do not unregister in onPause, in which case must to unregister in onDestroy().
If you startAvtivity only to fetch some results, it is a good way to startActivityForResult.
Its not a great idea to use LocalBroadcastReceiver for this purpose. Use startActivityForResult instead. Follow this Official doc for implementation details.
The reason its not wokring is:
You are registering the receiver in onStart and unregistering it in onPause(). When your second activity is shown, onPause () will be called as a result the BroadcastReceiver is unregistered.
Its not a great idea to keep it registered since it would lead to memory leaks.
I am trying to wrap my head around what proper activity flow convention is.
I currently have:
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
//do stuff
//clicklisteners setup etc
Intent intent = new Intent(this, ExampleActivity.class);
//putExtras
startActivity(intent);
}
}
public class ExampleActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
//getExtras
//objectA state lives here
//do stuff
}
}
If the user presses back when on the ExampleActivity view, and then clicks another listener that takes them to ExampleActivity, I want to be able to access "objectA" state again. How do I implement this? I am not understanding onResume or onRestart...
are these the methods to call? or is there a better convention to navigate the app activities?
Android has a mechanism for having an activity pass results back to the prior activity that started it. The documentation for that is here.
Basically, you use startActivityForResult to start the second activity, the second activity uses setResult to set results, and the first activity receives those results in the onActivityResult callback when the second activity finishes.
If the user presses back when on the ExampleActivity view, the ExampleActivity is dead and user is back in the MainActivity, which calls "onResume".
When your are back from activity1 to activity2, activity2's onResume method is called.
With that being said, after the user closed ExampleActivity objectA is destroyed.
I have a navigation drawer in main activity A and a login activity B. Activity B has a OnLogin callback in which i update a global userinfo from a singleton which main activity can access. Note that this OnLogin callback is invoked in a thread.
Now I want to update main activity navigation drawer header ui (e.g. user name and user icon). I'm using startActivityForResult in main activity A to get a flag from login activity B to indicate that something has changed and then update UI in OnActivityResult.
The problem I'm facing is that when activity B finishes (triggered by OnBackPressed in activity B), the OnLogin callback doesn't necessary get called. As a result, onActivityResult won't necessary pick up the change made in UserInfo. My question is, what is a proper way of updating UI in this case?
What i ended up doing
UserInfo.java
class UserInfo extends Observable {
private String value_;
public void setValue(String value)
{
value_ = value;
setChanged();
}
}
MainActivity.java
MainActivity extends AppCompatActivity implements Observer {
public void onCreate(Bundle savedInstanceState)
{
// other onCreate stuff
Singleton.getInstance().getUserInfo().addObserver(this);
// UserInfo initialization
...
// UI initialization
Singleton.getInstance().getUserInfo().notifyObservers();
}
public void update(Observable observable, Object data)
{
if (observable instanceof UserInfo)
{
//update ui
}
}
}
LoginActivity.java
OnLogin(String value)
{
UserInfo userInfo = Singleton.getInstance().getUserInfo();
userInfo.setValue(value);
userInfo.notifyObserver();
}
Say I have two activities: "A" and "B".
Activity A has a button in it's layout. and I want to set it's click listener implemention on Activity B.
So let's say here's Activity A:
Button button = (Button)findViewById(R.id.button);
button.setOnClickListener(B.this);
and in Activity B, I'm trying to implement the function:
public void OnClick(View v)
{
//DO SOMETHING
}
I'm getting the following errors:
The method setOnClickListener(View.OnClickListener) in the type View
is not applicable for the arguments (A)
No enclosing instance of the type A is accessible in scope
What am I doing wrong here?
The handling of the GUI components must be accompanied within the same UI thread that instantiated that.
So your desired view is not correct also make sure the you can have the click and other listener been worked only if the view is set with that components and is currently visible ( In foreground) for the user to have interaction.
If you really want that then You can override the default implementation of the click listener within the different activities via following:
1)Static Reference: make the button as public static in activity A and use it in Activity B by Class A's name.
2)Interface:implements OnClickListener on the activity A , but will not be accessible in B
3)Custom MyClickListener for all activites.
public class MyClickListener implements OnClickListener {
#Override
public void onClick(View v) {
mContext = v.getContext();
switch (v.getId()) {
case R.id.button:
// Your click even code for all activities
break;
default:
break; }}
}
Use it the class A and B both as shown below:
Button button = (Button)findViewById(R.id.button);
button.setOnClickListener(new MyClickListener());
You must pass an instance of an OnClickListener to button.setOnClickListener(..). Class A isn't implementing OnClickListener, so you must implement it in order for it to be an instance of an OnClickListener.
class A extends Activity implements OnClickListener {
// instance variable, constructors, etc
#Override
public void onClick(View v) { // note onClick begins with lowercase
// DO SOMETHING
}
}