I have a activity with an container inside of it in which I display a list generated by a listFragment. Now I want handle clicks on list items by "forwarding" the onItemClick method via a pulic interface to the mainActivity. I did setOnItemClickLIstener and I also tried many solutions I found here and elsewhere e.g. setting
android:focusable="false"
android:focusableInTouchMode="false"
in the xml file for my custom list items.
The fragment code looks like this (I will not post the whole code to keep it simple, if needed I will provide further parts of the code)
public class DishListFragment extends ListFragment implements ListView.OnItemClickListener {
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private static final String ARG_PARAM3 = "param3";
private static final String ARG_PARAM4 = "param4";
private static final String ARG_PARAM5 = "param5";
//List of Dishes to contain the dishes we get from the server
//Todo: fill with dynamic content
private ArrayList<DishListItem> dishes;
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
private ListView mListView;
private ListAdapter mAdapter;
public static DishListFragment newInstance(Date day, boolean soup, boolean meat,
boolean veggies, boolean sideDishes) {
DishListFragment fragment = new DishListFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, String.valueOf(day));
args.putString(ARG_PARAM2, String.valueOf(soup));
args.putString(ARG_PARAM3, String.valueOf(meat));
args.putString(ARG_PARAM4, String.valueOf(veggies));
args.putString(ARG_PARAM5, String.valueOf(sideDishes));
fragment.setArguments(args);
return fragment;
}
public DishListFragment() { }
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//dummy list of dishes addad for developing purposes
// Todo: implement dynamic server generated list content
// create this array to test the comment function
String[] commentDummy = new String[]{"gut", "lecker", "schlecht"};
dishes = new ArrayList<DishListItem>();
dishes.add(new DishListItem("Rigatonelli", commentDummy, 2.0f ,4));
dishes.add(new DishListItem("Spinatcremesuppe"));
dishes.add(new DishListItem("Hackbällchen"));
dishes.add(new DishListItem("Gemüsepfanne"));
dishes.add(new DishListItem("Reis"));
dishes.add(new DishListItem("Rumpsteak"));
dishes.add(new DishListItem("Rumpsteak"));
dishes.add(new DishListItem("Rumpsteak"));
dishes.add(new DishListItem("Rumpsteak"));
dishes.add(new DishListItem("Rumpsteak"));
dishes.add(new DishListItem("Rumpsteak"));
//end here
// set an adapter to the list and let it display the list
// Todo: implement custom list view elements for graphical UI
// Todo: implement custom adapter to handle user preferences (meat/ veggies/ soups/ sidedishes)
mAdapter = new DishListAdapter(getActivity(),dishes);
}
//create on click adapter to handle clicks on list items
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id){
DishListItem dishItem = this.dishes.get(position);
Toast.makeText(getActivity(), dishItem.getDishName() +" clicked!", Toast.LENGTH_SHORT).show();
mListener.onDishClicked(dishes, position);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_dishlist, container, false);
View header = inflater.inflate(R.layout.list_header_day_date, mListView ,false);
mListView = (ListView) view.findViewById(android.R.id.list);
mListView.addHeaderView(header);
mListView.setAdapter(mAdapter);
// Set OnItemClickListener so we can be notified on item clicks
mListView.setOnItemClickListener(this);
return view;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public void setEmptyText(CharSequence emptyText) {
View emptyView = mListView.getEmptyView();
if (emptyText instanceof TextView) {
((TextView) emptyView).setText(emptyText);
}
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
public void onDishClicked(ArrayList<DishListItem> dishes, int position);
}
}
The main activity looks like this
public class CulinariumSpeiseplan extends ActionBarActivity
implements DishListFragment.OnFragmentInteractionListener
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_culinarium_speiseplan);
//add list fragment to the activity layout (put it into the container)
if(savedInstanceState == null){
getFragmentManager().beginTransaction()
.add(R.id.listDishesContainer, new DishListFragment())
.commit();
}
}
{
#Override
public void onDishClicked(ArrayList<DishListItem> dishes, int position) {
Toast.makeText(this, dishes.get(position).getDishName() +" clicked!", Toast.LENGTH_SHORT).show();
SingleDishEnhancedView singleDishEnhancedView = SingleDishEnhancedView.newInstance(dishes, position);
singleDishEnhancedView.show(getFragmentManager(), "DishDisplay");
}
}
the toasts are just for test purposes but they don't get displayed either. I hope I am not being completely stupid but I just can't seem to find an answer to that problem.
Thank you for your time.
EDIT: I should also mention, that I do neither get an compilation error, nor does the app crash at any point. The list is scrollable and does behave as you would expect it, you can even see the little click animation as you click on one of the items.
EDIT2: I updated the code because the comments were pointing out some significant bits were missing. I hope the updated code makes it more clear.
The solution was fairly simple the onItemClick method has to use ListView instead of AdapterView, although I'm not really sure why this didn't cause a crash or at least some kind of warning. Either ways, the problem is solved. Thanks for the comments, they led me the right way.
Related
My question is similar to this one.
Best approach to communicate between Fragment/Activity and RecyclerView.Adapter?
I know how to implement an onClickListener, an Interface and an OnItemSelected method in the corresponding activity when the user clicks on a button in a Fragment. I have a fragment with an array list. By clicking on each item in the array list in the fragment, an ExoPlayer will open in a new activity or a fragment. As I understand it, onItemClickListener doesn't work with Recyclerview. How do I set the onClick method to the items in the list? Also, do I set onClick outside of RecyclerView? This is my RecyclerView adapter class. Should the interface take additional parameters? Thank you in advance.
public class StepsAdapter extends RecyclerView.Adapter {
private static final String TAG = StepsAdapter.class.getSimpleName();
private ArrayList<Steps> stepsList = new ArrayList<Steps>();
private StepsAdapter.StepsAdapterOnClickHandler mClickHandler;
/**
* The interface that receives onClick messages.
*/
public interface StepsAdapterOnClickHandler {
void onClick(Steps stepClick);
}
/**
* Creates a StepsAdapter.
*
* #param clickHandler The on-click handler for this adapter. This single handler is called
* when an item is clicked.
*/
public StepsAdapter(StepsAdapterOnClickHandler clickHandler,ArrayList<Steps> stepsList) {
mClickHandler = clickHandler;
this.stepsList = stepsList;
}
/**
* Cache of the children views for a steps list item.
*/
public class StepsAdapterViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
#BindView(R.id.step_short_desc)
public TextView stepShortDescription;
#BindView(R.id.step_description)
public TextView stepDescription;
public StepsAdapterViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
view.setOnClickListener(this);
}
/**
* This gets called by the child views during a click.
*
* #param v The View that was clicked
*/
#Override
public void onClick(View v) {
int adapterPosition = getAdapterPosition();
Steps stepClick = stepsList.get(adapterPosition);
mClickHandler.onClick(stepClick);
}
}
#Override
public StepsAdapter.StepsAdapterViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
Context context = viewGroup.getContext();
int layoutIdForListItem = R.layout.steps_list_item;
LayoutInflater inflater = LayoutInflater.from(context);
boolean shouldAttachToParentImmediately = false;
View view = inflater.inflate(layoutIdForListItem, viewGroup, shouldAttachToParentImmediately);
return new StepsAdapter.StepsAdapterViewHolder(view);
}
#Override
public void onBindViewHolder(StepsAdapter.StepsAdapterViewHolder holder, int position) {
//Binding data
final Steps stepsView = stepsList.get(position);
holder.stepShortDescription.setText(stepsView.getStepShortDescription());
holder.stepDescription.setText(stepsView.getStepDescription());
}
#Override
public int getItemCount() {
return stepsList.size();
}
public void setStepsList(ArrayList<Steps> mStepsList) {
this.stepsList = mStepsList;
notifyDataSetChanged();
}
}
The corresponding fragment. Is the click method implemented correctly?
public class StepsListFragment extends Fragment implements StepsAdapter.StepsAdapterOnClickListener {
// Tag for logging
private final String TAG = StepsListFragment.class.getSimpleName();
#BindView(R.id.recyclerview_steps)
RecyclerView mRecyclerView;
ArrayList<Steps> stepsArrayList;
Recipes recipes;
// Final Strings to store state information about the list of steps and list index
public static final String STEPS_LIST_INDEX = "list_index";
// Define a new interface OnStepsClickListener that triggers a callback in the host activity
OnStepClickListener mCallback;
// OnStepsClickListener interface, calls a method in the host activity named onStepSelected
public interface OnStepClickListener {
void onClick(Steps stepClick);
}
// Override onAttach to make sure that the container activity has implemented the callback
#Override
public void onAttach(Context context) {
super.onAttach(context);
// // This makes sure that the host activity has implemented the callback interface
// // If not, it throws an exception
try {
mCallback = (OnStepClickListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement OnStepSelectedListener");
}
}
/**
* Mandatory empty constructor for the fragment manager to instantiate the fragment
*/
public StepsListFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// //Inflate the Steps fragment layout
View rootView = inflater.inflate(R.layout.fragment_steps, container, false);
// // Bind the views
ButterKnife.bind(this, rootView);
Bundle bundle = this.getArguments();
if (bundle != null) {
recipes = getArguments().getParcelable("Recipes");
stepsArrayList = new ArrayList<>();
stepsArrayList = recipes.getRecipeSteps();
}
if (savedInstanceState != null) {
//Restore the fragment's state here
stepsArrayList = savedInstanceState.getParcelableArrayList(STEPS_LIST_INDEX);
}
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getContext());
mRecyclerView.setLayoutManager(mLayoutManager);
Log.i("listSteps", stepsArrayList.size() + "");
StepsAdapter stepsAdapter = new StepsAdapter(this, stepsArrayList);
mRecyclerView.setAdapter(stepsAdapter);
// Return the root view
return rootView;
}
public void onClick(Steps stepClick){
mCallback.onClick(stepClick);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveIn`enter code here`stanceState(outState);
//Save the fragment's state here
outState.putParcelableArrayList(STEPS_LIST_INDEX, stepsArrayList);
super.onSaveInstanceState(outState);
} }
The best way to implement click function on each item of recyclerview is initialise onClickListener when the view is populated inside in the recyclerview viewholder. Then in the onClick method, use a custom interface/listener to catch the click activity in your parent fragment/activity.
eg: create a custom interface like this;
public interface RecyclerviewOnClickListener{
void recyclerviewClick(int position);
}
Now implement this interface in your parent activity/fragment containing the recyclerview. Suppose your fragment name is ChatFragment. Then,
public class ChatFragment extends Fragment implements RecyclerviewOnClickListener{
.
.
}
This will implement the function onClick(int position) in your fragment. In your adapter constructor, you should create a field for the RecyclerviewOnClickListener. Suppose your adapter name is ChatAdapter, then
Adapter Constructor.
public ChatAdapter(RecyclerviewClickListener listener, .....<other params>){
this.listener = listener;
}
In your fragment, you can initialise your adapter like the following
ChatAdapter adapter = new ChatAdapter(this, <any additional params>);
You should pass the same instance of 'listener' to your viewholder also, and initialise the listener there also
Now in your recyclerview ViewHolder, you can set view.setOnClickListener(new OnClickListener{
this.listener.recyclerviewClick(getAdapterPosition())
});
The getAdapterPosition() function returns the position of the click in the recyclerview, which will get a callback in the recyclerviewClick() function in your fragment.
About the number of parameter you are passing, you can use as much as you want, but for a click function in recyclerview, the ideal way is to use only one param which the position. Now you can modify the contents in the list that you are passing from your fragment to adapter and call notifyDataSetChanged() which will update the recyclerview. Hope it's clear.
Try this inside OnBindviewHolder
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//code here
}
I'm new in android and want an app with viewpager. I am unable to design the viewpager in the layout. The layout fetch the data dynamatically. I want to create a matreial UI viewpager which swipes the page left or right like a paper.I have made a view which shows the data but is unable to swipe like a viewpager left or right...
The code is as below:
public class DetailNewsActivity extends AppCompatActivity {
private PullToZoomScrollViewEx scrollView;
private ArrayList<NewsItemModel> newsArr;
private TextView tvNewsTitle;
private TextView tvNewsPublishDate;
private TextView tvNewsFull;
private int newsPosition = 0;
private ImageView ivYoutubeEnable;
private SharedPreferences sharedPref;
int textSize = 16;
boolean isHighQuality = false;
private Typeface typeface;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail_news);
init();
AdView mAdView = (AdView) findViewById(R.id.adView);
AdRequest adRequest = new AdRequest.Builder()
.addTestDevice("5745FD6726ACCBEE8324DB158D021FA5")
.build();
mAdView.loadAd(adRequest);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_detail_news, container, false);
return view;
}
private void init() {
typeface = Typeface.createFromAsset(getAssets(), "AnmolUni.ttf");
// newsArr = (ArrayList<NewsItemModel>) getIntent().getSerializableExtra("newsArray");
newsArr = AppController.getAppController().getMainNewsArr();
AppController.getAppController().setMainNewsArr(null);
newsPosition = getIntent().getIntExtra("newsPosition", 0);
findViewById(R.id.iv_back).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
findViewById(R.id.iv_share).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
generateBranchURL(newsPosition);
}
});
sharedPref = getSharedPreferences(Constants.SHARED_PREF_NAME, Context.MODE_PRIVATE);
textSize = sharedPref.getInt("text_size", 16);
isHighQuality = sharedPref.getBoolean("isHighQuality",false);
loadViewForCode();
scrollView = (PullToZoomScrollViewEx) findViewById(R.id.scroll_view);
setNewsFromArray(newsPosition);
// ((ImageView) scrollView.getZoomView().findViewById(R.id.iv_zoom)).setImageResource(android.R.drawable.arrow_down_float);
(scrollView.getZoomView().findViewById(R.id.iv_zoom)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(DetailNewsActivity.this, ImageVideoActivity.class);
intent.putExtra("viewType", "image");
if(isHighQuality)
intent.putExtra("imageArr", newsArr.get(newsPosition).getImage());
else
intent.putExtra("imageArr", newsArr.get(newsPosition).getMedium());
startActivity(intent);
}
});
DisplayMetrics localDisplayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(localDisplayMetrics);
int mScreenHeight = localDisplayMetrics.heightPixels;
int mScreenWidth = localDisplayMetrics.widthPixels;
LinearLayout.LayoutParams localObject = new LinearLayout.LayoutParams(mScreenWidth, (int) (9.0F * (mScreenWidth / 16.0F)));
scrollView.setHeaderLayoutParams(localObject);
scrollView.setParallax(true);
// scrollView.getPullRootView().findViewById(R.id.container_layout).setOnTouchListener(new OnSwipeTouchListener(DetailNewsActivity.this) {
scrollView.getPullRootView().setOnTouchListener(new OnSwipeTouchListener(DetailNewsActivity.this) {
#Override
public void onSwipeLeft() {
if (newsPosition < newsArr.size() - 1) {
newsPosition++;
setNewsFromArray(newsPosition);
} else {
CommonUtils.showToast(DetailNewsActivity.this, "No more news");
}
}
#Override
public void onSwipeRight() {
if (newsPosition > 0) {
newsPosition--;
setNewsFromArray(newsPosition);
} else {
CommonUtils.showToast(DetailNewsActivity.this, "This is the first news");
}
}
});
scrollView.setOnPullZoomListener(new PullToZoomBase.OnPullZoomListener() {
#Override
public void onPullZooming(int newScrollValue) {
Log.d("MainActivity", "onPullZooming: " + newScrollValue);
// Intent intent = new Intent(DetailNewsActivity.this, ImageVideoActivity.class);
// intent.putExtra("viewType", "image");
// intent.putExtra("imageArr", newsArr.get(newsPosition).getImage());
// startActivity(intent);
}
#Override
public void onPullZoomEnd() {
}
});
}
void setNewsFromArray(int position) {
if (position >= newsArr.size()) {
finish();
return;
}
if (!newsArr.get(position).getMedium().get(0).isEmpty()) {
if(isHighQuality)
Picasso.with(DetailNewsActivity.this).load(newsArr.get(position).getImage().get(0)).placeholder(R.drawable.logo).error(R.drawable.logo).
into((ImageView) scrollView.getZoomView().findViewById(R.id.iv_zoom));
else
Picasso.with(DetailNewsActivity.this).load(newsArr.get(position).getMedium().get(0)).placeholder(R.drawable.logo).error(R.drawable.logo).
into((ImageView) scrollView.getZoomView().findViewById(R.id.iv_zoom));
} else {
((ImageView) scrollView.getZoomView().findViewById(R.id.iv_zoom)).setImageResource(R.drawable.logo);
}
tvNewsTitle.setText(newsArr.get(position).getTitle());
tvNewsPublishDate.setText(newsArr.get(position).getPublish_dt());
//String style = "<html><body style='text-align:justify'>";
//Log.i("RAJEEV",style + newsArr.get(position).getFullnews());
tvNewsFull.setText(Html.fromHtml( newsArr.get(position).getFullnews()));
if (newsArr.get(position).getYoutube_video().isEmpty()) {
ivYoutubeEnable.setVisibility(View.GONE);
} else {
ivYoutubeEnable.setVisibility(View.VISIBLE);
}
ivYoutubeEnable.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(DetailNewsActivity.this, ImageVideoActivity.class);
intent.putExtra("viewType", "youtube");
intent.putExtra("youtube_code", newsArr.get(newsPosition).getYoutube_video());
startActivity(intent);
}
});
}
private void loadViewForCode() {
PullToZoomScrollViewEx scrollView = (PullToZoomScrollViewEx) findViewById(R.id.scroll_view);
View headView = LayoutInflater.from(this).inflate(R.layout.ptz_head_view, null, false);
View zoomView = LayoutInflater.from(this).inflate(R.layout.ptz_zoom_view, null, false);
View contentView = LayoutInflater.from(this).inflate(R.layout.ptz_content_view, null, false);
scrollView.setHeaderView(headView);
scrollView.setZoomView(zoomView);
scrollView.setScrollContentView(contentView);
tvNewsTitle = (TextView) scrollView.getPullRootView().findViewById(R.id.tv_news_title);
tvNewsPublishDate = (TextView) scrollView.getPullRootView().findViewById(R.id.tv_news_publish_date);
tvNewsFull = (TextView) scrollView.getPullRootView().findViewById(R.id.tv_news_full);
tvNewsFull.setTextSize(textSize);
if (!AppController.isPunjabiSupported()) {
tvNewsTitle.setTypeface(typeface);
tvNewsFull.setTypeface(typeface);
}
ivYoutubeEnable = (ImageView) scrollView.getHeaderView().findViewById(R.id.iv_youtube_header);
}
void generateBranchURL(final int newsPosition) {
// String imageUrl = "";
// if (newsArr.get(newsPosition).getMedium().size() <= 1)
// imageUrl = newsArr.get(newsPosition).getMedium().get(0);
BranchUniversalObject branchUniversalObject = new BranchUniversalObject()
.setCanonicalIdentifier("NewsDetails")
///.setCanonicalUrl("https://branch.io/deepviews")
//.setTitle("" + newsArr.get(newsPosition).getTitle())
//.setContentDescription("" + newsArr.get(newsPosition).getIntro())
//.setContentImageUrl("" + imageUrl)
// You use this to specify whether this content can be discovered publicly - default is public
.setContentIndexingMode(BranchUniversalObject.CONTENT_INDEX_MODE.PUBLIC);
// Here is where you can add custom keys/values to the deep link data
//.addContentMetadata("property1", "blue")
//.addContentMetadata("property2", "red");
LinkProperties linkProperties = new LinkProperties()
.addControlParameter("$desktop_url", "http://www.newsnumber.com/news/share/" + newsArr.get(newsPosition).getFn_id())
.addControlParameter("$ios_url", "itms-apps://itunes.apple.com/us/app/newsnumber/id1022442357?mt=8")
.addControlParameter("NewsId", "" + newsArr.get(newsPosition).getFn_id())
.addControlParameter("CatId", "" + newsArr.get(newsPosition).getCat_id())
.addControlParameter("$og_title", newsArr.get(newsPosition).getTitle())
.addControlParameter("$og_description", newsArr.get(newsPosition).getIntro())
.addControlParameter("$og_image_url", newsArr.get(newsPosition).getImage().get(0))
.addControlParameter("$twitter_title", newsArr.get(newsPosition).getTitle())
.addControlParameter("$twitter_description", newsArr.get(newsPosition).getIntro())
.addControlParameter("$twitter_image_url", newsArr.get(newsPosition).getImage().get(0))
;
branchUniversalObject.generateShortUrl(this, linkProperties, new Branch.BranchLinkCreateListener() {
#Override
public void onLinkCreate(String url, BranchError error) {
if (error == null) {
Log.i("MyApp", "got my Branch link to share: " + url);
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, "News Number\n");
sharingIntent.putExtra(Intent.EXTRA_TEXT, url);
startActivity(Intent.createChooser(sharingIntent, "Share via"));
}
}
});
}
}
can anyone help??
thanks in advance.
It seems like you might be trying to make a new Activity for each "page" of a ViewPager. The Android support library already has their own ViewPager that uses fragments.
You basically need three things to use a ViewPager:
The ViewPager itself
An adapter for the ViewPager
The fragment that will be used in the ViewPager (esentially the "template" that will be used for each "page" in the ViewPager)
First, we'll create the fragment. This is just a simple example that uses only one TextView, but it will work for any amount of views and data. You'll notice that static method "newInstance()" that creates and returns an instance of this fragment. Google recommends using this method to instantiate new Fragments for a ViewPager as it makes passing data to the fragment much easier. All fragments have a "setArguments()" method that lets you pass in a Bundle when you instantiate it with whatever data you want. The method "getArguments()" can be used to access that bundle and get the values out of it in onCreate() or onCreateView(). This is how you pass in an object or objects to bind its data to the views. In this example, were just passing in a String and setting that String to a TextView. You'll see how it's used when we create the adapter for the ViewPager.
//You should be using android.support.v4.app.Fragment here
public class ExampleFragment extends Fragment {
private static final String DAY_NAME_KEY = "day_name";
private TextView dayName;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater,
#Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.fragment_example, container, false);
dayName = (TextView) fragmentView.findViewById(R.id.day_name);
return fragmentView;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//Set the name of the day to the dayName TextView
String day = getArguments().getString(DAY_NAME_KEY);
dayName.setText(day);
}
public static ExampleFragment newInstance(String day) {
Bundle bundle = new Bundle();
bundle.putString(DAY_NAME_KEY, day);
ExampleFragment fragment = new ExampleFragment();
fragment.setArguments(bundle);
return fragment;
}
}
Now, we need to make an adapter that will create the views when the ViewPager is swiped. You need to extend either FragmentPagerAdapter or FragmentStatePagerAdapter. FragmentPagerAdapter is used for a small number of static fragments and it will use more memory. So you only want to use this if you have 4 or 5 pages and aren't adding any more dynamically.
For your case, it sounds like you want to swipe through a variable number of pages that are dynamically added, so you want to use FragmentStatePagerAdapter. It's optimized for memory efficiency and it will handle the saving and restoring of the fragments' state for you.
The adapter is simple.
First, you need to make your constructor match the super class's constructor. What that means is that your constructor must have a FragmentManager parameter. All you do with that is pass it to the super class. (You'll see below.)
Secondly, you have to implement just 2 methods from the FragmentStatePagerAdapter class:
public Fragment getItem(int position)
and
public int getCount()
getItem will be automatically called by the ViewPager when it is swiped. You just have to tell it what type of fragment to return. We'll be using the newInstance() method from the ExampleFragment class here.
getCount is the number of views that your ViewPager will be using. For example, I will have an ArrayList that will contain 7 strings (one for each day of the week). I want each one of those strings to be displayed on a different page of my ViewPager. So I'm just going to return the size of the ArrayList for this method.
Here's the class:
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
//A reference to the array of data that will be used to populate
//each fragment. In this case it's an array of Strings, but it
//could be any type of object. The Strings within this array are what
//we'll be passing to the newInstance() method of each fragment.
private ArrayList<String> days;
//Constructor must take a FragmentManager to match the superclass.
public ViewPagerAdapter(FragmentManager fm, ArrayList<String> days) {
//All you have to do with the fragment manager is pass it to super
super(fm);
//The array will be passed in when we create the Adapter in our Activity
this.days = days;
}
#Override
public Fragment getItem(int position) {
/*
Automatically called when another page is needed.
The adapter will keep track of the position of the current page
so the first time this is called, it will be 0, then when a
swipe occurs, it will be one. If it is swiped backward, it will go back to 0.
So when the position is 0, a new Fragment will be created and the
String at days.get(0) ("Monday") will be passed to it.
*/
return ExampleFragment.newInstance(days.get(position));
}
#Override
public int getCount() {
return days.size();
}
}
Now we just have to set the adapter for the ViewPager in our Activity and it will automatically handle swipes for us.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<String> daysOfWeek = new ArrayList<>();
daysOfWeek.add("Monday");
daysOfWeek.add("Tuesday");
daysOfWeek.add("Wednesday");
daysOfWeek.add("Thursday");
daysOfWeek.add("Friday");
daysOfWeek.add("Saturday");
daysOfWeek.add("Sunday");
ViewPager pager = findViewById(R.id.view_pager);
//Pass the activity's fragmentmanager by calling getSupportFragmentManager().
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager(), daysOfWeek);
pager.setAdapter(adapter);
}
}
This is what we get (I've added some padding and color to make it clear):
As for changing the way the pages "turn" (for example, like a newspaper), you need to look into PageTransformer
Can it be possible to slide the viewpager half of the screen?
My ultimate goal is to display two list view at a time, after first page slide, left list would be the previous list.
So Like as below..
list1,list2
list2,list3
list3,list4
Any solutions?
Thanks
Okay, I am going to take a stab at this. I accomplished what (I think) you are trying to do. My application has 3 ListViews, and each list contains different content fetched from an online source and populates a ViewPager using custom adapters and ListViews. The custom adapter is then assigned to a fragment on a PagerAdapter. I copied a lot of my code from a Google resource, and will try to outline what I did.
First, I added a ViewPager to my layout for my MainActivity
activity_main.xml:
<android.support.v4.view.ViewPager
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- add a PagerTitleStrip -->
<android.support.v4.view.PagerTitleStrip
android:id="#+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"/>
</android.support.v4.view.ViewPager>
Then, I created a separate ListView layout I could use for my custom adapters:
listview.xml
<ListView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#E6E6E6"
android:background="#E6E6E6"
tools:context=".MainActivity" />
After I had these set, I dug into my activity. The rest takes place within MainActivity.java:
First, lay out some variables:
public class MainActivity extends FragmentActivity implements OnNavigationListener {
// your pager adapter
SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;
// your custom adapters (look this up on your own if you do not understand)
ArrayList<ListEntry> listOneArrayList = null;
ArrayList<ListEntry> listTwoArrayList = null;
CustomAdapterListOne customAdapterListOne = null;
CustomAdapterListTwo customAdapterListTwo = null;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// more on that in the next block...
}
}
Now, let's get into onCreate() and start creating!
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// set up your pager adapter
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.viewpager);
mViewPager.setAdapter(mSectionsPagerAdapter);
// if you want to set a default view:
mViewPager.setCurrentItem(0);
// now, run some AsyncTasks to load up our lists
// I use AsyncTasks because I fetch my data from a server
new generateListOne().execute();
new generateListTwo().execute();
}
/*
* Get the entries and create a list adapter
*/
private class generateListOne extends AsyncTask<String, Void, Object> {
#Override
protected Object doInBackground(String... args) {
listOneArrayList = new ArrayList<ListEntry>();
// this is where I would do all of my networking stuff
// and populate my arraylist
return null;
}
#Override
protected void onPostExecute(Object result) {
// you have to create a new xml layout for 'listview_row' to use here v
customAdapterListOne = new CustomAdapterListOne(self, R.layout.listview_row, listOneArrayList);
/** Very important! This is where you specify where the list goes: **/
// * Note: Fragment pages start at 0!
ListSectionFragment fragment = (ListSectionFragment) getSupportFragmentManager().findFragmentByTag(
"android:switcher:"+R.id.viewpager+":0"); // <- this is where you specify where the list goes
if (fragment != null) { // <- Could be null if not instantiated yet
if(fragment.getView() != null) {
customAdapterListOne.notifyDataSetChanged();
fragment.updateListOneDisplay(customAdapterListOne);
}
}
}
}
I'm not going to write out generateListTwo(), but hopefully you understand the concept from generateListOne(). Pay very close attention to what is happening in onPostExecute(). Now, we have to write out the FragmentPagerAdapter and our ListSection Fragment. Also, we have to include our custom list Adapter. All of that stuff follows:
/*
* Your Custom Adapter Class
*/
private class CustomAdapterListOne extends ArrayAdapter<ListEntry> {
/*
* Read up on the rest of this for custom adapter if you
* are unfamilar. There are plenty of resources..
*
* I am not going to type it all out.
*/
}
/*
* SectionsPagerAdapter class for FragmentPagerAdapter title
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment fragment = new ListSectionFragment();
Bundle args = new Bundle();
args.putInt(ListSectionFragment.ARG_SECTION_NUMBER, i + 1);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
// make sure this is correct
int yourNumberOfLists = 5;
return yourNumberOfLists;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0: return "First List";
case 1: return "Second List";
//case 2: etc..
}
return null;
}
public boolean onInterceptTouchEvent(MotionEvent event) {
return false;
}
}
/*
* ListSectionFragment class for ListFragment(s)
*/
public static class ListSectionFragment extends ListFragment {
public static final String ARG_SECTION_NUMBER = "section_number";
public static int CURRENT_SECTION = 0;
static ListSectionFragment newInstance(int num) {
ListSectionFragment fragment = new ListSectionFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
public void updateListOneDisplay(ArrayAdapter<ListEntry> listOneAdapter) {
setListAdapter(listOneAdapter);
}
public void updateListTwoDisplay(ArrayAdapter<ListEntry> listTwoAdapter) {
setListAdapter(listTwoAdapter);
}
// etc..
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Bundle args = getArguments();
CURRENT_SECTION = args.getInt(ARG_SECTION_NUMBER);
// note, we are using your listview here v
View view = inflater.inflate(R.layout.listview, container, false);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// and just for kicks:
Log.i(TAG, "Item clicked: " + position);
}
}
Don't forget your last } to close out the MainActivity.java class. Hopefully this helps someone, I know it took me forever to figure out. The effect that this code provides is similar to that of the Android Place application.
Edit: I forgot to mention when the list loads. When a list gains focus, it also loads the previous and next list. This makes it possible to transition to it and have it already be there ready to go. For example:
You go to list 2 and list 1 and list 3 are loaded. You then go to list 3 (and it transitions smoothly because it is loaded already), and list 4 and list 2 are loaded. This ensures that when you transition to a new list, it is already loaded or in the process of being generated.
i'm pretty new with Fragments and ViewPager. I'm using ActionBarSherlock and ViewPageIndicator from Jack Wharton.
I've started with a standard Android MasterDetailFlow Activity and did try to modify it to use a ViewPager in the detail part.
I'm using the standard DummyContent to provide some static data but i've replaced the DummyItem with my "Survey"-Library i have to use in this app. DummyContent provides a public static ArrayList which i use to fill the list in the list activity. After i choose a survey in this list, the corresponding questions should be shown in the view pager.
Here is the code of my QuestionActivity.java which hosts the question fragments.
public class QuestionActivity extends SherlockFragmentActivity {
private QuestionsFragmentPagerAdapter mAdapter;
private PageIndicator mIndicator;
private ViewPager mPager;
private String surveyName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_viewpager);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
surveyName = getIntent().getExtras().getString(ItemDetailFragment.ARG_SURVEY_NAME);
mAdapter = new QuestionsFragmentPagerAdapter(getSupportFragmentManager(), DummyContent.mgr.getSurvey(surveyName).getQuestions());
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mIndicator = (PageIndicator) findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
}
}
QuestionsFragmentPagerAdapter.java
public class QuestionsFragmentPagerAdapter extends FragmentPagerAdapter {
ArrayList<Question> questions;
public QuestionsFragmentPagerAdapter(FragmentManager fm, List<Question> questions) {
super(fm);
this.questions = (ArrayList<Question>) questions;
}
#Override
public Fragment getItem(int position) {
Fragment f = QuestionFragment.newInstance(questions.get(position));
return f;
}
#Override
public int getCount() {
return questions.size();
}
}
QuestionFragment.java
public class QuestionFragment extends SherlockListFragment {
protected enum QuestionType {
FT, SC, MC;
}
public final static String ARG_QUESTION_QUESTION = "question_question";
public final static String ARG_QUESTION_TYPE = "question_type";
public final static String ARG_QUESTION_ANSWERINGOPTIONS = "question_answeringptions";
private TextView lblQuestion;
private EditText txtAnswer;
private ListView listAnswers;
private ArrayAdapter<String> listAdapter;
private Question question;
private int listLayout;
/**
*
* #param question
* #return
*/
public static QuestionFragment newInstance(Question question) {
QuestionFragment fragment = new QuestionFragment();
// Creates a Bundle with all informations available in the question obj.
Bundle args = createBundleFromQuestion(question);
fragment.setArguments(args);
return fragment;
}
/**
*
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Creates the question object from the given arguments.
// I know this isn't a good solution, i will implement the
// Parcelable asap i have solved the current issues.
//
createQuestionFromBundle(getArguments());
// String questionXml = getArguments() != null ? getArguments().getString(ARG_QUESTION_XML) : null;
// this.question = (Question) MyXmlSerializer.deserialize(questionXml, Question.class);
}
/**
* Creates a the Question object form the Bundle.
* #param extras
*/
private void createQuestionFromBundle(Bundle extras) {
// Think we don't need it here. The field question gets instantiated.
}
/**
*
*/
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.answer_question, null);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initWidgets();
setCorrectLayout();
initContent();
}
private void initContent() {
String questionStr = question.getQuestion();
lblQuestion.setText(questionStr);
if(question instanceof FTQuestion) {
} else if (question instanceof ClosedQuestion) {
listAdapter = new ArrayAdapter<String>(getActivity(), listLayout);
List<Answer> answeringOptions = question.getAnswers();
for(Answer answer : answeringOptions) {
listAdapter.add(answer.getAnswer());
}
listAnswers.setAdapter(listAdapter);
}
}
/**
*
*/
private void initWidgets() {
listAnswers = getListView();
lblQuestion = (TextView) getActivity().findViewById(R.id.lblQuestion);
txtAnswer = (EditText) getActivity().findViewById(R.id.txtAnswer);
}
/**
* Sets the FT/SC/MC layout
*/
private void setCorrectLayout() {
if(question instanceof FTQuestion) {
setFtLayout();
} else if (question instanceof SCQuestion) {
setScLayout();
} else if (question instanceof MCQuestion) {
setMcLayout();
}
}
/**
*
*/
private void setFtLayout() {
if(listAnswers.getVisibility()!=ListView.INVISIBLE && listAnswers.getVisibility()!=ListView.GONE) {
listAnswers.setVisibility(ListView.GONE);
}
}
/**
*
*/
private void setScLayout() {
listLayout = R.layout.answer_question_single_choice_list_row;
listAnswers.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
if(txtAnswer.getVisibility() == TextView.VISIBLE) txtAnswer.setVisibility(TextView.GONE);
}
/**
*
*/
private void setMcLayout() {
listLayout = R.layout.answer_question_multiple_choice_list_row;
listAnswers.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
if(txtAnswer.getVisibility() == TextView.VISIBLE) txtAnswer.setVisibility(TextView.GONE);
}
}
Choosing the right survey in the list works fine, but now the questions are displayed totaly wrong.
Actually there should be now 3 pages with 3 different questions. On the first page there should be a label with a question"Eine tolle FT Frage?" and below this label an EditText. On the second page there should be a label with a question "Eine tolle SC Frage?" and below a list with the answering options. On page three the should have the question "Eine tolle MC Frage?" and also a list below it with the same answering options as on page two.
The screenshos show a transition between the pages in the order: 1 -> 2 -> 3 -> 2 -> 1 -> 2.
you can see, that it does not appear in a way i described it above. the content of the pages does also change during the transition. i believe that there could be a problem with the DummyContent because it's static?!
If i create a survey with just one question, everything works fine...
Okay i've found the answer:
i wanted to initialize the used widgets in the onCreateView Callback. But then i always got "java.lang.IllegalStateException: Content view not yet created". A closer look showed, that this was just because of the getListView() method.
Now i switched the initialization of the widgets to the onCreateView() Callback but the getListView() i left in onActivityCreated().
Now everything works fine, and the fragments are displayed correctly!
That's how it looks right now:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.answer_question, null);
lblQuestion = (TextView) v.findViewById(R.id.lblQuestion);
txtAnswer = (EditText) v.findViewById(R.id.txtAnswer);
return v;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listAnswers = getListView();
setCorrectLayout();
initContent();
}
Add mIndicator.setOnPageChangeListener to your indicator.And send BroadCast inside for current page.
indicator.setOnPageChangeListener(new OnPageChangeListener()
{
#Override
public void onPageSelected(int page) {
switch (page) {
case 0:
sendBroadcast(intent)// update your content.When broadcast come set correct layout.
break;
default:
break;
}
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
#Override
public void onPageScrollStateChanged(int arg0) {}
});
Implement broadcast listener to the fragment.
Move your init methods(initWidgets(),initContent())
to a OnCreateView method
It should works
I hope someone can assist please. I have a Fragment hosting multiple list fragments using support library. The list fragments are supposed to display data that i retrieve form an async task in the parent fragment. I have been trying to figure out exactly how the data is being loaded because it is not loading correctly.
Each time the list display fragment is launched it preforms an async task to get and parse Json into an ArrayList <ArrayList <HashMap <String, String> > >
Each List fragment queries the parent fragment for data at its position in the ArrayList.
eg. For the 3rd page in it should retrieve arrList[2] which contains an `ArrayList <HashMap <String, String> > to display as a list.
The pager is acting weird. Maybe i am not understanding the lifecycle of the fragments or how the pager uses them. I have 7 Fragments. If i start on frag3 the pager will show fragment 3 with no data on it. It also loads fragment 2 and 4 with no data. If i go left to frag 1 it will display fragment 1 correctly and load fragment 0. I can properly switch to frag 0 but if i switch to frag 2 it loads data from frag 0 and loads frag 0's data into all of the rest of the views. If i go back and forth enough it will replace all data in every fragment with data from frag 0. I believe that it does not load data immediately because it does not have the data when the viewpager launches. I have not made it wait for the async task yet.
I thought that each fragment gets its view redrawn each time it is taken far enough from view. So i put Update in the onCreateView() of the fragment. I feel like this is a small thing that i have just misplaced or i am overlooking it. I tried to implement FragmentStatePagerAdapter but i do not think that i did it right.
Any Help is much Appreciated And i am very open to discussion if i am just doing things horribly wrong. I usually do. It never fails. Create something to find out i need to rewrite everything.
public class ListFragmentDisplay extends SherlockFragment {
public static final String TAG = "listFragmentDisplay";
Calendar calendar = Calendar.getInstance();
private int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
// listbyday is a list of hash maps each list of hash maps represents a day
// of the week with items for that Object
private ArrayList<ArrayList<HashMap<String, String>>> listByDay = null;
private String objectName = null;
private ViewPager pager;
private FragAdapter adapter;
public ArrayList<HashMap<String, String>> getList(int day) {
return listByDay.get(day);
}
private void getObjectName() {
barName = ((MainFragActivity) getActivity()).getobjectSelected();
}
public static ListFragmentDisplay newInstance() {
return new ListFragmentDisplay();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the ListView layout file.
initArrList();
getObjectName();
fillList();
return inflater.inflate(R.layout.list_view, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
pager = (ViewPager) view.findViewById(R.id.viewPager);
adapter =new FragAdapter(getChildFragmentManager());
if (pager.getAdapter() == null)
pager.setAdapter(adapter);
reload();
pager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageScrollStateChanged(int arg0) {}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {reload();}
#Override
public void onPageSelected(int arg0) {
}
});
pager.setCurrentItem(dayOfWeek-1);
}
private void initArrList() {
if (listByDay == null) {
listByDay = new ArrayList<ArrayList<HashMap<String, String>>>();
} else {
listByDay.clear();
}
for (int i = 0; i < 7; i++) {
ArrayList<HashMap<String, String>> hm = new ArrayList<HashMap<String, String>>();
listByDay.add(hm);
}
}
synchronized private void fillList() {
LoadWebTask lWT = new LoadWebTask();
executeAsyncTask(lWT, getSherlockActivity().getApplicationContext());
}
FragmentPager
public class FragAdapter extends FragmentPagerAdapter {
private static final String[] CONTENT = new String[] { "frag0", "frag1",
"frag2", "frag3", "frag4", "frag5", "frag6" };
public FragAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int arg0) {
return MyListFragment.newInstance(arg0);
}
#Override
public int getCount() {
return CONTENT.length;
}
#Override
public CharSequence getPageTitle(int position) {
return CONTENT[position % CONTENT.length];
}
}
ListFragment
public class MyListFragment extends SherlockListFragment {
public static final String NAME_TAG = "name";
public static final String DESCRIPTION_TAG = "description";
private static int dow;
public static final String TAG = "listFragment";
// Keys used in Hashmap that will be mapped to the rows
String[] dFrom = { NAME_TAG, DESCRIPTION_TAG };
private ArrayList<HashMap<String, String>> list;
int[] dTo = { R.id.name, R.id.description };
public void upDateList() {
//**************************Not really sure if this is how things are supposed
//** to be done. For my small data- set i feel like it will work but i would
//** be interested in knowing how else this might be done.
ListFragmentDisplay lFD = (ListFragmentDisplay) this
.getParentFragment();
dList = lFD.getList(dow);
}
public static MyListFragment newInstance(int pos) {
MyListFragment frag = new MyListFragment();
dow = pos;
return (frag);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
upDateList();
View results = inflater.inflate(R.layout.list_fragment, container,
false);
SimpleAdapter adapter = new SimpleAdapter(getParentFragment()
.getActivity(), list, R.layout.listrow, dFrom, dTo);
setListAdapter(adapter);
return results;
}
}
Edit. Solved Code: In List Fragment
The Initial Question has been solved. I am only in the process of implementing the onPostExecute callback to the ListFragmentDisplay. Much Thanks to Luksprog for solving my very noobish mistake. I made dow static without knowing its affect. I think it was actually something that Eclipse offered to solve a conflict. I should have read it closer.
public class MyListFragment extends SherlockListFragment {
public static final String NAME_TAG = "name";
public static final String DESCRIPTION_TAG = "description";
public static final String TAG = "listFragment";
// Keys used in Hashmap that will be mapped to the rows
String[] dFrom = { NAME_TAG, DESCRIPTION_TAG };
private ArrayList<HashMap<String, String>> list;
int[] dTo = { R.id.name, R.id.description };
SimpleAdapter adapter = null; **NEW**
public void upDateList() {
ListFragmentDisplay lFD = (ListFragmentDisplay) this
.getParentFragment();
dList = lFD.getList(getArguments().getInt(TAG)); **NEW**
if(adapter != null) **NEW**
adapter.notifyDataSetChanged(); **NEW**
}
public static MyListFragment newInstance(int pos) {
MyListFragment frag = new MyListFragment();
Bundle args = new Bundle(); **NEW**
args.putInt(TAG, pos); **NEW**
frag.setArguments(args); **NEW**
return (frag);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
upDateList();
View results = inflater.inflate(R.layout.list_fragment, container,
false);
adapter = new SimpleAdapter(getParentFragment()
.getActivity(), list, R.layout.listrow, dFrom, dTo);
setListAdapter(adapter);
return results;
}
}
Is there any reason why you made the dow variable from MyListFragment as static? With the static keyword your fragments from the ViewPager will share their position so you'll call the lFD.getList(dow); method with the wrong position most of the cases. Make dow a private instance field: private int dow;
About the rest of the code, it looks ok, see if the change above solves the problem. To update your data in the inner fragments you could follow this scenario:
start with an empty list of data in ListFragmentDisplay and start the task
initially, your inner ListFragmnents will see that the data list is empty so you'll initialize them with an empty list(the getList(int day) method should just return an empty list if there is no data in the listByDay field)
your task now finishes. Suppose you have a callback from the onPostExecute method of the AsyncTask. In that callback which the ListFragmentDisplay will implement you'll update every Fragment from the ViewPager which is either currently visible to the user or it's in the FragmentPagerAdapter alive(so each Fragment which is not null and its getView() method doesn't return null from the ViewPager will be updated). The other Fragments will self update because the onCreateView method will need to be called for them and you have the updateList call in there.
For the point above keep in mind that calling the updateList method will not update a visible Fragment because in that method you just update the list of the Fragment you don't call notifyDataSetChanged on the adapter to let it know that the data has changed.