Fragment's onCreateView doesn't save member reference - android

I have a MainActivity with a ViewPager. The ViewPager consists of two Fragments each holding a single RecyclerView. I need to have a reference to the RecyclerView for updating/animating it etc. in the Fragment.
A problem occurs on screen rotation, because for some reason I cannot set the member variable back to the RecyclerView.
public abstract class NotifListFragment extends Fragment {
protected RecyclerView mRecyclerView;
public NotifListFragment() {
// Required empty public constructor
EventBusHelper.getBus().register(this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
mRecyclerView = (RecyclerView) inflater.inflate(R.layout.fragment_notif_list, container, false);
setupRecyclerView(mRecyclerView);
return mRecyclerView;
}
So here in the onCreateView I always inflate the fragment and save the reference in mRecyclerView variable. However, when I later try to access it, it is null.
I am using Otto to call both Fragment's onDataChanged() method. It is called when a button in the RecyclerView is pressed.
#Subscribe
public void onDataChanged(DataChangedEvent event) {
List<CustomNotification> oldData = ((NotifRecyclerViewAdapter) mRecyclerView.getAdapter()).getmValues();
List<CustomNotification> newData = getNotifications();
}
The mRecyclerView.getAdapter() is null in this call.
Fragment's getView() also returns null. What is happening?

There are a few things that I found wrong here. Please don't call setupRecyclerView(mRecyclerView); in your onCreateView(), this is something that should be called on your activityCreated() because your fragment might not have been attached to your activity till then. Plus I don't like to do findViewByIds there.
Use the onViewCreated() and onActivityCreated() callbacks.
So your code would look something like this.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_notif_list, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mRecycler = (RecyclerView) view.findViewById(R.id.yourId);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
setupRecyclerView(mRecycler);
}
It's possible that during your call to onDataChanged() that the fragment might not have been added. Do a null check there.

Related

How to initialize a button from a fragment

I have a button inside of a fragment that I need to be able to access in the activity to change it's text. I am using this code in my main activity:
CategoryFragment frag = new CategoryFragment();
getSupportFragmentManager().beginTransaction().add(R.id.activity_main, frag).commit();
frag.setButtonText(i);
The problem is the button is never initialized using the onCreateView() method (that method never even gets called) which causes a null pointer exception. I tried adding an onCreate() method in the fragment, which gets called, but I have to get the view in order to initialize my button. Since the view hasn't yet been initialized, I get another null pointer exception from the view. Here is my best attempt at the onCreate():
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
button = (Button) getView().findViewById(R.id.buttonFrag);
}
In OnCreateView() do like this :
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.yout_layout, container, false);
button = (Button) rootView.findViewById(R.id.buttonFrag);
return rootView;
}
You have completely misunderstood the way Fragment and Activity work with each other. An Activity mainly has the duty to "show" the Fragment, and you need to initialize the Button using your CategoryFragment class.
Override Category Fragment's onActivityCreated() and then add the following:
Button button = (Button) getView.findViewById(R.id.your_views_id);
button.setButton("Voila");
Study about Activity and Fragment Interaction. This might help u. http://simpledeveloper.com/how-to-communicate-between-fragments-and-activities/
You can use “static factory method” Refer following code
public class CategoryFragment extends Fragment {
/**
* Static factory method that takes an int parameter,
* initializes the fragment's arguments, and returns the
* new fragment to the client.
*/
public static CategoryFragment newInstance(String i) {
CategoryFragment f = new CategoryFragment();
Bundle args = new Bundle();
args.putInt("buttonText", i);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam = getArguments().getString("buttonText");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view=inflater.inflate(R.layout.fragment_category, container, false);
Button b=(Button) view.findViewById(R.id.button);
b.setText(mParam);
return view;
}
}
and from your activity just call
getSupportFragmentManager().beginTransaction().add(R.id.activity_main, CategoryFragment.newInstance(i)).commit();

Null pointer exception in imageview when using callback between two fragments?

i have two fragments, i want use callback using interface to change imageview
in first fragment from the second fragment but when callback is fired its get imageview null and i get the below error
java.lang.NullPointerException: Attempt to invoke virtual method 'void
android.widget.ImageView.setImageResource(int)' on a null object
reference
first fragment:
public class firstfragment extends Fragment implements MyProfileCallback
{
Imageview myprofile_image;
public firstfragment()
{
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View rootview = inflater.inflate(R.layout.fisrt, container, false);
myprofile_image=(ImageView) rootview.(find.id.myprofile_image);
/
...
/
}
#Override
public void callbackCall()
{
myprofile_image.setImageResource(R.drawable.profile_friends);
}
}
second fragment:
public class secondfragment extends Fragment
{
MyProfileCallback mcallback;
public secondfragment()
{
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View rootview = inflater.inflate(R.layout.second, container, false);
mcallback.callbackCall();
return rootview;
}
interface
public interface MyProfileCallback
{
void callbackCall();
}
Your question is kind of hard to understand so is your code, BUT, I think you should load the resource file in this case R.drawable.profile_friends
when the fragment view has being created
You can:
EDIT:
You are calling your callback from the onCreateView method meaning your mypfile_image view does not have a reference to your element yet
and you get a null pointer exception
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mcallback.callbackCall();
}

adding dynamic content on fragments android

