I have an Android application that we are porting over to Honeycomb/Android 3.0 and we are using Fragments in our new interface.
I have search working via the widget as shown here.
The problem is, the widget doesn't pop up any more when using Fragments. So the question is how do I get search to be used with Fragments?
Or how can I replace this line to be used with Fragments?
getActivity().onSearchRequested();
I solved this problem using interface/callbacks.
In my MainActivity, I write a callback interface:
private SearchRequestedCallback mSearchRequestedCallback;
public void setSearchRequestedCallback(SearchRequestedCallback callback) {
mSearchRequestedCallback = callback;
}
public interface SearchRequestedCallback {
void onSearchRequested();
}
In my Fragment, I set the callback in the onStart() and unset it in the onStop():
#Override
public void onStart() {
super.onStart();
getActivity().setTitle(getResources().getString(R.string.app_name));
((MainActivity)getActivity()).setSearchRequestedCallback(new SearchRequestedCallback() {
#Override
public void onSearchRequested() {
addFilter();
}
});
}
#Override
public void onStop() {
((MainActivity)getActivity()).setSearchRequestedCallback(null);
super.onStop();
}
You can't. The SearchManager is implemented to work with Activitys, not Fragments. See this post for more information.
Related
As the title says, I want to get the reference of currently visible activity or you can say activity which is at the top of backstack from a class, I don't want to send activity reference to that class, because I am using that class from many activities and if I do, I have to pass activity reference from every activity which is a long process.
I already have seen many answers which are typecasting context reference to activity but it is not working.
If anyone has the idea of how to do that in a short way, then please share.
I don't know what you mean by "long process".
Normally, if the Activity is delegating work to another class, it needs to pass itself as a reference so that the delegate knows how to call back the Activity to report progress, etc. This is standard Android stuff. AsyncTask works like this (as an example).
However, if all you want to do is display a Dialog, then you can, instead, start an Activity that looks like a Dialog. This is also a pretty common Android solution. There are themes that you can apply to an Activity that make it look just like a Dialog.
I have found a way via we can do this, In your application class add: registerActivityLifecycleCallbacks(this will listen to all activity lifecycle methods), like this:
public class MyApplication extends Application {
public static Activity currentActivity=null;
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
#Override
public void onActivityCreated(#NonNull Activity activity, #Nullable Bundle bundle) {
}
#Override
public void onActivityStarted(#NonNull Activity activity) {
currentActivity=activity;
}
#Override
public void onActivityResumed(#NonNull Activity activity) {
}
#Override
public void onActivityPaused(#NonNull Activity activity) {
}
#Override
public void onActivityStopped(#NonNull Activity activity) {
}
#Override
public void onActivitySaveInstanceState(#NonNull Activity activity, #NonNull Bundle bundle) {
}
#Override
public void onActivityDestroyed(#NonNull Activity activity) {
}
});
}
}
And then use it like:
if (MyApplication.currentActivity!=null){
// your code here
}
Don't forget to add your application class to manifest:
<application
android:name=".MyApplication"
.../>
For Fragment(put data to activity)
m=(MainActivity)getActivity();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Intent in=new Intent(getActivity(),MainActivity.class)
in.putExtra("test",test);
startActivty(in)
}
},10);
For Activity (get data from fragment )
{
String get_data=getIntent.getStringExtra("test");
}
//it will return always null...any body help me?
startActivty(in) will start the same activity.
Instead of this, you can make use of Interface. It's the easiest way to pass the data.
in your fragment, you can have an interface like,
SubmitData mSubmitData;
public interface SubmitData{
void DataListener(String s);
}
mSubmitData.DataListener("data to be sent");
In your activity, implement the SubmitData interface. It will make you override the DataListener method, where you can get the data.
public class MyActivity extends AppCompatActivity implements YourFragment.SubmitData{
#Override
public void DataListener(String s) {
// Data from the fragment
}
This questions has been asked and answered multiple times. You can find a valid reply here https://stackoverflow.com/a/9977370/5828132
Basically, it consists of creating an interface in the Fragment (for example) including a simple method. The Fragment has to declare a field of that type, and the Activity hosting the Fragment has to implement (implements) that interface. Both entities are usually connected using a explicit cast, in the onAttach() callback of the Fragment life-cycle, i.e.:
#Override
public void onAttach(Context context) {
super.onAttach(context);
// fragmentField_interfaceType = (interfaceType) context;
}
Hope it helps!
I have a Fragment that does some communication with the internet trough some helper Class that requires an interface to handle asynchronous callbacks like this:
SomeInternetCommunicator.getResource(theResourceToGet, retrieverInterfaceInstance);
The interface looks like this:
public interface SomeInternetCommunicator {
void onResourceRetrieveSuccess(SomeResource resource);
void onResourceRetrieveFailed(CommunicatorException e);
}
The problem is that, sometimes the calls take too long, the user already navigated elsewhere and the Fragment that did the call to getResource is not part of the currently running Activity anymore (not showing, not on backstack). This causes many problems because this orphan Fragment is still attempting to react to the callbacks even if it is not part of the Activity anymore. For example, getContext() returns null.
Now my workaround on the Fragment looks like this:
SomeInternetCommunicator flocktrackerTrackerRetrieverInterface = new SomeInternetCommunicator() {
#Override
public void onResourceRetrieveSuccess(SomeResource resource) {
if(isVisible()){
doRetrievalPostProcessing(resource);
}
}
#Override
void onResourceRetrieveFailed(CommunicatorException e) {
if(isVisible()){
doExceptionHandling();
}
}
};
Using the isVisible() works because this ensures that the fragment is still on the foreground, part of the Activity and ready to do the handling. This, however, doesn't help me to cover the case for when the Fragment is not visible, but still part of the current Activity, limiting my possibilities for loading the Fragment before showing it. (Activity is in the background, Fragment is on the Backstack, Fragment loaded by a ViewPager).
Is there a better way to ensure that the Fragment is still on the current Activity's scope before I do the postprocessing? Maybe checking isAdded()?
This question seems to explain a broader but related situation, but it has no answers.
Thank you!
there're two usual approaches to this case:
the best approach is to have a way to clear the interface instance from the SomeInternetCommunicator. Something like:
.
#Override public void onDestroyView(){
SomeInternetCommunicator.removeMe(this);
}
if option (1) is not possible because SomeInternetCommunicator is a poorly coded library, you force option 1 to be possible by making a separate class to implement the interface.
.
public class SomeInternetCommunicatorInterceptor implements SomeInternetCommunicatorInterface {
private SomeInternetCommunicatorInterface listener;
public void setListener(SomeInternetCommunicatorInterface listener){
this.listener=listener;
}
#Override
public void onResourceRetrieveSuccess(SomeResource resource){
if(listener != null){
listener.onResourceRetrieveSuccess(resource);
}
}
#Override
public void onResourceRetrieveFailed(CommunicatorException e){
if(listener != null){
listener.onResourceRetrieveFailed(e);
}
}
}
then on your fragment you use this new class as:
private SomeInternetCommunicatorInterceptor interceptor;
public void onCreateView(....){
... your code
interceptor = new SomeInternetCommunicatorInterceptor();
}
onStart(){
interceptor.setListener(this);
}
onStop(){
interceptor.setListener(null);
}
public void onDestroyView(){
interceptor = null;
super.onDestroyView();
}
VERY IMPORTANT:
if you make SomeInternetCommunicatorInterceptor an internal class of the fragment you HAVE TO make it as static class
I have an activity which may show some DialogFragments. This activity needs to get the response from the dialogs.
I use a listener. In activity:
ProgressMarkDialog dialog = new ProgressMarkDialog();
dialog.setOnProgressMarkSelected(new ProgressMarkDialog.OnProgressMarkSelected() {
#Override
public void onSelect(final int a) {
//some code..
}
});
In the dialog:
public void setOnProgressMarkSelected(OnProgressMarkSelected onProgressMarkSelected) {
this.onProgressMarkSelected = onProgressMarkSelected;
}
This code works fine until somehow the activity is destroyed, but the dialog still open. The program will crash with NullPointerException because the onProgressMarkSelected is null.
I can use
#Override
public void onAttach(final Activity activity) {
super.onAttach(activity);
onProgressMarkSelected = (OnProgressMarkSelected) activity;
}
and implement the interface in the activity.
But if I have few DialogFragments, that means I should implement few interface in the activity and the code will be very messy.
What is the Android best practice for this case?
In my opinion the best way is to stick to the standard positive/negative buttons and attaching DialogInterface.OnClickListener as shown in the http://developer.android.com/reference/android/app/DialogFragment.html
Look at it this way: standard Android user expects to see positive and/or negative button in the dialog. The Activity -if needed- should only be informed about the result (positive, negative input data) of the dialog. Any other input validation should be handled inside the DialogFragment
You could use inheritance with interfaces. Because on interfaces multiple inheritance is possible like this:
public interface A(){
void doA();
}
public interface B(){
void doB();
}
public interface BundleAB extends A, B {
void justAnotherMethod();
}
With this you can bundle your interfaces and use it like this:
public class MyClass implements BundleAB {
#Override
public void doA(){}
#Override
public void doB(){}
#Override
public void justAnotherMethod(){}
}
One of the classes I've written needs to react when the following Activity events occur:
onStart()
onPause()
onResume()
onStop()
I can react to those on the Activity itself:
public class Activity extends ApplicationContext
{
protected void onCreate(Bundle savedInstanceState);
protected void onStart();
protected void onRestart();
protected void onResume();
protected void onPause();
protected void onStop();
protected void onDestroy();
}
From the Activity I could tell the object in question that a certain event has occurred, but I don't like this idea: it requires the developer to implement the logic outside my object/class. Ideally I would like the object to be responsible for registering these events and set itself as a listener, independent of the Activity.
Any ideas? Thanks in advance.
API level 14 has Application.ActivityLifecycleCallbacks.
Before that, afaik, sorry, no.
If you wish to offer your class to others, you will need to either provide abstract classes that extend the most common Activities, or have them put certain calls in their own Activity's lifecycle methods, like
protected void onPause() {
super.onPause();
yourClassInstance.onPause();
}
May as well make it more general, and create abstract NotifyingActivity classes that accept NotifyingActivity.LifecycleListener's, and make your class implement such a listener and register itself in its constructor.
Leverage ActivityLifecycleCallbacks that has been introduced since API level 14.
This is what the interface looks like now.
public interface ActivityLifecycleCallbacks {
void onActivityCreated(Activity activity, Bundle savedInstanceState);
void onActivityStarted(Activity activity);
void onActivityResumed(Activity activity);
void onActivityPaused(Activity activity);
void onActivityStopped(Activity activity);
void onActivitySaveInstanceState(Activity activity, Bundle outState);
void onActivityDestroyed(Activity activity);
}
What you need to do is simply to implement the interface methods and register it on your application.
public class MyApplication extends Application implements ActivityLifecycleCallbacks {
#Override
public void onCreate() {
super.onCreate();
this.registerActivityLifecycleCallbacks(this);
}
//implement call back methods.
}
You can use this library that does exactly what you're trying to do, without having to write code in your activity or in your base activity.
And is very simple to use:
ActivityListener.bind(mActivity).with(mCallback);
Maybe it helps someone