I'm doing a recycler method in my android studio project but i have a problem.
Everytime i'm trying to findViewById my application is crashing.
Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object reference
And i don't understand why because i'm creating my view in the good way.
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_carrito, container, false);
return view;
}
And i'm trying to continue with that
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
...
Log.e("test : ",Integer.toString(R.id.recyclerBuy));
recyView = view.findViewById(R.id.recyclerBuy);
/* recyView.setLayoutManager(new GridLayoutManager(getContext(),RecyclerView.VERTICAL));
recyView.setAdapter(buyAdapter);
*/
}
But i'm crashing at the line recyView = view.findViewById(R.id.recyclerBuy);. My R.id.recyclerBuy is not empty.
And here is my RecyclerView
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".ui.carrito.CarritoFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerBuy"
android:layout_width="match_parent"
android:layout_height="550dp"
android:layout_marginBottom="88dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent" />
...
</androidx.constraintlayout.widget.ConstraintLayout>
Anyone have a clue why i'm crashing everytime ?
This happens because onAttach() callback is called before onCreateView().
The easiest way to fix the issue is placing the code where you finding your RecyclerView in onCreateView(). Something like:
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_carrito, container, false);
recyView = view.findViewById(R.id.recyclerBuy);
// here you recyView won't be null
return view;
}
A good article about fragments lifecycle: https://medium.com/androiddevelopers/the-android-lifecycle-cheat-sheet-part-iii-fragments-afc87d4f37fd
Related
I have two APKs. First APK is a main APK which loads second APK.
MainActivity.java (first APK): Object mainFragment was loaded by DexClassLoader early
setContentView(R.layout.activity_main);
LinearLayout fragContainer = findViewById(R.id.main_fragment);
LinearLayout ll = new LinearLayout(context);
ll.setOrientation(LinearLayout.HORIZONTAL);
ll.setId(View.generateViewId());
getSupportFragmentManager().beginTransaction().add(ll.getId(), mainFragment, "mainFragment").commit();
fragContainer.addView(ll);
activity_main.xml (first APK):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#+id/main_fragment"
android:orientation="vertical"
/>
</LinearLayout>
MainFragment.java (second APK):
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, viewGroup, false);
view.findViewById(R.id.emailSignInButton).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
}
});
return view;
}
fragment_main.xml (second APK):
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:text="#string/sign_in"
android:layout_width="88dp"
android:layout_height="wrap_content"
android:id="#+id/emailSignInButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="32dp"
android:layout_marginEnd="32dp" android:layout_marginTop="8dp"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
I don't understand, why in the line
View view = inflater.inflate(R.layout.fragment_main, viewGroup, false);
view is always NULL. Do I need to load R.layout.fragment_main into memory like mainFragment?
#CommonsWare already answered you: you are loading classes, not resources.
In Android´s packages, you have both classes (Like R), and resources (Preprocessed XML files, like layouts, for example). A ClassLoader is capable of reading and loading the first ones, so, loading another´s APK R class is possible. But R´s indexes just point towards resource files, they don´t contain the actual values of said resources. So, the R class you sideloaded does not provide the route to a valid resource. If R could do that, then the APK/AAR/APKLib formats would not exists; regular JAR files would suffice. But they don`t,because android resource files are different from class files, and thus, a "link" of sorts is necessary to make them visible to your classes: the R class.
if you want to make your current code work, you need to replace fragment_main.xml with a coded viewgroup instance. Create a class/method providing a constraintLayout instance housing your button (MyViewFactory.createConstraintLayoutWithButton, for example), set the properties via code, and replace
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, viewGroup, false);
view.findViewById(R.id.emailSignInButton).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
}
});
return view;
}
with something like
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
View view = MyViewFactory.createConstraintLayoutWithButton(getContext)
view.findViewById(R.id.emailSignInButton).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
}
});
return view;
}
As long as you don´t use resources, you´ll be fine. That said, this approach is quite fragile, so maybe it would be better to create intent filters between your APKs in order to make APK 2 to work for APK 1.
Edit:
You can use the R constants as ids for your code generated views, as long as you set them manually first. For example:
public static ConstraintLayout createConstraintLayoutWithButton(Context context){
Constraintlayout mylayout = new ConstraintLayout(context);
//set up of the layout
Button myButton = new Button(context);
//set up of the button
button.setId(R.id.emailSignInButton);
myLayout.addView(button);
return mylayout;
}
And then you can locate that button with the id.
I have read all the other topics related to this issue and none seem to be helping me solve the problem.
I am doing some background task in an asynctask that needs to persist on orientation change (configChanges). I have gotten the data to persist I believe by using fragments and setRetainInstance(true), but my buttons (Im assuming any views really) are being set to null on recreation of the fragment on orientation change. This is causing a null pointer error when I try to operate on the buttons reference after orientation has change (fragment has been recreated).
I have tried wrapping the button and calls on the button in a statement to check if the bundle is null. This stops the crash but does not allow for the button to be used again on recreation of the fragment.
The following class extends Fragment.
#Override
public void onCreate(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreate()");
super.onCreate(savedInstanceState);
setRetainInstance(true);
currentActivity = super.getActivity();
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onActivityCreated(Bundle)");
super.onActivityCreated(savedInstanceState);
simpleForecastIntent = new Intent(currentActivity, SimpleForecastActivity.class);
Button fetchDataButton = (Button) currentActivity.findViewById(R.id.fetchDataButton);
if (savedInstanceState == null) {
fetchDataButton.setOnClickListener(fetchDataButtonListener);
fetchDataButton.setTransformationMethod(null);
}
locationManager = (LocationManager)
currentActivity.getSystemService(Context.LOCATION_SERVICE);
if (isTaskRunning) {
progressDialog = ProgressDialog.show(currentActivity, "Fetching data", "Please wait...");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreateView(LayoutInflater, ViewGroup, Bundle)");
return inflater.inflate(R.layout.main_menu, container, false);
}
main_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activities.MainActivity">
<include layout="#layout/toolbar" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<Button
android:id="#+id/fetchDataButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/locationField"
android:text="#string/fetch_weather_data"
android:layout_centerHorizontal="true" />
<EditText
android:id="#+id/locationField"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="#string/enter_location"
android:layout_alignEnd="#+id/fetchDataButton"
android:layout_alignLeft="#+id/fetchDataButton"
android:layout_alignRight="#+id/fetchDataButton"
android:layout_alignStart="#+id/fetchDataButton"
android:inputType="textPostalAddress" />
<ListView
android:id="#+id/previousLocationsList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/fetchDataButton"
android:layout_centerHorizontal="true" />
</RelativeLayout>
</LinearLayout>
I have spent far too many hours on something so trivial and really need a bump in the correct direction. How can I get the button to not be null on recreation of fragment?
EDIT SOLVED:
I was using the disposed of activity's context to find the view of the button. Instead of the new activities view context.
#Override
public void onCreate(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreate()");
super.onCreate(savedInstanceState);
setRetainInstance(true);
currentActivity = super.getActivity();
}
The problem is that you are referencing your button in onActivityCreated instead of onCreateView. On orientation change, the view gets torn down and then recreated. You should override onCreateView and maintain the reference to your button from there.
UPDATE:
I see how your code is working, but in my opinion it's following a bad design pattern. You are still instantiating your view references inside of onActivityCreated, instead of immediately after they are inflated in onCreateView.
I would switch it to something like this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreateView(LayoutInflater, ViewGroup, Bundle)");
View root = inflater.inflate(R.layout.main_menu, container, false);
Button fetchDataButton = (Button) root.findViewById(R.id.fetchDataButton);
...
return root;
}
Im trying to get the TextViews shown in my faq_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/question_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAlignment="center"
android:text="Title 1"/>
<TextView
android:id="#+id/answer_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAlignment="center"
android:text="Description 1"
android:textColor="#33000000"
android:layout_marginTop="5dp"/>
</LinearLayout>
In my Fragment class
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
((TextView)container.findViewById(R.id.question_text)).setText(title);
((TextView)container.findViewById(R.id.answer_text)).setText(description);
return inflater.inflate(R.layout.faq_fragment, container, false);
}
App is crashing and Im getting error:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
You need to inflate the view before using it.
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.faq_fragment, container, false);
((TextView)view .findViewById(R.id.question_text)).setText(title);
((TextView)view .findViewById(R.id.answer_text)).setText(description);
return view;
}
You should use the inflated view:
Change it to:
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.faq_fragment, container, false);
((TextView)view.findViewById(R.id.question_text)).setText(title);
((TextView)view.findViewById(R.id.answer_text)).setText(description);
return view;
}
I'm simply trying to change the text of a textView that is located within the actual fragment. It isn't throwing any error but it simply isn't updating. Aside from this the fragment successfully attaches to the activity via a viewpager.
The fragment:
public class FragmentPlotData extends Fragment {
public static TextView textViewPlotData;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_plot_data, container, false);
textViewPlotData = (TextView) view.findViewById(R.id.textViewPlotData);
textViewPlotData.setText("Changed text ");
return inflater.inflate(R.layout.fragment_plot_data, container, false);
}
}
The fragment's layout:
<TextView
android:id="#+id/textViewPlotData"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="30sp"
android:textColor="#color/black_process_2"
android:text="#string/original text"
android:gravity="center"/>
</RelativeLayout>
You should return view in onCreateView, don't inflate a new layout like that.
Just replace:
return inflater.inflate(R.layout.fragment_plot_data, container, false);
to:
return view;
i'm trying to create a fragment dialog and need the full space to display information. so i want to disable the titlebar. But after i disabled it the isn't maximized in width anymore.
public class ArticleSearchFragment extends DialogFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(STYLE_NO_TITLE, getTheme());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.article_search, container, false);
...
}
And the XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<AutoCompleteTextView
android:id="#+id/searchField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Ean / Name / Produkt Nummer"
android:completionThreshold="1" />
<Button
android:id="#+id/cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/cancel" />
</LinearLayout>
put this code in your onCreateView() of dialog fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_view_image, null);
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
return view;
}
It will remove title bar from Dialog Fragment