I'm new to fragments and they are a bit confusing to me right now.
I have read alot and actually built a test app using this tutorial
I was able to add more tabs and so on. But I don't want to display static
content (xmls). I want to be able to modify the UI add listviews, load json data with asynctasck and so on but the very first attempt I made has failed.
So on Tab1:
public class Tab1 extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v =inflater.inflate(R.layout.tab_1,container,false);
return v;
}
}
I tried to declare a textview and edit it's text with settext but
I get a crash and also findviewbyid is not available as a method.
It didn't throw and error when I typed getView().findViewById but
that's not the problem.
Are fragments limited or very different from traditional activities?
Do I need to make never ending customizations
in order to get a listview loading?
Thank you.
You should declare your TextView as a Member variable for your class and get a reference to that view in onCreateView like:
public class Tab1 extends Fragment {
// your TextView member variable
private TextView mTextView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, #Nullable Bundle savedInstanceState) {
View v =inflater.inflate(R.layout.tab_1, container, false);
mTextView = (TextView) v.findViewById(R.id.my_text_view);
return v;
}
// It is safe to access the views here, not in onCreate since it is called before onCreateView
#Override
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
mTextView.setText("Hello, World!");
}
}
For reference on the Fragment lifecycle
Are fragments limited or very different from traditional activities?
A Fragment has its own lifecycle like that of an Activity but it is dependent upon the lifecycle of its parent Activity, so to answer your question they are not very different, it is just a good practice for modularizing code.
Do I need to make never ending customizations in order to get a listview loading?
A little unclear what you mean by never ending customizations but loading a dynamic ListView is very simple in Android.
For Example:
using fragment_one.xml we have just a FrameLayout
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fl_list_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
And the code:
public class Tab1 extends Fragment {
// your FrameLayout member variable
private FrameLayout mFlParent;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_one, container, false);
mFlParent = (FrameLayout) v.findViewById(R.id.fl_list_container);
return v;
}
// It is safe to access the views here, not in onCreate since it is called before onCreateView
#Override
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
// Create a new list, adapter and add a item click listener
ListView myList = new ListView(context); // context needed
myList.setAdapter(new ArrayAdapter<String>(context, android.R.id.simple_list_item_1, new String []{"Item 1", "Item 2", "Item 3", "Item 4"}));
myList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//... handle clicks on list items as usual
}
});
// add the view to the FrameLayout
mFlParent.addView(myList); // may want to call mFlParent.removeAllViews(); before adding just to be safe
}
}
Good luck and happy coding.
Fragment doesn't have an activity methods.
If you want to use findViewById methods, you should use a class field.
public class Tab1 extends Fragment {
private View mView;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.tab_1,container,false);
return mView;
}
#Override
public void onCreate() {
// here you can use `findViewById` method via `mView` variable
mView.findViewById(YOUR_VIEW_ID);
}
}
There is basically 2 method to be use in fragment
1. onCreateView
2. onViewCreated
First one is use to inflate layout on your fragment
Second one is use to find all view used in your layout.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, #Nullable Bundle savedInstanceState) {
View v =inflater.inflate(R.layout.tab_1, container, false);
return v;
}
#Override
public void onViewCreated(View v){
mTextView = (TextView) v.findViewById(R.id.my_text_view);
mTextView.setText("Hello, World!");
}

Android - Add code to a fragment

I am a beginner in coding for Android and i am trying to do an application with two fragments. Unfortunately, when i add code to set action to my layout, it makes my application crash, so i'm wondering where i should put my code on the fragment file. If i take out the function onCreate, the application doesn't crash and my layout is good.
Here is my code. Thank you so much for your answer.
public class FragmentOne extends Fragment{
public static final String TAG = "FragmentOne";
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = View.inflate(getActivity(), R.layout.fragmentone, null);
return v;
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final EditText etData = (EditText) getView().findViewById(R.id.etData);
}
}
First of all I can see a few mistakes in your code.First of all as #user1873880 mentioned, onCreate() is always called before onCreateView(), so you should consider dealing with your views in onCreateView(). Second mistake which I can see is that you are not creating your View as it's designed to be used on Fragment. In my opinion the way your Fragment should look is like this :
public class FragmentOne extends Fragment {
private static final String TAG = "FragmentOne";
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
// create your view using LayoutInflater
return inflater.inflate(R.layout.fragmentone, container, false);
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// do your variables initialisations here except Views!!!
}
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
// initialise your views
EditText etData = (EditText) view.findViewById(R.id.etData);
}
}
Hope this helps you! : )
The reason is that onCreate is invoked before onCreateView, so you can manipulate with your views only after onCreateView callback. For more information check Fragment lifecycle here.

Android Fragment Implementation

I am trying to implement Fragments in my Project using the https://github.com/JakeWharton/Android-ViewPagerIndicator plugin.
My Fragment
public final class NearByFragment extends Fragment {
private static String TAG = "bMobile";
public static NearByFragment newInstance(String content) {
NearByFragment fragment = new NearByFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
return inflater.inflate(R.layout.fragment_search_nearby, null);
}
}
Now I want to execute some code like start start a new thread and download a JSON from the server and then assign a list view from the content I download. In fragments we are assigning views in onCreateView. so where should I write the
listview = (ListView) findViewById(R.id.list_items);
((TextView) findViewById(R.id.title_text))
.setText(R.string.description_blocked);
and other code to generate the Fragment view ?
You can search within the view that you just inflated:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
View v = inflater.inflate(R.layout.fragment_search_nearby, null);
listview = (ListView)v.findViewById(R.id.list_items);
((TextView)v.findViewById(R.id.title_text))
.setText(R.string.description_blocked);
return v;
}
You can also use the Fragment.getView() function elsewhere in your code and call that view's findViewById() member.
You can use getActivity().findByView() from the Fragment if you want to have access to the layout elements. Alternatively, you can just put the findByView() call in the main Activity.

Categories

Resources