I'm using ViewPager to show welcome, register, and some other screens. those screens are fragments controlled by FragmentStatePagerAdapter:
private static class TourPagerAdapter extends FragmentStatePagerAdapter {
public TourPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
WellcomeTourFragment ta = null;
switch (position) {
case 0:
ta = WellcomeTourFragment.newInstance(R.layout.welcome_fragment);
break;
case 1:
ta = WellcomeTourFragment.newInstance(R.layout.signup_fragment);
break;
first fragment (WellcomeFragment) shows some views and background image loaded from internet using picasso library:
private ImageView bkgImage;
public static WellcomeTourFragment newInstance(int layoutId){
WellcomeTourFragment pane = new WellcomeTourFragment();
Bundle args = new Bundle();
args.putInt(LAYOUT_ID, layoutId);
pane.setArguments(args);
return pane;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final ViewGroup rootView = (ViewGroup) inflater.inflate(getArguments().getInt(LAYOUT_ID, -1), container, false);
this.bkgImage = (ImageView) rootView.findViewById(R.id.imgView_Background);
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Picasso.with(getActivity())
.load(IMG_uRL)
.into(this.bkgImage);
}
My problem here is that, i am getting
java.lang.IllegalArgumentException: Target must not be null.
I am sure the ImageView does exits in my welcome_fragment layout. but really don't know what makes target to be null.
Are you sure that the correct layout is being inflated? Try debugging and looking at the rootView after it has been inflated. Is it possible you are including the wrong layout id when you call your newInstance method?
Related
i have seen the relative post to my issue but, it's not solve my probleme.
I'm trying to get a swipe view with 3 fragment.
In the main fragment i have this:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View vue = inflater.inflate(R.layout.fragment_conversions, container, false);
ConversionsPagerAdapter cPageAdapter = new ConversionsPagerAdapter(getActivity().getSupportFragmentManager());
ViewPager vp = vue.findViewById(R.id.conversionsPager);
cPageAdapter.getItem(0);
vp.setAdapter(cPageAdapter);
Button convKmhKts = (Button) vue.findViewById(R.id.convKmhKts);
convKmhKts.setText("...");
...
Here is the class of my FragmentStatePagerAdapter:
public class ConversionsPagerAdapter extends FragmentStatePagerAdapter{
public ConversionsPagerAdapter(FragmentManager fm) {
super(fm);
Log.i("ARKA", "FragmentStatePagerAdapter CONSTRUCTOR");
}
#Override
public Fragment getItem(int i) {
return ConversionFragment.newInstance(i);
}
#Override
public int getCount() {
return 1;
}
}
And finnaly the Fragment which display the Tab:
public class ConversionFragment extends Fragment {
public static final String ID_CONVERSION = "id_conversion";
public static ConversionFragment newInstance(int pos) {
ConversionFragment stf = new ConversionFragment();
Bundle args = new Bundle();
args.putInt("pos", pos);
stf.setArguments(args);
return stf;
}
public ConversionFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
// The last two arguments ensure LayoutParams are inflated
// properly.
Bundle args = getArguments();
int idConversion = args.getInt(ID_CONVERSION);
Log.i("idConversion", String.valueOf(idConversion));
int idVue;
switch (idConversion){
case 0: idVue = R.layout.fragment_conversions_vitesse;
break;
case 1: idVue = R.layout.fragment_conversions_vitesse;
default: idVue = R.layout.fragment_conversions_vitesse;
break;
}
View rootView = inflater.inflate(idVue, null);
return rootView;
}
}
The fact is, the getItem() is never called.
I try to change getActivity().getSupportFragmentManager() by getChildFragmentManager(), but it seem it's not the good way...
When i'm trying to acces my button i get this:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
At the line where i'm using the button.
If you use ViewPager inside fragment you have to use chield fragment manager so try replace getActivity().getSupportFragmentManager() with getChildFragmentManager(). If you use one fragment manager for all stuff, it will bring some bugs to you.
For more information
You are doing wrong here
cPageAdapter.getItem(0);
vp.setAdapter(cPageAdapter);
Set adapter to view pager first and then try to call get item method.
vp.setAdapter(cPageAdapter);
cPageAdapter.getItem(0);
Ok,
the probleme was that i try to acces a component which is not inflated:
convKmhKts.setText("...");
I acces to it in the child fragment and now it's ok....
I am creating a app in which i wanna slide images,so for that i will be using view pager.For the image i have created a fragment which will display the images.
Code
public class ImageSwitcher extends BaseFragment {
private ImageView imageView;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.image_switcher_fragment, container, false);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initialize();
}
private void initialize() {
imageView = (ImageView) view.findViewById(R.id.image_switcher);
imageView.setBackgroundResource("");
}
Now at this line
imageView.setBackgroundResource("");
the image will come from the int array which i will pass.
My doubt is
How will i pass int values to fragments
Is there any better way to use image switcher
Pass your Integer value from your fragment using Bundle as below:
Fragment fragment = new Fragment();
Bundle bundle = new Bundle();
bundle.putInt("id", id);
fragment.setArguments(bundle);
Access the value in Fragment onCreateView method:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
int m_id=getArguments().getInt("id");
return inflater.inflate(R.layout.fragment, container, false);
}
class MyFragment extends Fragment {
private static final String ARG_BG_RES="ARG_BG_RES";
public Fragment() {}
static public newInstance(String backgroundRes) {
Bundle args = new Bundle();
args.putExtra(ARG_BG_RES, backgroundRes);
Fragment fragment = new Fragment();
fragment.setArguments(args);
return f;
void whereYouNeedIt() {
String backgroundRes = getArguments().getStringExtra(ARG_BG_RES);
...
}
}
From outside:
MyFragment f = MyFragment.newInstance("black");
Don't omit public Fragment() {} it's required by the OS.
You can use bundle to pass values to the fragment or during initializing pass values via a custom constructor
For background resource if you are not changing images based on some logic in code, apply it via XML background and a drawable :-/
I have seen Link1 for this issue but could understand it right. I have a fragment that loads a list. When i click the list item it opens another activity. But i press back button it loads the list again. I want it to be at the same scroll position where it was before. In above mentioned link it specifies to use flag but i haven't got the point.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dashboard);
android.app.Fragment fragment = new MeFragment();
getFragmentManager().beginTransaction().replace(R.id.layout_FragmentsContainer, fragment).addToBackStack(null).commit();
}
}
public class MeFragment extends Fragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_me, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
meLV = (ListView) getView().findViewById(R.id.lv_Inbox);
loadingListProgress = (ProgressBar) getView().findViewById(R.id.progress_LoadingList);
meList = new ArrayList<Message>();
meAdapter = new MessagesListAdapter(getActivity(), meList);
//addFooter();
meLV.setAdapter(meAdapter);
meLV.setOnItemClickListener(this);
pageCount = 0;
loadmoreProgressDialog = new ProgressDialog(getActivity());
loadmoreProgressDialog.setTitle("Please wait ...");
loadmoreProgressDialog.setMessage("Loading more ...");
loadmoreProgressDialog.setCancelable(true);
loadUserMessages();
meLV.setOnScrollListener(new EndlessScrollListener() {
#Override
public void onLoadMore(int page, int totalItemsCount) {
// TODO Auto-generated method stub
//addFooter();
loadmoreProgressDialog.show();
loadUserMessages();
}
});
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// TODO Auto-generated method stub
Utils.showToast_msg(getActivity(), "MessageItemClicked");
ReferralDetailFragment fragment = new ReferralDetailFragment();
getFragmentManager().beginTransaction().replace(R.id.layout_FragmentsContainer, fragment).addToBackStack(null).commit();
}
}
public class ReferralDetailFragment extends Fragment implements OnClickListener {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_referraldetail,container, false);
linkToAcknowledge = (TextView) view.findViewById(R.id.lbl_Link_to_Acknowledge);
return view;
}
}
I implemented a simple solution for this in my app, basically when you press back to go to the fragment again, onCreateView() is called. Here in onCreateView() you have done all initialization, so we change
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_me, container, false);
/*
*Whatever you want to do
*
*/
return view;
}
to:
View view;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
if(view==null){
view = inflater.inflate(R.layout.fragment_me, container, false);
/*
*Whatever you want to do
*
*/
}
else{
((ViewGroup)view.getParent()).removeView(view);
}
return view;
}
Here, we move View view outside and make it a class variable. So if it is the first time the fragment is called, it is null and the initialization occurs, otherwise it goes to else black. Else block is required because onCreateView() adds whatever it returns as a child of the view's parent, so since view is already there, we remove it and onCreateView automatically adds it again.
According to our exchange in the comments, I completely deletde my answer and re-write a new one.
I copy/paste the code from one of my apps and removing the useless things and changing the names. Hope there is not too many typing mistakes, at that it is the minimum required to have it working.
When I pop back to FirstFragment from SecondFragment, the scroll position of FirstFragment is the same as when I clicked an item to load the SecondFragment.
Note that I don't extend FragmentActivity. I have an activity which loads the fragments.
Extend/modify to match your needs.
MainActivity :
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
}
}
FirstFragment Class :
public class FirstFragment extends Fragment implements OnItemClickListener {
private ListView mListView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.first_fragment_layout, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mListView = (ListView) getView().findViewById(R.id.listview_first_fragment);
mListView.setAdapter(mAdapter); // depends on your adapter
mListView.setOnItemClickListener(this);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mListView.setItemChecked(position, true);
//in case you need, set the bundle here, for example pass the position
Bundle arguments = new Bundle();
arguments.putInt("position", position);
SecondFragment secondFragment = new SecondFragment();
secondFragment.setArguments(arguments);
getFragmentManager().beginTransaction().replace(R.id.fragment_container, secondFragment).addToBackStack(null).commit();
}
}
SecondFragment Class :
public class SecondFragment extends Fragment {
private Integer mPosition;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.second_fragment_layout, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Bundle arguments = getArguments();
if (arguments == null) {
mPosition= 0;
} else {
mPosition= arguments.getInt("Position");
}
}
}
What you are trying to achieve may be done with help of savedInstanceState. i also had this kind of problem which i resolved by using add() method instead of replace() in transition.
If you can change your method or already not using add() than give it a shot.
and if add() method didn't do the trick then check the implementation of savedInstanceState.
correctly save instance state.
How to save states of fragment views.
I am trying to create a ViewPager which contains 5 fragments.
5 fragments "container", so each of them contain 2 fragments.
The 4 first fragments have the same layout and belong to the same class. The fifth is from an other class, and there is no problem with that one.
The problem is that when the activity launches, only 1 fragment seem to be working (the one at position 0 in viewPager). I tried to return new Fragment() at position 0 in my PagerAdapter, but when I do that it's the 2nd fragment that is working. (By working i mean displaying the list on the left, I still haven't taken care of the details fragment on the right)
Here is some code
CustomPagerAdapter.java
public class CustomPagerAdapter extends FragmentPagerAdapter{
public CustomPagerAdapter(FragmentManager fm) {
super(fm);
}
public CustomPagerAdapter(FragmentManager fm, Context context) {
super(fm);
}
#Override
public Fragment getItem(int pos) {
if(pos == 4)
return new OtherContainerFragment();
else
return new ContainerFragment(pos);
}
#Override
public int getCount() {
return 5;
}
ContainerFragment.java
public class ContainerFragment extends Fragment {
private int CONTAINER_TYPE;
public ContainerFragment(){
}
public ContainerFragment(int type){
CONTAINER_TYPE = type;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_container, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
CustomListFragment frag = new CustomListFragment(CONTAINER_TYPE);
ft.replace(R.id.replaceable_list, frag);
ft.commit();
CustomListFragment.java
public class CustomListFragment extends SuperCustomListFragment{
private ArrayList<Model> mModels;
private int TYPE;
public CustomListFragment(){
}
public CustomListFragment(int type){
TYPE = type;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mModels = new ArrayList<Model>();
if(TYPE == AppConstants.FRAGMENT_TYPE_JOURNAL){
mAdapter = AppUtils.getJournalListAdapter(getActivity(), mModels);
new syncPapers().execute();
}else if(TYPE == AppConstants.FRAGMENT_TYPE_MOVIES){
mAdapter = AppUtils.getMoviesListAdapter(getActivity(), mModels);
new syncMovies().execute();
}
if(mAdapter != null)
mListView.setAdapter(mAdapter); //mListView is defined in the superClass
Here are the constants I use :
public class AppConstants {
public static final int FRAGMENT_TYPE_AGENDA = 0; //so Fragment at position 0 should be of type agenda
public static final int FRAGMENT_TYPE_NEWS = 1; // position 1 should be of type news
public static final int FRAGMENT_TYPE_MOVIES = 2; // ...
public static final int FRAGMENT_TYPE_JOURNAL = 3; // ...
}
And the xml for the container :
<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:id="#+id/replaceable_list"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</LinearLayout>
<LinearLayout
android:id="#+id/replaceable_details"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/background" >
</LinearLayout>
</LinearLayout>
SO this code is not working, it seems that the list on the left in the fragment container is replaced in each fragment, and only the fragment at position 0 displays it. (Currently it displays the list with the adapter of type "JOURNAL", but it should display list of type "AGENDA".
--------------------
*BUT !...*
--------------------
If I create different fragment_container layout-files, and write IF conditions in the onCreateView and onViewCreated in the ContainerFragment.java, everything works fine.
So :
ContainerFragment.java
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if(CONTAINER_TYPE == AppConstants.FRAGMENT_TYPE_JOURNAL)
return inflater.inflate(R.layout.fragment_container_journal, container, false);
else if(CONTAINER_TYPE == AppConstants.FRAGMENT_TYPE_MOVIES)
return inflater.inflater(R.layout.fragment_container_movies, container, false);
else
return super.onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
CustomListFragment frag = new CustomListFragment(CONTAINER_TYPE);
if(CONTAINER_TYPE == AppConstants.FRAGMENT_TYPE_JOURNAL)
ft.replace(R.id.replaceable_journal_list, frag);
else if(CONTAINER_TYPE == AppConstants.FRAGMENT_TYPE_MOVIES)
ft.replace(R.id.replaceable_movies_list, frag);
else
return;
ft.commit();
I guess that's because in each fragment, I replace the LinearLayout of the same ID ? (replaceable_list)
I thought it was possible to share the same layout file for every fragments and didn't want to create 4 layout-files that would be the same. But it looks like I must do so ?
Or am I missing something here ?
Thank you for your time,
Though a very late response but I was facing same kind of issue and I fixed the issue by using
getChildFragmentManager().beginTransaction()
instead of
getActivity().getSupportFragmentManager().beginTransaction()
As in this case we are trying to make transaction from within a fragment (one out of the list of fragments which are attached to the ViewPager, thus the Activity holding the ViewPager) so we have to use getChildFragmentManager() here for desired results.
I was able to solve this by setting the id of the layout that is inflated within each fragment to its position.
What you would have to do is simply change the method onCreateView in you ContainerFragment class to:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_container, container, false);
v.setId(CONTAINER_TYPE)
return v;
This works because of the way the FragmentPagerAdapter implementation handles fragment tags.
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.