I'm using a PreferenceFragment and some headers to manage my application settings like in this official tutorial: http://developer.android.com/guide/topics/ui/settings.html#Fragment
You can call Preferences by the ActionBar in several Activities.
Now I want to detect, if a user enters oder leaves the preferences. How can I do that?
My approach is using the lifecycle methods like: onCreate, onResume, onPause ....
But is there another solution like a listener or something else?
You can override onBackPressed on PreferenceFragment to call a interface method that is implemented on your caller/s activity.
That way you can notify what you need to your activitys.
public interface PreferenceInterface
{
public abstract void preferencesClosed();
public abstract void preferencesOpened();
}
I hope this is what you are looking for.
Related
My Application have around 50 activities to which I want to register/De-register my listener. Traditional way could be to register it by writing it in every activity. Is there any way to define my listener globally.
Firstly, I think 50 activities are too much and I think you are doing something wrong.
Secondly, for your situation, you could make BaseActivity and register and unregister your listener in the appropriate lifecycle event.
class BaseActivity: AppCompatActivity() {
override fun onResume() {
super.onResume()
//register your listener here
}
override fun onStop() {
super.onStop()
//unregister your listener here
}
}
and then rather than extending Activity, you will extend the BaseActivity
I'd suggest you registering your activities at a central registrar, maybe a synchronized Set or List (I guess you need to implement a common interface for all your activities to be able to do so). Then your listener would be able to process this list and register at each and every activity.
Or the listener would just register at this central registrar. Thus, the registrar would be acting as a publisher as well, and passing subscriptions down to all registered activities.
I have this simple problem:
An activity contains a fragment. Both want to communicate with each other.
The fragment wants to inform the activity about certain interactions. Therefore it defines the OnFragmentInteractionListener interface which is implemented by the activity. This is already part of the Android Studio fragment template, so nothing new here.
The activity wants to inform the fragment about the back button being pressed. Therefore it defines the OnBackPressedListener interface which is implemented by the fragment.
class MainActivity extends AppCompatActivity implements MyFragment.OnFragmentInteractionListener {
...
#Override
public void onFragmentInteraction(Uri uri) {
...
}
interface OnBackPressedListener {
boolean onBackPressed();
}
}
class MyFragment extends Fragment implements MainActivity.OnBackPressedListener {
...
#Override
public boolean onBackPressed() {
...
}
interface OnFragmentInteractionListener {
void onFragmentInteraction(Uri uri);
}
}
IMHO a simple design that, unfortunatley, doesn't work. "Cyclic inheritance involving ..." is the message from Android Studio.
I would have expected that compilation error if I used nested classes instead of interfaces as the classes' static initializers might be cyclic dependent on each other. I don't see that problem with interfaces but I'm sure there's a good reason why it's not allowed.
The easiest way to resolve this is making one of the interfaces a package-level interface. But I wonder if this is the way to go. And if so: which one should be package-level.
You can have a BroadcastListener attached to the Fragment using a register call.
Please do not forget to unregister the listener in onStop or onPause if you plan to interact with the UI or it will cause exceptions.
Now the simple way is, override the onBackPressed inside your activity and when it gets hit, broadcast an event and let your fragment know. Simple and shouldn't be too problematic to handle.
I personally prefer this approach to send messages to all my Fragments. Another approach as you yourself said is declaring a package wide interface and doing the stuff that you wanted as you already wrote. Nothing wrong with this either, it's just Java being Java.
Consider the following scenario:
I have an Activity with UI elements that launches a DialogFragment when clicked
The DialogFragment has a listener interface that the Activity provides an implementation of. Say for example, the Activity is an image editor and the DialogFragment selects a contrast - the dialog would have a OnContrastChangedListener that the Activity implements
The Activity has implemented this interface to update views in its UI. Continuing the image editor example, the Activity implements the OnContrastChangedListener to update its preview view - something like this:
contrastDialog.setOnContrastChangedListener(new OnContrastChangedListener {
#Override
public void OnContrastChanged(int newContrast) {
getPreviewView().updateWithContrast(newContrast);
}
});
The orientation is changed, and everything is recreated and the listener saved and restored correctly using the methods recommended here (listener is saved in a Fragment and restored when the lifecycle is restoring state).
The problem is the listener interface now does not work. The function getPreviewView() is now returning null even though when called anywhere else in the Activity it returns the correct value
Excuse the poor terminology (my knowledge in compiling and bytecode is limited), but I can grasp what has happened. The interface has been compiled with the getPreviewView() version that returned the preview view that was destroyed on the orientation change, and this has since been released / garbage collected / is now null.
My question is, is there a way in Java to make the interface compile expecting the values / functions to change - much like the volatile keyword in C (I am expecting there isn't)? In that case, what's the best approach for getting around this type of situation? I have considered the following:
Create the DialogFragment (and its interface) in the code that is rerun when the Activity is recreated. This is fine for things like OnClickListeners for Buttons as they are definitely created. But this DialogFragment is only created when a button is pressed, so this approach means every dialog for the screen is created each time the Activity is - this seems wasteful given they may not even be run
Create all possible interfaces for the Activity every time and save them in member variables, then use these interfaces when the DialogFragments are requested to be created by the event. Same comments as above - seems wasteful creating every possible interface just in case it is run.
Keep some hacky "open dialog state" member variables in the Activity that guide the recreation of the interfaces. Hacky and creates a tie between the Activity and the DialogFragment which isn't great practice.
As you can see, all options involve recreation that is wasteful to some extent - is there a way to reuse the existing interface implementation?
EDIT: Options 1 and 2 won't work because they need a link to the existing Dialog. This is all doable but it is leaning more and more towards the hacked together option of having 'current Dialog' variables, getting the DialogFragment with FragmentManager when the activity is restarted, casting it appropriately based on the 'current Dialog' variable, recreating the listener. Is there a less messy way?
the onAttach onDetach method is good and I like using it, sometimes, when I know there will be more developers in the code I don't even cast it blindly, but I do a check like this:
if(activity instanceof MyInterface){
interface = (MyInterface) activity;
} else{
thrown new RuntimeException("Dear colleague, this fragment was meant to have the activity implementing MyInterface or else a bunch of other stuff won't work, please go back to your code and add the interface");
}
but as a different resort, you can also re-set the interface when the fragment is recreated. For example, on the activity onCreate
if(savedInstanceState != null){
mDialogFrag = getSupportFragmentManager().findFragmentByTag(MyDialogFrag.TAG);
if(mDialogFrag != null)
mDialogFrag.setListener(... the interface ...);
}
I know that's also not the best separation of objects, but the fact is that getPreviewView() NEEDS the current activity to proper operate, so you NEED to pass this reference again when everybody gets destroyed n rebuilt.
Those are just different ways of doing it.
If the activity will always have the implementation of the interface, would it be possible to set your listener in the DialogFragment's onAttach()? This will ensure that when it is destroyed and recreated, it will have the most up-to-date reference, like:
public void onAttach(Activity activity) {
super.onAttach(activity);
contrastChangedListener = (OnContrastChangedListener)activity;
}
public void onDetach() {
super.onDetach();
contrastChangedListener = null;
}
I have a custom View class that extends Spinner. I'm trying to figure out what the correct way to talk to the Activity that it's embedded in is, when the user makes a selection. I see that the OnItemSelected listener gets a reference to the Adapter, but I'm not clear on whether or not I should be using this adapter and walking up its parent chain somehow, or if I should just talk directly to the context (for some reason that doesn't feel safe, even though I can't think of a way in which it might fail, offhand).
the right way to do that, is to "listen" to your custom view by exposing an interface which your view holding a reference to instance of him, and you hosting activity should implement. exactly like the OnItemSelected interface and any events which android views are exposing is been implemented. this is the observer design pattern.
for example:
public class MyCustomSpinner extends Spinner {
public MyCustomSpinner(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public interface IMyEventListener {
public void onEventOccurred();
}
private IMyEventListener mEventListener;
public void setEventListener(IMyEventListener mEventListener) {
this.mEventListener = mEventListener;
}
protected void someMethodWhichDoingSomthingAndShouldRaiseAlsoTheEvent() {
/*
* Some Code which the function doing //more code...
*/
if (mEventListener != null) {
mEventListener.onEventOccurred();
}
}
}
this is how you will use it from your activity:
mMyCustomSpinner.setEventListener(new IMyEventListener() {
#Override
public void onEventOccurred() {
// TODO Auto-generated method stub
}
});
I'm trying to figure out what the correct way to talk to the Activity that it's embedded in is, when the user makes a selection.
You don't want to "talk to the Activity that it's embedded in". You want to talk to the controller responsible for the View. Today, that might be an Activity. Tomorrow, that might be a Fragment.
I see that the OnItemSelected listener gets a reference to the Adapter, but I'm not clear on whether or not I should be using this adapter and walking up its parent chain somehow
That implies that the View knows the specific type of Adapter, since the Adapter interface does not have any sort of getContext() method. Moreover, it ties you to talking to the Activity, which is not a good plan at this point, as mentioned above.
Personally, I'm a bit dubious about having a custom Spinner subclass in the first place. But, assuming there's a good reason for it, you should follow Tal Kanel's advice (posted while I was writing this) and design a custom listener interface for this custom event that is being declared by your custom View. Have the controller (Activity or Fragment) supply an implementation of that interface -- this could be directly implemented on the controller, or implemented as an anonymous inner class (as in Tal Kanel's answer), etc. Have your custom View call method(s) on the listener interface as needed.
The correct way is using a listener of some sort. I think you can make direct reference, your code would just not be reusable for another project then...
A simple solution -
((ParentClass) context).functionToRun();
Where ParentClass is the class name of the activity.
Is the there a way to set a landscape mode to the whole application, not by adding android:screenOrientation="portrait" to every activity in AndroidManifest?
Here's the only thing I can think of. Write a class that extends Activity and put the following in that class:
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Then, instead of extending Activity in your other classes, extend the new class.
One programmatic way of doing this, that I can think of, is to create a super class that extends activity and extend all your classes from there.
Have the below setting in the super class in a protected method and call super.xxx() to initiate this:
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
In case you what a specific activity in a different way you can simply override this.
[I have not tried this yet, but by the knowledge of OOP this works]
You could try putting that attribute in the node of your manifest. I don't know if that is supported though. And if not Im afraid putting it in each of your is going to be the next easiest way.
You might be able to achieve it by making yourself a CustomActivity that extends activity and sets the window flags to be Portrait in the onCreate. Then with all of your other activities you could extend your CustomActivity instead of plain Activity.