Sorry if this been asked before but I couldn't find an answer to my specific case. Also sorry that I'm new and a little stupid.
Problem:
I'm showing a dialog from a fragment and passing along a context in my constructor method because I need a context in my dialog to register for broadcastrecievers etc.
DialogFragment fragmentDialog = MyDialog.myConstructor(getActivity());
fragmentDialog.show(getFragmentManager(), "dialog");
Then in MyDialog class I store the context in a instance variable.
The problem arises when rotating the device and I get a nullPointerException when I try to use the context again in the dialog.
Can this be solved in some easy way?
If the device is rotated the Activity will be destroyed and recreated. So the Context you passed to your Fragment points on the Activity which was destroyed.
You could use setRetainInstance(true) in your Fragment. This way your Fragment will survive the recreation of the Activity.
To solve the NPE you have to pass the Context to the Fragment, if the Activity is recreated. Then the Context belongs to the new Activity.
In fact, without this update every line of code which points on the Activity like getActivity() or getFragmentManager() will lead in a NPE.
You get the NullPointerException because activites are destroyed and recreated when rotating the screen.
The SO post below gives more info...
https://stackoverflow.com/a/1673374/
Please be careful with the order of events if you rotate a FragmentActivity, because this can also be a source of NullPointerExceptions.
This is not documentated:
When the FragmentActivity is created the first time,
public class MyActivity extends FragmentActivity implements
MyFragment.OnFragmentInteractionListener {
private int var1;
private int var2;
#Override
protected void onCreate(Bundle savedInstanceState) {
//before
var1 = 3;
super.onCreate(Bundle savedInstanceState)
//after
var2 = 5;
}
//Interface Methods
public int getVar1() { return var1; }
public int getVar2() { return var2; }
}
both of the [before] and [after] code will be run before the fragments are attached and created. So, if you get the vars in the onCreate() call of the Fragment you get both vars. But when you rotate your device, the Activity is recreated from the savedInstanceState in the super call. Now, the fragments are reattached and created anew in this call! That means, this time the Methods of the Listener Interface are called before your [after] code. So, if you pass the Context of the activity to the fragment and get Information through the Interface like it is shown in: https://developer.android.com/training/basics/fragments/communicating.html
you get a NullPointerException for var2 because the interface methods are called from the fragments onCreate() onAttach() ... functions before the [after] code in the Activity's onCreate() is executed! So, take care that you set your Information the InterfaceFunctions are accessing before the super call.
Depending on what you're doing in your initialization you could consider creating a new class that extends Application and moving your initialization code into an overwridden onCreate method within that class.
public class MyApplicationClass extends Application {
#Override
public void onCreate() {
super.onCreate();
// TODO Put your application initialization code here.
}
}
And you are not stupid, even experts need help from time to time.
Related
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
When I see this basic source code in MyActivity.java,
onCreate() method is overriding just. but When I run the app, I can see that overrided method "onCreate()" runs. how is this possible?
If its possible to run the onCreate method in that code, I thought there should be a code like
onCreate();
We can always override these functions and add more to it but the Question is how are these functions called automatically when no one is calling them? We haven’t written any code to call them.
This is where the concept of CALLBACK FUNCTIONS comes in.
The concept of callbacks is to inform a class synchronous / asynchronous if some work in another class is done. Some call it the Hollywood principle: "Don't call us we call you".
Here's a example:
class A implements ICallback {
MyObject o;
B b = new B(this, someParameter);
#Override
public void callback(MyObject o){
this.o = o;
}
}
class B {
ICallback ic;
B(ICallback ic, someParameter){
this.ic = ic;
}
new Thread(new Runnable(){
public void run(){
// some calculation
ic.callback(myObject)
}
}).start();
}
interface ICallback{
public void callback(MyObject o);
}
Class A calls Class B to get some work done in a Thread. If the Thread finished the work, it will inform Class A over the callback and provide the results. So there is no need for polling or something. You will get the results as soon as they are available.
In Android Callbacks are used f.e. between Activities and Fragments. Because Fragments should be modular you can define a callback in the Fragment to call methods in the Activity. copied from here
for more study follow this link please :
link 1
link 2
The onCreate method is called during the Activity Lifecycle. The docs regarding this method state
You must implement this callback, which fires when the system first creates the activity
So the point of this method is for you to initialize anything specific to your activity that needs to be done when it is first created, and call super to propagate this to it's superclasses, allowing them to perform their initialization sequence as well. You should not be invoking this method yourself.
Im trying to implement fragment to activity communication.
Went through android developer doc where an Activity object is passed to onAttach life cycle and set up the Fragment-Activity communication.
This documentation asks to pass Context object instead of Activity. I replaced all the Activity objects by Context objects in the life cycle method onAttach. But it is throwing a NullPointerException while calling the method of the interface from Fragment.
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
colourChangerInterface = (ColourChangerInterface) context;
}
catch (Exception exp){
System.out.println("error!");
}
}
Can anyone please give a small example of the usage in the new way ?
Thanks
Edit :
Found this link where detail discussion is there on the same issue.
The issue is because of the broken API 'onAttach()'; it doesn't get called at all when Context object is passed.
A simple and quick solution found from the above link is to move the code from onAttach to onCreate.
Here is a small example that will describe you the communication between Activity and Fragment. Suppose you have a Interface ICommunication. This is given below:
public interface ICommunication {
public void testMethod();
}
Now you have a Activity name MainActivity that implements ICommunication then it must have implements the method testMethod(). This method will like this:
#Override
public void testMethod() {
Toast toast = Toast.makeText(getActivity(), "It's called from Fragment", Toast.LENGTH_SHORT).show();
}
Now, suppose this MainActivity belongs a Fragment name TestFragment . If you want to access testMethod() of MainActivity from TestFragment then you can simply call using this way :
((ICommunication)getActivity()).testMethod();
Here , TestFragment must be hold on MainActivity.
My related answer with source is here
Thats it :)
I have a main fragment with a viewpager inside it. This viewpager has 2 pages (list fragments). When I start the activty, the main fragment is shown and I also show the first paged fragment. This paged fragment displays data from a db using AsyncTask.
In the main fragment I have:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
onPageSelected(0);
}
#Override
public void onPageSelected(int position) {
Fragment fragment = (Fragment) pagerAdapter.instantiateItem(viewPager, position);
if (fragment instanceof IPagedFragment) {
((IPagedFragment) fragment).onShown(getActivity());
}
}
And the interface is:
public interface IPagedFragment {
void onShown(FragmentActivity activity);
}
The first issue I have is that I have to pass the activity as a parameter because when onShown gets called, the activity is still null.
Furthermore, the paged fragments use progressbar logic similar to the LoginActivity sample. I also get the following exception:
IllegalStateException: Fragment PagedFragment1{4201f758} not attached to Activity
at android.support.v4.app.Fragment.getResources(Fragment.java:620)
So what is the correct stage to start retrieving data from db once the paged fragment is fully available to the UI?
Issues like yours is the reason some developers are starting to question if fragments are really that good or useful.
Also "the correct" is debatable as you can do it in a variety of places and different developers will give you different answers, But let me try to supply you some useful info.
The attach/detach callbacks:
public void onAttach(Activity activity);
public void onDetach();
between those two methods any call to getActivity() will return the non-null activity the fragments is connected to. You can override them and use a private boolean isAttached to keep track of that call.
Also useful is the:
public void onActivityCreated (Bundle savedInstanceState)
this method is called AFTER the Activity.onCreate method. That is very important if you rely on some initialisation that happened there.
Also it's important to remember that on the moment the fragment transaction happens, the Fragment.onCreate happens after the Activity.onCreate and during rotation it happens before it.
As a general rule of thumb I use the Fragment.onStart() / Fragment.onStop() for getting/listening to data. On those calls, all the UI have been created, the fragment is attached to the activity and those callbacks don't get called if there's a dialog/popup (pause/resume does)
From the documentation:
public void onActivityCreated (Bundle savedInstanceState)
[...] tells the fragment when it is fully associated with the new activity instance.
source: http://developer.android.com/reference/android/app/Fragment.html#onActivityCreated(android.os.Bundle)
To get the reference of your activity, create a local object of fragmentActivity and get your activity reference as shown below.
private FragmentActivity fragmentActivity;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
fragmentActivity=activity;
}
This question already has answers here:
Call an activity method from a fragment
(18 answers)
Closed 9 years ago.
I am trying to call a method in an activty from a Fragment screen.
I have a method called myMethod() which is in an activity called MyActivity;
I have a fragment called Screen1Fragment.
I would like to call MyActivity.myMethod() from inside the Screen1Fragment but I am not sure how to do this.
Previously the Screen1Fragment was an activity and so I was extending MyActivity so that I could directly call
myMethod().
But I have had to change the activity to a fragment for sliding tabs usage.
Thanks in advance.
Use getActivity() in your fragment.
MyActivity activity = (MyActivity) getActivity();
activity.myMethod();
if you are not sure if your fragment is attached to MyActivity then
Activity activity = getActivity();
if(activity instanceof MyActivity){
MyActivity myactivity = (MyActivity) activity;
myactivity.myMethod();
}
You should make your fragment totally independant of the activity you are attaching it to. The point of Fragments is that you can re-use them in different contexts with different activities. To achieve that and still being able to call methods from your Activity the following pattern in recommended in the official documentation.
In your fragment:
define a public interface with the method
public interface MyFragmentCallback{
public void theMethod();
}
define a field and get a cast reference:
private MyFragmentCallback callback;
public void onAttach(Activity activity){
callback = (MyFragmentCallback) activity
super.onAttach(activity);
}
In your Activity
implement MyFragmentCallback in the class definition.
implement theMethod() in your activity (Eclipse will ask you to do so)
Then, from your fragment, you can call callBack.theMethod()
The difference between this and simply calling your method on getActivity() is that your fragment is not paired with this specific activity anymore. So you may re-use it with other activity for example one for phones and the other for tablets.
If the method is the static method of MainActivity, something like:
public static void someMethod(){}
Then, it is pretty straightforward. Just call
MainActivity.someMethod()
However, I guess what you really want is to access some function from the Activity class. Then you can use the following code in the Fragment view creater
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState){
container.getContext().someMethod();
}
I asked a question about Fragment's initialization and post my code( Delay initialization when using Fragment in Android ). The question is solved. But my problem still exists. When I call onLoad() to get the variables, it throws NullPointerException. I initialize these variables in onCreateView(). So I guess the life cycle is end. I loged the info in A.java in these function: onDestroy, onDestroyView, onStop. the onDestroyView and onStop is called while the onDestroy is not when fragment A is changed to another one. Strange:
There is a EditText in fragment A. I input a string abc. 1、If the life cycle is end, then when I change fragment from A to another then change back to A, the input should be empty. But it's NOT. 2、if the life cycle is not end, why can't I get the variable?
So is there anything to save the abc somewhere? What's it? Where?
It seems that I can't delay the initialization in Fragment. I can't get the non-static variables.
Code:
/** super class of Fragment */
public class BaseFragment extends Fragment {
public void onLoad(Context context){
}
}
/** */
public class AFragment extends BaseFragment{
TextView name;
#Override
public View onCreateVew(...){
name = new TextView(..);
}
#Override
public void onLoad(Context context){
// here will throw NullPointerException
name.setText("=========");
}
}
public class TabsAdapter extends FragmentPagerAdapter implements TabHost.OnTabChangeListener,ViewPager.OnPageChangeListener {
....
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.mClss.getName(), info.mArgs);
}
#Override
public void onPageSelected(int position) {
TabWidget widget = mTabHost.getTabWidget();
int oldFocusability = widget.getDescendantFocusability();
widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
mTabHost.setCurrentTab(position);
widget.setDescendantFocusability(oldFocusability);
BaseFragment f = (BaseFragment) getItem(position);
f.onLoad(mContext);
}
}
But my problem still exists. When I call onLoad() to get the
variables, it throws NullPointerException. I initialize these
variables in onCreateView().
The problem is in the way you work with those fragments. More exactly, in the onPageSelected method you call the FragmentPagerAdapter's getItem() method to find the fragment for that position(or this is what I'm thinking you're trying to do). But calling this method simply instantiate a new fragment each time you call it, it doesn't give you a reference to the ViewPager's fragment for that position. This newly instantiated fragment isn't attached to an Activity and it's onCreateView method hasn't be called so it doesn't have any views created. Attempting to use your onLoad method to access one of this views is wrong and it will throw that NullPointerException. You should try to use my code from the previous answer, as that code will try to find the fragments that the ViewPager instantiated and it's using as its pages through the FragmentManager.