I have a fragment which doesn't contain anything at the application start, but after the data is loaded it should show the loaded data. I do all my data loading in MainActivity in function onDataLoaded which implements DataLoadedListener. After the data is loaded the function sends the data (ArrayList) as a parameter through the function call (initializeAdapter()). Then, the function initializeAdapter() gets it and initialize custom made adapter (adapter is a global object, initialized in initializeAdapter() and used in onCreateView()).
I guess that I should refresh fragment view after the data is loaded and the adapter is initialized, but I don't know how to do it. I tried in a lot of ways but didn't make it.
onDataLoaded function in MainActivity which calls initializeAdapter()
#Override
public void onDataLoaded(List<Grad> gradovi, List<Ponuda> ponude) {
Spinner spinnerGradovi = (Spinner) findViewById(R.id.gradovi_spinner);
ArrayAdapter<String> adapterGradovi;
List<String> listaGradova = new ArrayList<>();
ArrayList<Ponuda> ponudaArrayList = new ArrayList<Ponuda>();
ponudaLista = ponude;
gradLista = gradovi;
for(Grad grad : gradovi ){
listaGradova.add(grad.getNaziv());
}
for(Ponuda ponuda : ponude){
ponudaArrayList.add(ponuda);
}
adapterGradovi = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, listaGradova);
spinnerGradovi.setAdapter(adapterGradovi);
Fragment fragmentGet = svePonudeFragment;
((SvePonudeFragment)fragmentGet).initializeAdapter(ponudaArrayList);
}
and this is a Fragment
public class SvePonudeFragment extends Fragment {
private RecyclerView rv;
RVAdapter adapter;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.sve_ponude_fragment, container, false);
rv = (RecyclerView) rootView.findViewById(R.id.rv);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
rv.setLayoutManager(llm);
rv.setAdapter(adapter);
return rootView;
}
public void initializeAdapter(List<Ponuda> preuzetePonude){
adapter = new RVAdapter(preuzetePonude);
//this isn't working
/*FragmentManager manager = getActivity().getSupportFragmentManager();
android.support.v4.app.FragmentTransaction ft = manager.beginTransaction();
ft.detach(this).attach(this).commit();*/
//this is not working, neither
Fragment frg = getFragmentManager().findFragmentByTag("sve_ponude_fragment_tag");
final android.support.v4.app.FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.detach(frg);
ft.attach(frg);
ft.commit();
}
}
I am also interested in how to make an empty adapter which loads if data is not loaded yet? And when the data is loaded to fill out another adapter and use it.
Initialize adapter before you set. If you interested to change you approach I can give suggestions: Create a constructor for you fragment which you can pass the ArrayList. OnCreate or OnCreateView you can initialize the adapter and pass the list into. After setting adapter notifyDataChanges and to check if there is data please use some Logs when you pass the data and before you pass the data. Do not directly blame the adapter or fragment control your data. Besides I suggest you to study more using fragments + RecyclerView. I am posting one example that you can look at but the data load in the fragment.
public class CategoryFragment extends Fragment {
//Class Tag
private static final String TAG = CategoryFragment.class.getSimpleName();
//Fragments base context
private Context mContext;
//RecyclerView widget
private RecyclerView mRecyclerView;
//RecyclerView's Layout Manager
private RecyclerView.LayoutManager mLayourManager;
//RecyclerView's Adapter
private CategoryFragmentAdapter mCategoryFragmentAdapter;
//Category Data List
private ArrayList<Category> mCategoryList;
//Interface object
onCategoryItemClick mCallBackCategory;
#Override
public void onAttach(Context context) {
super.onAttach(context);
//Instantiate base context
mContext = context;
//Instantiate interface
mCallBackCategory = (onCategoryItemClick)getActivity();
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Instantiate Category List
mCategoryList = new ArrayList<Category>();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
//Custom fragment view instantiating
View view_fragment_category = inflater.inflate(R.layout.fragment_items, container, false);
//Instantiating Fragment's recycler view
mRecyclerView = (RecyclerView) view_fragment_category.findViewById(R.id.recycle_categories);
//Instantiate RecycleView's Layout Manager: LinearLayoutManager is one of the default
mLayourManager = new LinearLayoutManager(mContext);
//Setting layout manager for recycler view
mRecyclerView.setLayoutManager(mLayourManager);
//Retrieve data from server, populate the category data list and set the RecyclerView's adapter
getCategories();
//Instantiate the adapter and push the data
mCategoryFragmentAdapter = new CategoryFragmentAdapter(mContext, mCategoryList);
//RecyclerView item click listener
mCategoryFragmentAdapter.SetOnItemClickListener(new CategoryFragmentAdapter.OnItemClickListener() {
#Override
public void onItemClick(View v , int position) {
//Test display
//Toast.makeText(mContext, mCategoryList.get(position).getId(),Toast.LENGTH_LONG).show();
//Push to Activity method with clicked item ID
mCallBackCategory.proceedToProducts(mCategoryList.get(position).getId());
}
});
return view_fragment_category;
}
Related
I have a ListView in a Fragment that is populated when the app starts.
I put a ParcelableArrayList in a Bundle in my newInstance method, and I get it back in my OnCreateView after passing the ArrayList in the newInstance method in my Activity (which is the data read from the SQLite database).
This part works, as I display my data in my Fragment correctly.
I implemented a button that removes all data from the table, and I would now like to update my view after I cleaned the table.
The remove all button is handled in my main activity where I call my database handler to empty the table.
What is the best way to do that ? Here are the parts of the code that seem relevant to me :
My Fragment class :
public class MainFragment extends Fragment {
public static final String RECETTES_KEY = "recettes_key";
private List<Recette> mRecettes;
private ListView mListView;
public MainFragment() {
// Required empty public constructor
}
public static MainFragment newInstance(List<Recette> r) {
MainFragment fragment = new MainFragment();
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(RECETTES_KEY, (ArrayList<? extends Parcelable>) r);
fragment.setArguments(bundle);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mRecettes = getArguments().getParcelableArrayList(RECETTES_KEY);
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_main, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
configureListView();
}
// Configure ListView
private void configureListView(){
this.mListView = getView().findViewById(R.id.activity_main_list_view);
RecetteAdapter adapter = new RecetteAdapter(getContext(), mRecettes);
mListView.setAdapter(adapter);
}
}
Relevant parts from my Main acivity :
This is in my OnCreate method :
mDatabaseHandler = new DatabaseHandler(this);
mRecettes = mDatabaseHandler.readRecettes();
mDatabaseHandler.close();
This is in the method I use to show a fragment :
if (this.mMainFragment == null) this.mMainFragment = MainFragment.newInstance(mRecettes);
this.startTransactionFragment(this.mMainFragment);
Let me know if I should add more of my code, this is my first time posting :)
Lucile
In your R.layout.fragment_main, you can add an id to the root view, say with android:id#+id/fragment_root
And whenever you want to change the fragment view:
In activity:
MainFragment fragment = (MainFragment) getSupportFragmentManager().getFragmentById(R.id.fragment_root);
fragment.updateList(mRecettes);
And then create the new method updateList() in your MainFragment
public void updateList(List<Recette> recettes) {
mRecettes.clear();
mRecettes.addAll(recettes);
configureListView();
}
Also you can tag your fragment when you add it to your transaction instead of using its id, and then use getSupportFragmentManager().getFragmentByTag()
I am trying to get an ArrayList from an activity and then display it inside a fragment in a custom adapter. The problem it's that I cannot setAdapter to do so. The error it says the context it's wrong, when I created the Adapter.
Creare_istoricAdapter class:
public class Creare_istoricAdapter extends ArrayAdapter<Creare_istoric> {
private static final String TAG = "Creareistoric_adapter";
private Context mContext;
int mResource;
public Creare_istoricAdapter(#NonNull Context context, int resource, #NonNull ArrayList<Creare_istoric> objects) {
super(context, resource, objects);
mContext = context;
mResource = resource;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
String id_alerta = getItem(position).getId_alerta();
String tip_problema = getItem(position).getTip_problema();
String data_ora= getItem(position).getData_ora();
String stare_problema = getItem(position).getStare_problema();
String descriere = getItem(position).getDescriere();
Creare_istoric istoric = new Creare_istoric(id_alerta, tip_problema, data_ora, stare_problema, descriere);
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(mResource, parent, false);
TextView text_tip_alerta_istoric = convertView.findViewById(R.id.text_tip_alerta_istoric);
TextView text_ora_alerta_istoric = convertView.findViewById(R.id.text_ora_alerta_istoric);
TextView text_stare_alerta_istoric = convertView.findViewById(R.id.text_stare_alerta_istoric);
text_tip_alerta_istoric.setText(tip_problema);
text_ora_alerta_istoric.setText(data_ora);
text_stare_alerta_istoric.setText(stare_problema);
return convertView;
}
}
The fragment class:
public class Fragment_alerte_trimise extends Fragment {
public Fragment_alerte_trimise(){}
ListView list_view_alerte_trimise;
ArrayList<Creare_istoric> alerteTrimise= new ArrayList<>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View alerte_trimise = inflater.inflate(R.layout.fragment_alerte_trimise,container, false);
return alerte_trimise;
Bundle bundle_trimise;
if (bundle_trimise != null) {
alerteTrimise = bundle_trimise.getParcelableArrayList("alerte_trimise");
}
list_view_alerte_trimise =getView().findViewById(R.id.list_view_alerte_trimise);
Creare_istoricAdapter adapter = new Creare_istoricAdapter(this, R.layout.istoric_alerte_adapter, alerteTrimise);
list_view_alerte_trimise.setAdapter(adapter);
}
}
The problems it's in new Creare_istoricAdapter(this, R.layout.istoric_alerte_adapter, alerteTrimise) , about the context, and is also greyed out, saying it's redundant.
EDIT:
I have changed the code following the answers below, but now when I open the activity that uses the fragment, it does not show the list at all. It's only an blank screen.
The fragment code:
public class Fragment_alerte_trimise extends Fragment {
public Fragment_alerte_trimise(){}
private ListView list_view_alerte_trimise;
ArrayList<Creare_istoric> alerteTrimise= new ArrayList<>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View alerte_trimise = inflater.inflate(R.layout.fragment_alerte_trimise,container, false);
return alerte_trimise;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Bundle bundle_trimise = getArguments();
if (bundle_trimise != null) {
alerteTrimise = bundle_trimise.getParcelableArrayList("alerte_trimise");
}
list_view_alerte_trimise =getView().findViewById(R.id.list_view_alerte_trimise);
list_view_alerte_trimise.setAdapter(new Creare_istoricAdapter(getContext(), R.layout.istoric_alerte_adapter, alerteTrimise));
}
}
The way I created the Parceable:
Bundle bundle_trimise = new Bundle();
bundle_trimise.putParcelableArrayList("alerte_trimise", alerteTrimise);
Fragment_alerte_trimise fg = new Fragment_alerte_trimise();
fg.setArguments(bundle_trimise);
I have the ListView created in the layout that's inflated by the onCreateView, but when I use getView().findViewById it says that it may produce 'NullPointerException', and so does the getContext(), which says it might be null
Please try to use getContext() instead of this.
You have to use activity context instead of fragment context this. Instead of using getContext() or getActivity() you should initialize the context on onAttach to avoid NullPointerException. Check below:
private Context activityContext;
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
activityContext = context;
}
#Override
public void onDetach() {
super.onDetach();
activityContext = null;
}
Beside this, you have to return the view inside onCreateView at the very end. Check below:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
....
// use alerte_trimise instead of getView()
list_view_alerte_trimise = alerte_trimise.findViewById(R.id.list_view_alerte_trimise);
//use activityContext instead of this
Creare_istoricAdapter adapter = new Creare_istoricAdapter(activityContext, R.layout.istoric_alerte_adapter, alerteTrimise);
....
return alerte_trimise;
}
In your code, you try to use Bundle after call return. That's why rest of your code is unreachable.
You are using Creare_istoricAdapter in your Fragment_alerte_trimise so it needs context. therefor we can give activity context or application context(beyond the activity level)
Moreover...
getContext() - Returns the context view only current running activity.
getActivity()- Return the Activity this fragment is currently associated with.
getActivity() can be used in a Fragment for getting the parent Activity of the Fragment.
Add this code changes to your code.
getActivity().getApplicationContext()
Use getContext() instead of this. this refers to current object (Fragment), which is not subclass of Context.
Create adapter in onViewCreated(), because getContext() returns null in onCreateView().
I tried to use arraylist in fragment
my arraylist not work in fragment class.
please help me fix this
before I use this code in main activity, and then I added menu fragment I move this code to this fragment
and then my arraylist get error
this error " 'RelativeLayout(anroid.content.Context)' in 'android.widget.RelativeLayout' cannot be applied to '(com.cupaxxhd.mysurah.HomeFragment)' "
and this " 'MyAdapter(android.content.Context, java.util.Arraylist)' in 'com.cupaxxhd.mysurah.Myadapter' cannot be applied to '(com.cupaxxhd.mysurah.HomeFragment, java.util.Arraylist)'
public class HomeFragment extends Fragment {
RecyclerView mRecyclerView;
MyAdapter myAdapter;
public HomeFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_home, container, false);
mRecyclerView = v.findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new RelativeLayout(this));
myAdapter = new MyAdapter(this, getMyList());
mRecyclerView.setAdapter(myAdapter);
return v;
}
private ArrayList<Model> getMyList(){
ArrayList<Model> models = new ArrayList<>();
Model m = new Model();
m.setTitle("Al-Lahab");
m.setDescription("Surah Al-Lahab adalah surat ke-111 dalam Al-Qur'an.");
m.setDetails("تَبَّتْ يَدَا أَبِي لَهَبٍ وَتَبّ\n"
);
m.setImg(R.drawable.al_lahab);
models.add(m);
return models;
}
You need to pass Context instead of fragment instance and use LayoutManager instead of RelativeLayout. Like this:
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
new MyAdapter(getActivity(), getMyList());
the ProgressBar doesn't disappear in the fragment also items aren't loaded in the RecyclerView, When the code was in the body of onCreate of the main activity ,it was working
I am making fragment that contains ProgressBar and RecyclerView with retrieving data from firebase database , I added setVisibility at the end of onDataChange method so that after getting all the data and store it in the array list , the ProgressBar disappear
RecyclerView offersRecycler;
ArrayList<offer> offers;
OffersAdapter offersAdapter;
View fragment_layout;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
fragment_layout = inflater.inflate(R.layout.fragment_offers, container, false);
// Offers RecyclerView
offersRecycler = fragment_layout.findViewById(R.id.offersRecycler);
offers = new ArrayList();
offers_init();
offersAdapter = new OffersAdapter(offers,getContext());
offersRecycler.setAdapter(offersAdapter);
offersRecycler.setLayoutManager(new LinearLayoutManager(getContext()));
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_offers, container, false);
}
private void offers_init() {
DatabaseReference db_offers = db_ref().child("offers");
db_offers.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
try {
ProgressBar loadingOffers = fragment_layout.findViewById(R.id.loadingOffers);
loadingOffers.setProgress(10);
for (DataSnapshot offer_item : dataSnapshot.getChildren()) {
String id = offer_item.getKey();
String title = offer_item.child("title").getValue().toString();
String rating = offer_item.child("rating").getValue().toString();
String orders_number = offer_item.child("orders_number").getValue().toString();
offer offer_object = new offer(id,title, rating, orders_number);
offers.add(offer_object);
offersAdapter.notifyDataSetChanged();
}
Toast.makeText(getContext(),"title",Toast.LENGTH_LONG).show();
loadingOffers.setVisibility(View.GONE);
}catch (Exception ex){
Toast.makeText(getContext(),ex.getMessage(),Toast.LENGTH_LONG).show();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
}
I expect the ProgressBar to hide and the array loaded into the RecyclerView
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
fragment_layout = inflater.inflate(R.layout.fragment_offers, container, false);
// Offers RecyclerView
offersRecycler = fragment_layout.findViewById(R.id.offersRecycler);
offers = new ArrayList();
offers_init();
offersAdapter = new OffersAdapter(offers,getContext());
offersRecycler.setAdapter(offersAdapter);
offersRecycler.setLayoutManager(new LinearLayoutManager(getContext()));
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_offers, container, false);
}
^ This is your code snippet. What you are doing is - inflating a layout fragment_layout = inflater.inflate(R.layout.fragment_offers, container, false) and using fragment_layout to get the instance of RecyclerView. This is fine.
But at the end of the method, you are inflating a new layout and returning that. So the Android framework uses that View instead of fragment_layout to set the Fragment view. All the views in fragment_layout won't be shown since it's never added to the fragment and hence you don't see any changes in the RecyclerView.
At the end of the onCreateView method, you should just return fragment_layout.
in your CreateView, change
return inflater.inflate(R.layout.fragment_offers, container, false);
by
return fragment_layout;
You call the layout, init recyclerview, but recall the "blank" layout
Also, avoid underscore for method or variable name, it's not the java convention
I have been tasked with creating a very unorthodox layout that can only be accomplished with a viewpager inside the second pane of another viewpager, thankfully the outer viewpager needs to be locked so the task was a little more realistic, however the unexpected issue arose where after the inner viewpager was loaded onCreateView is never called, I can see that it is sliding side to side so the inner viewpager is setup but it will not load any inner view for some odd reason, any help will go a long way thanks
Main Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_fragment);
pagePosition = 0;
setupViews();
}
private void setupViews() {
//setup images to be changed later
ivCategory = (ImageView) findViewById(R.id.ivCatergory);
ivHome = (ImageView) findViewById(R.id.ivHome);
ivProfile = (ImageView) findViewById(R.id.ivProfile);
//setup the viewpager
pager = (CustomViewPager) findViewById(R.id.viewpager);
//add fragments to the fragment array
pageList.add(NavigationFragment.newInstance(0, getApplicationContext(), this));
pageList.add(NavigationFragment.newInstance(1, getApplicationContext(), this));
pageList.add(NavigationFragment.newInstance(0, getApplicationContext(), this));
// initialize the page adapter
pageAdapter = new FragmentHomeAdapter(getSupportFragmentManager(), pageList);
//set the page adapter to the viewpager
pager.setAdapter(pageAdapter);
//set homepage to be first
pager.setCurrentItem(1);
//disable swiping to mimic iphone behaviour
pager.setPagingEnabled(false);
}
viewpager
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
int pageType = getArguments().getInt(PAGE_TYPE);
View v;
if (pageType == 1) {//all inner fragments will happen here
v = inflater.inflate(R.layout.fragment_container, container, false);
//setup the inner viewpager
pager = (CustomViewPager) v.findViewById(R.id.viewpager);
pageList.add(HomeFragment.newInstance(0, context, getActivity()));
pageList.add(HomeFragment.newInstance(1, context, getActivity()));
// initialize the page adapter
pageAdapter = new FragmentHomeAdapter(getActivity().getSupportFragmentManager(), pageList);
//set the page adapter to the viewpager
pager.setAdapter(pageAdapter);
pager.setPagingEnabled(true);
}
return v;
}
inner viewpager
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v;
v = inflater.inflate(R.layout.fragment_list_feed, container, false);
lv = (ListView) v.findViewById(R.id.lvFeed);
listAdapter = new ListHomeAdapter(getArguments().getInt(PAGE_TYPE), feedListItems, getActivity());
//add header
header = (ViewGroup) inflater.inflate(R.layout.list_item_header, lv, false);
lv.addHeaderView(header, null, false);
lv.setAdapter(listAdapter);
if (getArguments().getInt(PAGE_TYPE) == 0) {
new getFeedListItems().execute();
} else {
new getFeedListItems().execute();
}
Toast.makeText(context, "This never shows",
Toast.LENGTH_SHORT).show();
return v;
}
When showing Fragments inside another Fragment, use getChildFragmentManager() instead of getSupportFragmentManager()
Initialize your pageAdapter this way:
pageAdapter = new FragmentHomeAdapter(getChildFragmentManager(), pageList);