I have two fragments and a main activity. The first fragment, FriendsFragment (extends ListFragment) is displayed on the screen and when the user clicks an item, the main Activity replaces the FriendsFragment with FeedFragment, then calls a method from FeedFragment to update the textView.
I'm getting an error that the textView object in the FeedFragment class is null even though I instantiate using the findViewById method.
I have looked at related questions and have tried the solutions but nothing is working. I've tried doing getView().findViewById(R.id.feed_view), getActivity().findViewById(R.id.feed_view), and I've tried putting these in onActivityCreated() and onCreateView()
The only thing that worked is writing this code in onActivityCreated():
text = getView().findViewById(R.id.feed_view);
text.setText("some string");
but this is not what I want
FeedFragments.java
public class FeedFragment extends Fragment {
private static String TAG = "Feed Fragment";
private TextView text;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
Log.i(TAG, "Entered FeedFragment.java onActivityCreated()");
super.onActivityCreated(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
Log.i(TAG, "Entered FeedFragment.java onCreateView()");
View v = inflater.inflate(R.layout.fragment_feed, container,false);;
text = v.findViewById(R.id.feed_view);
return v;
}
public void updateDisplay(int position)
{
Log.i(TAG, "FeedFragment.java: updateDisplay()");
text.setText(position);
}
MainActivity.java
// previously declared feedFragment: feedFragment = new FeedFragment();
public void onItemSelected(int position)
{
Log.i(TAG, "Entered onItemSelected(" + position + ")");
fragManager = getFragmentManager();
FragmentTransaction fragTransaction = fragManager.beginTransaction();
fragTransaction.replace(R.id.fragment_container, feedFragment, "feed_fragment");
fragTransaction.addToBackStack(null);
fragTransaction.commit();
feedFragment.updateDisplay(position);
}
fragment_feed.xml
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/feed_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/greeting" />
</ScrollView>
activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
onViewcreated() is being called after updateDisplay() because the system doesn't run it right away.
you need to pass a value to the feedFragment on it's creation and store it in a bundle and retrieve it after the fragment internal code is run by the system.
the way you solve it is like this:
when you instantiate feedFragment you do it like this:
feedFragment = FeedFragment.newInstance(position)
and inside FeedFragment class you should have a static code:
private static final String ARG_PARAM1 = "param1";
public static FeedFragment newInstance(int param1) {
FeedFragment fragment = new FeedFragment();
Bundle args = new Bundle();
args.putInt(ARG_PARAM1, param1);
fragment.setArguments(args);
return fragment;
}
and non static code:
private int mParam1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getInt(ARG_PARAM1);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
Log.i(TAG, "Entered FeedFragment.java onCreateView()");
View v = inflater.inflate(R.layout.fragment_feed, container,false);;
text = v.findViewById(R.id.feed_view);
text.setText(String.valueOf(mParam1));
return v;
}
I wrapped mParam1 in String.valueOf() because when you pass integer to setText it thinks you try to use a Strings.xml resource instead of the number you chose.
also I used very generic variable names. please change them to something meaningful so that your code makes sense.
Related
I have a working "folder explorer" for the internal storage only. But I want to improve that explorer to use internal and external storage. I want something like this:
Bellow is the basic code of my working folder explorer (internal storage only):
select_folders.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
SelectFoldersActiviy.java
public class SelectMusicFolderActivity extends AppCompatActivity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragmentContainer, FoldersFragment.newInstance(path))
.commit();
}
}
...
}
The following fragment class uses a ListView to list all subfolders for a folder. In the onItemClick() method of the ListView objet I instantiate a new fragment with the current item path as argument. Like so:
FoldersFragment.java
public class FoldersFragment extends Fragment {
...
private static final String RUTA_KEY = "ruta";
private final String PATH = "ruta";
public static FoldersFragment newInstance(String ruta) {
FoldersFragment fragment = new FoldersFragment();
Bundle args = new Bundle();
args.putString(RUTA_KEY, ruta);
fragment.setArguments(args);
return fragment;
}
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
ruta = getArguments().getString(RUTA_KEY);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
getActivity().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragmentContainer,
FoldersFragment.newInstance(currentItemPath))
.addToBackStack(null)
.commit();
}
}
}
With what I can combine the viewpager2 to get the aproach of the image?
I tried with fragmentcontainerview inside viewpager2, but viewpager2 dont support direct childs.
I tried with NavHostFragment too, but that needs a predefined navigation graph, and the number of folders is undetermined.
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 1 year ago.
First of all, I am absolute beginner for this, I'm sorry if this such a dumb mistakes. But I always got this error
java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.recyclerview.widget.RecyclerView.setLayoutManager(androidx.recyclerview.widget.RecyclerView$LayoutManager)' on a null object referenceat com.example.loginregister.ui.home.HomeFragment$1.onResponse(HomeFragment.java:104)
whenever I tried to run my app. I already changed getActivity() to HomeFragment.this , or getApplicationActivity() but still error, I'm stuck this for a long time because I not really understand how it's work, I hope someone can explain to me how to call context in fragment, here my java
public class HomeFragment extends Fragment {
private RecyclerView rvData;
private RecyclerView.Adapter adData;
private RecyclerView.LayoutManager lmData;
private List<DataModel> listData = new ArrayList<>();
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rvData = getActivity().findViewById(R.id.rv_user);
lmData = new LinearLayoutManager(getActivity(),LinearLayoutManager.VERTICAL,false);
rvData.setLayoutManager(lmData);
retrieveData();
return inflater.inflate(R.layout.fragment_home, container, false);
}
public void retrieveData(){
APIRequestData ardData = RetroServer.connectRetrofit().create(APIRequestData.class);
Call<ResponseModel> showData = ardData.ardRetrieveData();
showData.enqueue(new Callback<ResponseModel>() {
#Override
public void onResponse(Call<ResponseModel> call, Response<ResponseModel> response) {
int code = response.body().getCode();
String message = response.body().getMessage();
Toast.makeText(getActivity(), "Code: "+code+"| Message: "+message, Toast.LENGTH_SHORT).show();
listData = response.body().getData();
adData = new AdapterData(getActivity(),listData);
rvData.setLayoutManager(lmData);
adData.notifyDataSetChanged();
}
#Override
public void onFailure(Call<ResponseModel> call, Throwable t) {
Toast.makeText(getActivity(), "Fail to Retrieve Data", Toast.LENGTH_SHORT).show();
}
});
}
and here is my fragment_home.xml
<?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"
tools:context=".ui.home.HomeFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_user"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="#layout/card_item"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
use this code
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, container, false);
rvData = view.findViewById(R.id.rv_user);
return view;
}
As I see your layout is supposedly layout for a fragment. You should edit your code like this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View inflate = inflater.inflate(R.layout.fragment_home.xml, container, false);
rvData = inflate.findViewById(R.id.rv_user);
lmData = new LinearLayoutManager(getActivity(),LinearLayoutManager.VERTICAL,false);
rvData.setLayoutManager(lmData);
retrieveData();
return inflate;
}
If you really need your "context" basically the private fragment variable
private Context context;
Then you may retrieve it in onAttach method somewhat like this:
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
this.context = context;
}
This enables you to use context specific features like getting colors etc.
I have created an activity that I am using for barcode scanning. The onCreate looks like this:
public class GradeScreenScanner extends AppCompatActivity implements ZXingScannerView.ResultHandler {
public static final int REQUEST_CAMERA = 1;
protected ZXingScannerView scannerView;
protected FirebaseFirestore db;
protected String scanResult;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
scannerView = new ZXingScannerView(this);
setContentView(scannerView);
db = FirebaseFirestore.getInstance();
}
}
Once I have a result I am then wanting to launch a new fragment like so:
android.app.FragmentManager fragmentManager = getFragmentManager();
ScreenFragment screenFragment = new ScreenFragment();
screenFragment.db = db;
screenFragment.serialNumberScanned = serialNumberScanned;
fragmentManager.beginTransaction()
.addToBackStack("screen")
.replace(R.id.content_frame, screenFragment)
.commit();
But I get the following error that I am not sure how to deal with:
java.lang.IllegalArgumentException: No view found for id 0x7f08005a (uk.wefix:id/content_frame) for fragment ScreenFragment{6262536 #1 id=0x7f08005a}
Just in case, the fragments onCreate looks like this:
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
myView = inflater.inflate(R.layout.grade_screens_layout, container, false);
return myView;
}
Help appreciated.
#Override
public void setContentView(View view) {
getDelegate().setContentView(view);
}
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/content_frame"/>
Was missing from the xml in the activity view. My error, well spotted Umair
yes , usually when you get No view found for id or nullPointer i suggest you to check:
1-android:id="#+id/
2- findViewById
3- in the java class the variable declaration
in most cases it works ;)
good luck.
I want to have an information fragment on a sliding tab fragment, and be able to pass in some parameter to the information fragment when creating it. I've put (hopefully all) the relevant code below:
InfoFragment.java:
public class InfoFragment extends Fragment
{
private static final String HEADER_ARG = "HEADER";
private String header;
/**
* Use this factory method to create a new instance of this fragment using the provided parameters.
*/
public static InfoFragment newInstance(String header)
{
InfoFragment fragment = new InfoFragment ();
Bundle args = new Bundle();
args.putString(HEADER_ARG, header);
fragment.setArguments(args);
return fragment;
}
/**
* Required empty public constructor
*/
public InfoFragment() {}
/**
* Gets the args out of the bundle
*/
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (getArguments() != null)
{
this.header = getArguments().getString(HEADER_ARG);
}
else
{
Log.e("Frag", "Args = null");
}
}
// Rest of Fragment...
}
TabFragment.java:
public class TabFragment extends Fragment
{
/**
* Mandatory empty constructor for the fragment manager to instantiate the fragment (e.g. upon screen orientation changes).
*/
public TabFragment() {}
/**
* Create the Inventories tab view
*/
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.tab_2, container, false);
return view;
}
/**
* Dynamically add fragments
*/
#Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
InfoFragment infoFrag = InfoFragment.newInstance("MyHeader");
FragmentManager fm = getChildFragmentManager();
fm.beginTransaction().add(R.id.info_fragment, infoFrag);
}
// Rest of TabFragment...
}
tab_fragment.xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment
android:id="#+id/character_item_fragment_1"
android:name="lomax.mycharacter3.InfoFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
The console log shows that the getArgs() = null, and I have no idea why. Any ideas?
Because you're using fragment tag, your fragment will be instantiated using empty constructor, also you forgot to call commit at the end on transaction, that's why you didn't get exception about view with missing id.
Fixed version:
tab_fragment.xml:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/info_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Code:
InfoFragment infoFrag = InfoFragment.newInstance("MyHeader");
FragmentManager fm = getChildFragmentManager();
fm.beginTransaction().add(R.id.info_fragment, infoFrag).commit();
I followed this question and tried my hand at calling a method which is in my Fragment. I'm trying to call the method from an activity. However it's not recognizing the fragment's method. Here's my code:
XML:
<RelativeLayout
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:id="#+id/peoplefragment">
<ListView
android:id="#+id/searchpeople_list"
android:layout_height="fill_parent"
android:layout_width="match_parent"
android:scrollbars="none"
android:background="#fff">
</ListView>
</RelativeLayout>
Fragment Code:
public class SearchPeopleTab extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.activity_search_people_tab, container, false);
View rootView = inflater.inflate(R.layout.activity_search_people_tab, container, false);
return rootView;
}
public static void UpdateResults(String requestSearch)
{
new GetSearchResults(requestSearch).execute();
}
class GetSearchResults extends AsyncTask<Void, Void, Void> {
String requestSearch;
GetSearchResults(String searchtext)
{
this.requestSearch = searchtext;
}
#Override
protected Void doInBackground(Void... params) {
}
Activity Code: (Calling the Fragment's method)
private void PopulateResults() {
FragmentManager manager = (FragmentManager) getSupportFragmentManager();
Fragment fragment = manager.findFragmentById(R.id.peoplefragment);
fragment.UpdateResults(requestSearch); //thats the method in the fragment.
}
The 'UpdateResults()' part is underlined and the following message is given as an error:
Cannot resolve method UpdateResults()
Looks like it can't find the method. What am I doing wrong?
Remove the keyword static from the method.
And also, store the fragment in the SearchPeopleTab reference variable, that you created.
You don't really need the line to store the FragmentManager, you can directly use getSupportFragmentManager();
//FragmentManager fm = (FragmentManager) getSupportFragmentManager();
SearchPeopleTab fragment = (SearchPeopleTab) getSupportFragmentManager().findFragmentById(R.id.peoplefragment);
fragment.UpdateResults();
When static methods are used, they are called using the class name. When you want a method to be called on specific objects, the method should not be static.
You need to cast the Fragment to your defined class
private void PopulateResults() {
FragmentManager manager = (FragmentManager) getSupportFragmentManager();
SearchPeopleTab fragment = (SearchPeopleTab)manager.findFragmentById(R.id.peoplefragment);
fragment.UpdateResults(); //thats the method in the fragment.
}