I am working on Swipe Views with Tabs. The code provided in the "EffectiveNavigation" project at the Creating Swipe Views with Tabs page provides a solid starting ground. Experimenting further I added an OnClickListener to the given TextView and added a setCurrentItem to the onClick method. This behaves as expected and the ViewPager jumps to the requested page.
/**
* A dummy fragment representing a section of the app, but that simply displays dummy text.
*/
public static class DemoObjectFragment extends Fragment {
public static final String ARG_OBJECT = "object";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_collection_object, container, false);
Bundle args = getArguments();
((TextView) rootView.findViewById(android.R.id.text1)).setText(
Integer.toString(args.getInt(ARG_OBJECT)));
((TextView) rootView.findViewById(android.R.id.text1)).setOnClickListener(new OnClickListener() {
public void onClick(View v) {
/*
*setCurrentPagerItem(5); -> omitted here to reduce complexity
*/
mViewPager.setCurrentItem(5);
}
});
return rootView;
}
}
As the project I'm working on requires the loading of static webpages instead of text. I replaced the TextView with a WebView to load a different webpage at every swipe. This works perfectly well. Click events from the HTML side are handled by a JavascriptInterface I have implemented.
It is here that I'm facing a problem. The setCurrentPagerItem method works perfectly well when called outside of the JavascriptInterface. When called from within the JavascriptInterface the WebView shows a blank screen and stays so until a swipe to the right or left is made. A swipe to the right displays the next page to the one requested and a swipe to the left displays the requested page. LogCat shows no errors and this behaviour is consistent across a 4.3 based emulator and a Nexus 7 running 4.4.4. I shall provide the entire code below.
public class CollectionDemoActivity extends FragmentActivity {
/**
* The {#link android.support.v4.view.PagerAdapter} that will provide fragments representing
* each object in a collection. We use a {#link android.support.v4.app.FragmentStatePagerAdapter}
* derivative, which will destroy and re-create fragments as needed, saving and restoring their
* state in the process. This is important to conserve memory and is a best practice when
* allowing navigation between objects in a potentially large collection.
*/
DemoCollectionPagerAdapter mDemoCollectionPagerAdapter;
/**
* The {#link android.support.v4.view.ViewPager} that will display the object collection.
*/
ViewPager mViewPager;
private static Context context;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection_demo);
context = this;
// Create an adapter that when requested, will return a fragment representing an object in
// the collection.
//
// ViewPager and its adapters use support library fragments, so we must use
// getSupportFragmentManager.
mDemoCollectionPagerAdapter = new DemoCollectionPagerAdapter(getSupportFragmentManager());
// Set up action bar.
final ActionBar actionBar = getActionBar();
// Specify that the Home button should show an "Up" caret, indicating that touching the
// button will take the user one step up in the application's hierarchy.
actionBar.setDisplayHomeAsUpEnabled(true);
final OnPageChangeListener mPageChangeListener = new OnPageChangeListener() {
#Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
}
#Override
public void onPageSelected(int pos) {
final Toast pageNo;
pageNo = Toast.makeText(context,"PAGE "+(Integer.toString(pos+1))+"/100",Toast.LENGTH_SHORT);
pageNo.show();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
pageNo.cancel();
}
}, 100);
}
};
// Set up the ViewPager, attaching the adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mDemoCollectionPagerAdapter);
mViewPager.setOnPageChangeListener(mPageChangeListener);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// This is called when the Home (Up) button is pressed in the action bar.
// Create a simple intent that starts the hierarchical parent activity and
// use NavUtils in the Support Package to ensure proper handling of Up.
Intent upIntent = new Intent(this, MainActivity.class);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
// This activity is not part of the application's task, so create a new task
// with a synthesized back stack.
TaskStackBuilder.from(this)
// If there are ancestor activities, they should be added here.
.addNextIntent(upIntent)
.startActivities();
finish();
} else {
// This activity is part of the application's task, so simply
// navigate up to the hierarchical parent activity.
NavUtils.navigateUpTo(this, upIntent);
}
return true;
}
return super.onOptionsItemSelected(item);
}
private void setCurrentPagerItem(int item) {
mViewPager.setCurrentItem(item);
}
/**
* A {#link android.support.v4.app.FragmentStatePagerAdapter} that returns a fragment
* representing an object in the collection.
*/
public static class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter {
public DemoCollectionPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment fragment = new DemoObjectFragment();
Bundle args = new Bundle();
args.putInt(DemoObjectFragment.ARG_OBJECT, i + 1); // Our object is just an integer :-P
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
// For this contrived example, we have a 100-object collection.
return 100;
}
#Override
public CharSequence getPageTitle(int position) {
return "OBJECT " + (position + 1);
}
}
/**
* A dummy fragment representing a section of the app, but that simply displays dummy text.
*/
public static class DemoObjectFragment extends Fragment {
public static final String ARG_OBJECT = "object";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_collection_object, container, false);
Bundle args = getArguments();
final WebView webView = (WebView) rootView.findViewById(R.id.webView);
switch(args.getInt(ARG_OBJECT)) {
case 1 :
webView.loadUrl("file:///android_asset/html/index.html");
break;
default :
webView.loadUrl("file:///android_asset/html/page_"+(Integer.toString(args.getInt(ARG_OBJECT)-1))+".html");
break;
}
WebSettings ws = webView.getSettings();
ws.setJavaScriptEnabled(true);
webView.addJavascriptInterface(new Object()
{
#JavascriptInterface
public void toPage(String pageNo) {
((CollectionDemoActivity) getActivity()).setCurrentPagerItem(4);
}
}, "external");
return rootView;
}
}
}
I could be wrong but it sounds like you are not updating on the UIThread.
You could try something like this.
getActivity().runOnUiThread(new Runnable(){
#Override
public void run() {
((CollectionDemoActivity) getActivity()).setCurrentPagerItem(4);
}
});
Related
For the 2 last days I spent all my time to try to find a solution to a strange problem in a viewpager with fragment. All fragment contains a listview (which has his own adapter).
Here is the situation :
I have an activity which instantiate a viewpager and an adapter for it and contains the object adapter class.
public class SellerActivity extends AppCompatActivity {
/**
* The {#link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {#link FragmentPagerAdapter} derivative, which will keep every
* loaded fragment in memory. If this becomes too memory intensive, it
* may be best to switch to a
* {#link android.support.v4.app.FragmentStatePagerAdapter}.
*/
private SectionsPagerAdapter mSectionsPagerAdapter;
private FirebaseAuth mAuth = FirebaseAuth.getInstance();
/**
* The {#link ViewPager} that will host the section contents.
*/
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_seller);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.vpContainer2);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs2);
tabLayout.setupWithViewPager(mViewPager);
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
// This method will be invoked when a new page becomes selected.
#Override
public void onPageSelected(int position) {
mViewPager.setCurrentItem(position);
mSectionsPagerAdapter.getItem(position);
Toast.makeText(SellerActivity.this,
"Selected page position: " + position, Toast.LENGTH_SHORT).show();
}
// This method will be invoked when the current page is scrolled
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// Code goes here
}
// Called when the scroll state changes:
// SCROLL_STATE_IDLE, SCROLL_STATE_DRAGGING, SCROLL_STATE_SETTLING
#Override
public void onPageScrollStateChanged(int state) {
// Code goes here
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_shop, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
Intent i = new Intent(SellerActivity.this, MainActivity.class);
if (id == R.id.action_home) {
startActivity(i);
finish();
return true;
}
if (id == R.id.action_logout) {
mAuth.signOut();
startActivity(i);
finish();
return false;
}
return super.onOptionsItemSelected(item);
}
/**
* A {#link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
return SellerFragment.newInstance(position + 1, "1");
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "En Attente";
case 1:
return "En cours";
case 2:
return "Terminées";
}
return null;
}
}
I have then a fragment which looks like this :
public class SellerFragment extends Fragment {
private String title;
private int page;
private AllOrders allOrders;
final List<CommandItemForSeller> orders = new ArrayList<>();
final LinkedHashMap<String, Order> saveOrders = new LinkedHashMap<>();
public SellerFragment(){
}
// newInstance constructor for creating fragment with arguments
public static SellerFragment newInstance(int page, String title) {
SellerFragment fragmentFirst = new SellerFragment();
Bundle args = new Bundle();
args.putInt("someInt", page);
args.putString("someTitle", title);
fragmentFirst.setArguments(args);
return fragmentFirst;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
page = getArguments().getInt("someInt", 0);
title = getArguments().getString("someTitle");
allOrders = new AllOrders();
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_seller, container, false);
TextView tvLabel = (TextView) view.findViewById(R.id.tvLabel);
tvLabel.setText(page + " -- " + title);
DatabaseReference myRef = FirebaseDatabase.getInstance().getReference().child("orders");
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot orders : dataSnapshot.getChildren()) {
String orderString = orders.getValue(String.class);
//allOrders.addOrder(new Order(orderString, orders.getKey().substring(orders.getKey().length() - 4, orders.getKey().length())));
saveOrders.put(orders.getKey(), new Order(orderString, orders.getKey().substring(orders.getKey().length() - 4, orders.getKey().length())));
}
}
#Override
public void onChildChanged (DataSnapshot dataSnapshot, String s){
}
#Override
public void onChildRemoved (DataSnapshot dataSnapshot){
}
#Override
public void onChildMoved (DataSnapshot dataSnapshot, String s){
}
#Override
public void onCancelled (DatabaseError databaseError){
}
};
myRef.addChildEventListener(childEventListener);
orders.clear();
allOrders.clear();
allOrders.addAllOrders(saveOrders.values());
List<Order> selectedOrders = allOrders.getItemsOrderedByStatus(page);
for (int i = 0; i < selectedOrders.size(); i++) {
orders.add(new CommandItemForSeller(selectedOrders.get(i)));
}
CommandItemForSellerAdapter aa = new CommandItemForSellerAdapter(getActivity(), R.layout.pending_listview_item, orders);
ListView lv = (ListView) view.findViewById(R.id.commandListView);
lv.setAdapter(aa);
return view;
}
As you can see each fragment calls content from Firebase Database so it remains asynchronous.
My problem is :
When I try to load "synchronous" data (that I previsouly write in my code), list content is set by onCreate method at the first creation so each fragment for each tab get some content. However, the second tab never ever refresh for new data.
So in a case of asynchronous, onCreate method doesn't return any data (due to the load time) and new datas should be added by the onCreateView (like a refresh) but for the second tab it never happens !
After many hours of debugging, I've just found out the following :
When I switch from tab 1 to tab 2, fragment is rendered for tab 3. When I switch from tab 3 to tab 2, fragment is rendered for tab 1. Even if the getItem(position) returns the right position for the tab, tab 2 now never calls onCreateView method and remains empty.
Please.. tell me why this projet behaves like that, I don't want to give up but I really don't understand what is the issue here.
If you need more specific information, tell me I can give you anything you want.
When using FragmentPagerAdapter, ViewPager keeps adjacent pages "alive" (one to the left and one to the right) - meaning that when you have three fragments only, the second one will be never destroyed. You have to find a different way if you want to refresh data when fragments come into view - one idea is to add listener for page changes, using ViewPager.addOnPageChangeListener method - https://developer.android.com/reference/android/support/v4/view/ViewPager.html#addOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener)
Then, you can trigger refresh from within onPageSelected callback.
In your case, I think the simplest solution is to make SectionsPagerAdapter implement ViewPager.OnPageChangeListener, store reference to each created Fragment (preferably WeakReference), and then call some refresh method on an appropriate SellerFragment instance.
I'm trying to create an application using the Master/Detail Flow template provided by Android.
I'm trying to add multiple actionbar menu items to both the master and detail portions of the actionbar.
I have use the example of Android studio but when i set the different menu for master e for detail, is show only the menu (to right) .
the Activity detail is:
public class PDetailActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_p_detail);
// Show the Up button in the action bar.
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// savedInstanceState is non-null when there is fragment state
// saved from previous configurations of this activity
// (e.g. when rotating the screen from portrait to landscape).
// In this case, the fragment will automatically be re-added
// to its container so we don't need to manually add it.
// For more information, see the Fragments API guide at:
//
// http://developer.android.com/guide/components/fragments.html
//
if (savedInstanceState == null) {
// Create the detail fragment and add it to the activity
// using a fragment transaction.
Bundle arguments = new Bundle();
arguments.putString(PDetailFragment.ARG_ITEM_ID, getIntent().getStringExtra(PatientDetailFragment.ARG_ITEM_ID));
PatientDetailFragment fragment = new PDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction().add(R.id.p_detail_container, fragment).commit();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_p_detail, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. For
// more details, see the Navigation pattern on Android Design:
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
//
navigateUpTo(new Intent(this, PListActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
the fragment detail is:
public class PDetailFragment extends Fragment {
/**
* The fragment argument representing the item ID that this fragment
* represents.
*/
public static final String ARG_ITEM_ID = "item_id";
/**
* The dummy content this fragment is presenting.
*/
private PObj mItem;
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public PDetailFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
((PatientDetailActivity)getActivity()).getSupportActionBar().setTitle("Detail");
if (getArguments().containsKey(ARG_ITEM_ID)) {
// Load the dummy content specified by the fragment
// arguments. In a real-world scenario, use a Loader
// to load content from a content provider.
mItem = PListFragment.pObjHashMap.get(getArguments().getString(ARG_ITEM_ID));
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_p_detail, container, false);
// Show the dummy content as text in a TextView.
if (mItem != null) {
((TextView) rootView.findViewById(R.id.p_detail)).setText(mItem.name);
}
return rootView;
}
}
The activity master:
public class PListActivity extends BaseActivity implements PListFragment.Callbacks {
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
* device.
*/
private boolean mTwoPane;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_p_list);
// Show the Up button in the action bar.
// getActionBar().setDisplayHomeAsUpEnabled(true);
if (findViewById(R.id.p_detail_container) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-large and
// res/values-sw600dp). If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
// In two-pane mode, list items should be given the
// 'activated' state when touched.
((PListFragment) getSupportFragmentManager()
.findFragmentById(R.id.p_list))
.setActivateOnItemClick(true);
}
// TODO: If exposing deep links into your app, handle intents here.
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_p, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. Use NavUtils to allow users
// to navigate up one level in the application structure. For
// more details, see the Navigation pattern on Android Design:
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
//
// navigateUpFromSameTask(this);
SharedPreferenceObj sp = MySharedPref.getSharedPref(getApplicationContext());
sp.setLast_id_office(StaticValues.ID);
MySharedPref.setSharedPref(getApplicationContext(), sp);
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Callback method from {#link PListFragment.Callbacks}
* indicating that the item with the given ID was selected.
*/
#Override
public void onItemSelected(String id) {
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
Bundle arguments = new Bundle();
arguments.putString(PatientDetailFragment.ARG_ITEM_ID, id);
PatientDetailFragment fragment = new PDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.p_detail_container, fragment)
.commit();
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent dIntent = new Intent(this, PDetailActivity.class);
dIntent.putExtra(PDetailFragment.ARG_ITEM_ID, id);
startActivity(dIntent);
}
}
#Override
public void onBackPressed() {
SharedPreferenceObj sp = MySharedPref.getSharedPref(getApplicationContext());
sp.setLast_id_office(StaticValues.ID);
MySharedPref.setSharedPref(getApplicationContext(),sp);
super.onBackPressed();
}
}
the fragment master is:
public class PListFragment extends ListFragment {
//DummyContent dummyContent ;
public static List<PObj> pObjArrayList = new ArrayList<PObj>();
public static Map<String, PObj> pObjHashMap = new HashMap<String, PObj>();
/**
* The serialization (saved instance state) Bundle key representing the
* activated item position. Only used on tablets.
*/
private static final String STATE_ACTIVATED_POSITION = "activated_position";
/**
* The fragment's current callback object, which is notified of list item
* clicks.
*/
private Callbacks mCallbacks = sDummyCallbacks;
/**
* The current activated item position. Only used on tablets.
*/
private int mActivatedPosition = ListView.INVALID_POSITION;
/**
* A callback interface that all activities containing this fragment must
* implement. This mechanism allows activities to be notified of item
* selections.
*/
public interface Callbacks {
/**
* Callback for when an item has been selected.
*/
public void onItemSelected(String id);
}
/**
* A dummy implementation of the {#link Callbacks} interface that does
* nothing. Used only when this fragment is not attached to an activity.
*/
private static Callbacks sDummyCallbacks = new Callbacks() {
#Override
public void onItemSelected(String id) {
}
};
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public PListFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
((PListActivity)getActivity()).getSupportActionBar().setTitle("Master");
pObjArrayList.clear();
pObjHashMap.clear();
for (int i=0;i<10;i++) {
patientObjArrayList.add(new PObj(i+"","name"+i,"address"+i));
patientObjHashMap.put(i+"",new PObj(i+"","name"+i,"address"+i));
}
setListAdapter(new ArrayAdapter<PObj>(getActivity(), android.R.layout.simple_list_item_activated_1,
android.R.id.text1, patientObjArrayList));
// TODO: replace with a real list adapter.
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Restore the previously serialized activated item position.
if (savedInstanceState != null
&& savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
Activity activity = (Activity) context;
// Activities containing this fragment must implement its callbacks.
if (!(activity instanceof Callbacks)) {
throw new IllegalStateException("Activity must implement fragment's callbacks.");
}
mCallbacks = (Callbacks) activity;
}
#Override
public void onDetach() {
super.onDetach();
// Reset the active callbacks interface to the dummy implementation.
mCallbacks = sDummyCallbacks;
}
#Override
public void onListItemClick(ListView listView, View view, int position, long id) {
super.onListItemClick(listView, view, position, id);
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mCallbacks.onItemSelected(pObjArrayList.get(position).id);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mActivatedPosition != ListView.INVALID_POSITION) {
// Serialize and persist the activated item position.
outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
}
}
/**
* Turns on activate-on-click mode. When this mode is on, list items will be
* given the 'activated' state when touched.
*/
public void setActivateOnItemClick(boolean activateOnItemClick) {
// When setting CHOICE_MODE_SINGLE, ListView will automatically
// give items the 'activated' state when touched.
getListView().setChoiceMode(activateOnItemClick
? ListView.CHOICE_MODE_SINGLE
: ListView.CHOICE_MODE_NONE);
}
private void setActivatedPosition(int position) {
if (position == ListView.INVALID_POSITION) {
getListView().setItemChecked(mActivatedPosition, false);
} else {
getListView().setItemChecked(position, true);
}
mActivatedPosition = position;
}
}
The problem is that i show only one menu (master) and no the menu (detail)
in this screenshot
in this screenshot I have only one menu and the + is on the right instead of the left next to the title "Master".
In the part relating to the detail is missing from the title and even the symbol X.
how can fix my problem?
Context:
I'm making a music player and I'm currently working on the miniplayer. The miniplayer lives in a ViewPager along with a floating action button (FAB) for shuffle. Initially, only the FAB is seen on screen. When you click on the FAB, music playback starts, the Fab-Miniplayer ViewPager's page count goes from 1 to 2, and its page is set to the second page, where the miniplayer is. The miniplayer itself in the second page is a vertical viewpager, so one can swipe through to different songs. The miniplayer/vertical viewpager is backed by a PagerAdapter that gets songs from a SongQueue obejct.
The Problem:
If I click on the FAB once, the miniplayer opens and everything works. Then I dismiss the miniplayer to stop playback by swiping back to the FAB page in the ViewPager. After clicking on the FAB to start playback and open the miniplayer for the second time, the first two fragments are never created. The miniplayer vertical ViewPager's PagerAdapter's getItem() methods are never called for item 0 and item 1. On a higher level, the first two songs in the miniplayer aren't showing up. Upon further investigation, the onCreate() methods are being called for the first two songs from the last time the miniplayer was opened, so I'm guessing the ViewPager is implementing some kind of caching or a reference is being held onto for too long because the miniplayer vertical viewpager thinks that it already has the first two songs the second time it is instantiated. Hopefully this problem description makes sense. If there are any questions, I'd be happy to try and go into more detail.
The Code
SongsFragment
/**
* Fragment used to display all of the songs on the device.
*/
public class SongsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
private static final String TAG = "SongsFragment";
private SwipeListView mSwipeListView;
private ViewPager fabMiniPlayerViewPager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
setHasOptionsMenu(true);
// Initialize the loader to load the list of songs
getLoaderManager().initLoader(SongCursorLoader.ALL_SONGS_ID, null, this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.list_view_songs, parent, false);
if (view != null) {
mSwipeListView = (SwipeListView) view.findViewById(R.id.list_view_songs);
}
LinearLayout emptyView = (LinearLayout) inflater.inflate(R.layout.list_view_songs_empty, parent, false);
mSwipeListView.setEmptyView(emptyView);
fabMiniPlayerViewPager = (ViewPager) view.findViewById(R.id.fab_miniplayer_ViewPager);
Integer viewPagerPageCount = new Integer(1);
fabMiniPlayerViewPager.setTag(viewPagerPageCount); // The fabMiniPlayerViewPager gets it's page count from the tag so it can be dynamically modified
fabMiniPlayerViewPager.setAdapter(new FragmentStatePagerAdapter(getChildFragmentManager()) {
#Override
public Fragment getItem(int i) {
if (i == 0) {
// ShuffleFabFragment just houses a single button, the code is below
ShuffleFabFragment fragment = new ShuffleFabFragment();
fragment.setViewPager(fabMiniPlayerViewPager);
return fragment;
}
MiniPlayerFragment fragment = new MiniPlayerFragment();
return fragment;
}
#Override
public int getCount() {
Integer count = (Integer) fabMiniPlayerViewPager.getTag();
return count.intValue();
}
});
fabMiniPlayerViewPager.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
// Pass touch events to the list view behind it
mSwipeListView.onTouchEvent(motionEvent);
return false;
}
});
return view;
}
#Override
public void onResume() {
super.onResume();
if (!MusicPlayerService.isStopped()) {
Integer viewPagerPageCount = 2;
fabMiniPlayerViewPager.setTag(viewPagerPageCount);
PagerAdapter adapter = fabMiniPlayerViewPager.getAdapter();
fabMiniPlayerViewPager.setAdapter(adapter);
fabMiniPlayerViewPager.setCurrentItem(1, false);
} else {
Integer viewPagerPageCount = 1;
fabMiniPlayerViewPager.setTag(viewPagerPageCount);
fabMiniPlayerViewPager.getAdapter().notifyDataSetChanged();
}
}
}
ShuffleFabFragment
/**
* Fragment representing the Shuffle Floating Action Button. On FAB click, it turns on shuffle and
* plays a random song. Depending on the user preference, the mini-player will appear or the
* Now Playing view will appear. The ShuffleFabFragment holds a reference to its containing
* ViewPager so it can do the following:
* <p/>
* 1. Add the MiniPlayer fragment to the ViewPager to enable swiping & animations
* 2. Remove the MiniPlayer fragment when it is swiped away
* <p/>
* Once the MiniPlayer is swiped away (to the right), it stops music playback.
*/
public class ShuffleFabFragment extends Fragment {
private static final String TAG = "ShuffleFabFragment";
private ViewPager fabMiniPlayerViewPager;
public void setViewPager(ViewPager viewPager) {
fabMiniPlayerViewPager = viewPager;
fabMiniPlayerViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i2) {
}
#Override
public void onPageSelected(int i) {
if (i == 0) { // MiniPlayer swiped away
Integer viewPagerPageCount = new Integer(1);
fabMiniPlayerViewPager.setTag(viewPagerPageCount);
PagerAdapter adapter = fabMiniPlayerViewPager.getAdapter();
Intent stopMusicIntent = new Intent(getActivity(), MusicPlayerService.class);
stopMusicIntent.setAction(MusicPlayerService.ACTION_STOP);
getActivity().startService(stopMusicIntent);
fabMiniPlayerViewPager.setAdapter(adapter);
}
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.shuffle_fab, viewGroup, false);
ImageView shuffleFabImageView = (ImageView) view.findViewById(R.id.shuffle_fab_ImageView);
shuffleFabImageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
// Scale up on touch to make the button appear to come closer
view.setScaleX(8f / 7f);
view.setScaleY(8f / 7f);
break;
case MotionEvent.ACTION_UP:
view.setScaleX(1f);
view.setScaleY(1f);
break;
default:
view.setScaleX(1f);
view.setScaleY(1f);
}
return false;
}
});
shuffleFabImageView.setClickable(true);
shuffleFabImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String shuffleMode = PreferencesHelper.getShuffleMode(getActivity());
if (shuffleMode.equals(PreferencesHelper.SHUFFLE_MODE_OFF)) {
PreferencesHelper.setShuffleMode(getActivity(), PreferencesHelper.SHUFFLE_MODE_SMART);
}
SongQueue.initializeQueue(null, true, Song.COLLECTION_TYPE_ALL_SONGS, getActivity().getApplicationContext(), null);
Song firstSong = SongQueue.getSong(0);
firstSong.play(getActivity(), false);
// On Click, update the page count, then set page to miniplayer
Integer viewPagerPageCount = new Integer(2);
fabMiniPlayerViewPager.setTag(viewPagerPageCount);
fabMiniPlayerViewPager.getAdapter().notifyDataSetChanged();
fabMiniPlayerViewPager.setCurrentItem(1, true);
}
});
return view;
}
}
MiniPlayerFragment
/**
* Hosts MiniplayerCardFragments and allows for song skipping
*/
public class MiniPlayerFragment extends Fragment implements ViewPager.OnPageChangeListener {
VerticalViewPager miniplayerCardViewPager;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.view_pager_miniplayer, viewGroup, false);
miniplayerCardViewPager = (VerticalViewPager) view.findViewById(R.id.miniplayer_cards_ViewPager);
miniplayerCardViewPager.setAdapter(new FragmentStatePagerAdapter(getChildFragmentManager()) {
#Override
public Fragment getItem(int position) {
Song song = SongQueue.getSong(position);
return MiniPlayerCardFragment.newInstance(song);
}
#Override
public int getCount() {
return SongQueue.getTotalSize();
}
});
miniplayerCardViewPager.setOnPageChangeListener(this);
SongQueue.addOnQueueChangeListener(new SongQueue.OnQueueChangeListener() {
#Override
public void onNextSongChanged() {
onQueueChanged();
}
#Override
public void onQueueChanged() {
// Force re-layout to update fragments
int queuePosition = SongQueue.getQueuePositionCurrentSong();
PagerAdapter adapter = miniplayerCardViewPager.getAdapter();
miniplayerCardViewPager.setAdapter(adapter);
miniplayerCardViewPager.setCurrentItem(queuePosition, true);
}
#Override
public void onCurrentSongChanged() {
onQueueChanged();
}
});
return view;
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
int queuePosition = SongQueue.getQueuePositionCurrentSong();
if (queuePosition < position) {
Intent nextIntent = new Intent(getActivity(), MusicPlayerService.class);
nextIntent.setAction(MusicPlayerService.ACTION_NEXT);
getActivity().startService(nextIntent);
} else if (queuePosition > position) {
Intent prevIntent = new Intent(getActivity(), MusicPlayerService.class);
prevIntent.setAction(MusicPlayerService.ACTION_PREV);
getActivity().startService(prevIntent);
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
#Override
public void onResume() {
super.onResume();
// Force re-layout to update fragments
int queuePosition = SongQueue.getQueuePositionCurrentSong();
PagerAdapter adapter = miniplayerCardViewPager.getAdapter();
miniplayerCardViewPager.setAdapter(adapter);
miniplayerCardViewPager.setCurrentItem(queuePosition, true);
SongQueue.setPagerAdapter(adapter);
}
}
Screenshots to help visualization
After clicking on the FAB to start playback and open the miniplayer for the second time, the first two fragments are never created. The miniplayer vertical ViewPager's PagerAdapter's getItem() methods are never called for item 0 and item 1.
That is because the standard ViewPager already has pages 0 and 1. To clarify Sanket's answer, setOffscreenPageLimit() indicates how many pages to either side of the current page to create (via getItem()) and cache, and the minimum value is 1. Calls to setOffscreenPageLimit(0) will be ignored.
getItem() is not a means of finding out when the user switches pages. A PageChangeListener is your means of finding out when the user switches pages.
the miniplayer vertical viewpager thinks that it already has the first two songs the second time it is instantiated
It's not being instantiated a second time AFAICT.
ViewPager has bydefault offScreenPagerLimit value 3.. so it may be not loading your first 2 item second time..
try with this
mViewPager.setOffscreenPageLimit(0);
more info
What i am trying to do ::
I want header for a certain set of rows one after another
What i am using:: Sticky Header( i am running this sample)
What is happening::
Project runs well but when i scroll the header goes and sits on top until the next header comes
Question:: (Disabling pinned header & enable the header scroll along with grid)
I want to disable this feature so that the header scrolls along with
gridview being scrolled instead of waiting for the next header
I have seen this feature possible in expandable listview but how to
implement this here
ItemDetailFragment.java
public class ItemDetailFragment extends Fragment {
/**
* The fragment argument representing the item ID that this fragment
* represents.
*/
public static final String ARG_ITEM_ID = "item_id";
/**
* The dummy content this fragment is presenting.
*/
private int mItem;
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public ItemDetailFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments().containsKey(ARG_ITEM_ID)) {
// Load the dummy content specified by the fragment
// arguments. In a real-world scenario, use a Loader
// to load content from a content provider.
mItem = getArguments().getInt(ARG_ITEM_ID);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_item_detail, container, false);
((TextView) rootView.findViewById(R.id.item_detail)).setText(getResources().getStringArray(R.array.countries)[mItem]);
return rootView;
}
}
ItemListActivity.java
public class ItemListActivity extends ActionBarActivity implements ItemListFragment.Callbacks {
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
* device.
*/
private boolean mTwoPane;
/**
* Callback method from {#link ItemListFragment.Callbacks} indicating that
* the item with the given ID was selected.
*/
#Override
public void onItemSelected(int id) {
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
Bundle arguments = new Bundle();
arguments.putInt(ItemDetailFragment.ARG_ITEM_ID, id);
ItemDetailFragment fragment = new ItemDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.item_detail_container, fragment)
.commit();
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent detailIntent = new Intent(this, ItemDetailActivity.class);
detailIntent.putExtra(ItemDetailFragment.ARG_ITEM_ID, id);
startActivity(detailIntent);
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_list);
if (findViewById(R.id.item_detail_container) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-large and
// res/values-sw600dp). If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
// In two-pane mode, list items should be given the
// 'activated' state when touched.
((ItemListFragment) getSupportFragmentManager().findFragmentById(R.id.item_list)).setActivateOnItemClick(true);
}
// TODO: If exposing deep links into your app, handle intents here.
}
}
ItemListFragment.java
public class ItemListFragment extends Fragment implements OnItemClickListener,
OnHeaderClickListener, OnHeaderLongClickListener {
private static final String KEY_LIST_POSITION = "key_list_position";
/**
* A dummy implementation of the {#link Callbacks} interface that does
* nothing. Used only when this fragment is not attached to an activity.
*/
private static Callbacks sDummyCallbacks = new Callbacks() {
#Override
public void onItemSelected(int id) {
}
};
/**
* The serialization (saved instance state) Bundle key representing the
* activated item position. Only used on tablets.
*/
private static final String STATE_ACTIVATED_POSITION = "activated_position";
/**
* The current activated item position. Only used on tablets.
*/
private int mActivatedPosition = ListView.INVALID_POSITION;
/**
* The fragment's current callback object, which is notified of list item
* clicks.
*/
private Callbacks mCallbacks = sDummyCallbacks;
private int mFirstVisible;
private GridView mGridView;
private Menu mMenu;
private Toast mToast;
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public ItemListFragment() {
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Activities containing this fragment must implement its callbacks.
if (!(activity instanceof Callbacks)) {
throw new IllegalStateException("Activity must implement fragment's callbacks.");
}
mCallbacks = (Callbacks)activity;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_item_list, menu);
mMenu = menu;
menu.findItem(R.id.menu_toggle_sticky).setChecked(
((StickyGridHeadersGridView)mGridView).areHeadersSticky());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_item_grid, container, false);
}
#Override
public void onDetach() {
super.onDetach();
// Reset the active callbacks interface to the dummy implementation.
mCallbacks = sDummyCallbacks;
}
#Override
public void onHeaderClick(AdapterView<?> parent, View view, long id) {
String text = "Header " + ((TextView)view.findViewById(android.R.id.text1)).getText() + " was tapped.";
if (mToast == null) {
mToast = Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT);
} else {
mToast.setText(text);
}
mToast.show();
}
#Override
public boolean onHeaderLongClick(AdapterView<?> parent, View view, long id) {
String text = "Header " + ((TextView)view.findViewById(android.R.id.text1)).getText() + " was long pressed.";
if (mToast == null) {
mToast = Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT);
} else {
mToast.setText(text);
}
mToast.show();
return true;
}
#Override
public void onItemClick(AdapterView<?> gridView, View view, int position, long id) {
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mCallbacks.onItemSelected(position);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_toggle_sticky:
item.setChecked(!item.isChecked());
((StickyGridHeadersGridView)mGridView)
.setAreHeadersSticky(!((StickyGridHeadersGridView)mGridView)
.areHeadersSticky());
return true;
case R.id.menu_use_list_adapter:
mGridView.setAdapter(new ArrayAdapter<String>(getActivity(), R.layout.item,
getResources().getStringArray(R.array.countries)));
mMenu.findItem(R.id.menu_use_list_adapter).setVisible(false);
mMenu.findItem(R.id.menu_use_sticky_adapter).setVisible(true);
mMenu.findItem(R.id.menu_toggle_sticky).setVisible(false);
return true;
case R.id.menu_use_sticky_adapter:
mGridView.setAdapter(new StickyGridHeadersSimpleArrayAdapter<String>(getActivity()
.getApplicationContext(), getResources().getStringArray(R.array.countries),
R.layout.header, R.layout.item));
mMenu.findItem(R.id.menu_use_list_adapter).setVisible(true);
mMenu.findItem(R.id.menu_toggle_sticky).setVisible(true);
mMenu.findItem(R.id.menu_use_sticky_adapter).setVisible(false);
return true;
default:
break;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mActivatedPosition != ListView.INVALID_POSITION) {
// Serialize and persist the activated item position.
outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
}
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mGridView = (GridView)view.findViewById(R.id.asset_grid);
mGridView.setOnItemClickListener(this);
/*
* Currently set in the XML layout, but this is how you would do it in
* your code.
*/
// mGridView.setColumnWidth((int) calculatePixelsFromDips(100));
// mGridView.setNumColumns(StickyGridHeadersGridView.AUTO_FIT);
mGridView.setAdapter(new StickyGridHeadersSimpleArrayAdapter<String>(getActivity()
.getApplicationContext(), getResources().getStringArray(R.array.countries),
R.layout.header, R.layout.item));
if (savedInstanceState != null) {
mFirstVisible = savedInstanceState.getInt(KEY_LIST_POSITION);
}
mGridView.setSelection(mFirstVisible);
// Restore the previously serialized activated item position.
if (savedInstanceState != null && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
}
((StickyGridHeadersGridView)mGridView).setOnHeaderClickListener(this);
((StickyGridHeadersGridView)mGridView).setOnHeaderLongClickListener(this);
setHasOptionsMenu(true);
}
/**
* Turns on activate-on-click mode. When this mode is on, list items will be
* given the 'activated' state when touched.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void setActivateOnItemClick(boolean activateOnItemClick) {
// When setting CHOICE_MODE_SINGLE, ListView will automatically
// give items the 'activated' state when touched.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mGridView.setChoiceMode(activateOnItemClick ? ListView.CHOICE_MODE_SINGLE
: ListView.CHOICE_MODE_NONE);
}
}
#SuppressLint("NewApi")
private void setActivatedPosition(int position) {
if (position == ListView.INVALID_POSITION) {
mGridView.setItemChecked(mActivatedPosition, false);
} else {
mGridView.setItemChecked(position, true);
}
mActivatedPosition = position;
}
/**
* A callback interface that all activities containing this fragment must
* implement. This mechanism allows activities to be notified of item
* selections.
*/
public interface Callbacks {
/**
* Callback for when an item has been selected.
*/
public void onItemSelected(int position);
}
}
ItemDetailActivity.java
public class ItemDetailActivity extends ActionBarActivity {
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. Use NavUtils to allow users
// to navigate up one level in the application structure. For
// more details, see the Navigation pattern on Android Design:
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
//
NavUtils.navigateUpTo(this, new Intent(this, ItemListActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_detail);
// Show the Up button in the action bar.
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// savedInstanceState is non-null when there is fragment state
// saved from previous configurations of this activity
// (e.g. when rotating the screen from portrait to landscape).
// In this case, the fragment will automatically be re-added
// to its container so we don't need to manually add it.
// For more information, see the Fragments API guide at:
//
// http://developer.android.com/guide/components/fragments.html
//
if (savedInstanceState == null) {
// Create the detail fragment and add it to the activity
// using a fragment transaction.
Bundle arguments = new Bundle();
arguments.putInt(ItemDetailFragment.ARG_ITEM_ID,
getIntent().getIntExtra(ItemDetailFragment.ARG_ITEM_ID, 0));
ItemDetailFragment fragment = new ItemDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.add(R.id.item_detail_container, fragment).commit();
}
}
}
You can make the headers scroll with your view by adding the following to your code:
mGridView.setAreHeadersSticky(false);
Hope this helps.
I have a main activity and three fragments under it that can be switched by swiping left and right. Nothing special. The 1st and 3rd(last) fragment both use Asynctask to grap some info from online. What I'm trying to achieve here is three fragments that load up info from online and later on, I want to add in the pull down to refresh, but that shouldn't be a problem.
Here's what happens.
When you open the app, its set to open the 2nd(middle) fragment.
Upon swiping to the 3rd fragment, you'll see that everything loads up fine.
Upon returning to the 2nd fragment and going back to the 3rd, it completely disappears and returns as a blank page.
Now if I scroll twice back to the 1st fragment, and complete the network operation, it works fine.
Try to do it again, the button doesn't reply.
I believe it has something to do with the Asynctask. If there's a better way to setup this whole thing I have here, then please feel free to do so.
Main
public class Main extends FragmentActivity {
/**
* The {#link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {#link android.support.v4.app.FragmentPagerAdapter} derivative, which
* will keep every loaded fragment in memory. If this becomes too memory
* intensive, it may be best to switch to a
* {#link android.support.v4.app.FragmentStatePagerAdapter}.
*/
SectionsPagerAdapter mSectionsPagerAdapter;
/**
* The {#link ViewPager} that will host the section contents.
*/
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.a_main);
// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(
getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.setCurrentItem(1, false);
}
/**
* A {#link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a DummySectionFragment (defined as a static inner class
// below) with the page number as its lone argument.
// Fragment fragment = new DummySectionFragment();
// Bundle args = new Bundle();
// args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
// fragment.setArguments(args);
// return fragment;
switch (position) {
case 0:
// Top Rated fragment activity
return new Post();
case 1:
// Games fragment activity
return new Feed();
case 2:
// Movies fragment activity
return new Explore();
}
return null;
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return "Post";
case 1:
return "Feed";
case 2:
return "Explore";
}
return null;
}
}
}
1st Fragment
public class Post extends Fragment {
private MyAsyncTask mAuthTask = null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.f_post, container, false);
Button addGoalButton = (Button) rootView.findViewById(R.id.submit);
addGoalButton.setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
// Pass the fragmentView through to the handler
// so that findViewById can be used to get a handle on
// the fragments own views.
attemptLogin();
}
});
return rootView;
}
public void attemptLogin() {
if (mAuthTask != null) {
return;
}
mAuthTask = new MyAsyncTask();
mAuthTask.execute((Void) null);
}
private class MyAsyncTask extends AsyncTask<Void, Void, Void>
{
#Override
protected void onPostExecute(Void result) {
//mProgressDialog.dismiss();
}
#Override
protected void onPreExecute() {
Toast.makeText(getActivity(),
"dont worry, be happy!", Toast.LENGTH_LONG).show();
}
#Override
protected Void doInBackground(Void... params) {
// my network operation
return null;
}
}
}
3rd Fragment
public class Explore extends Fragment {
private MyAsyncTask mAuthTask = null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.f_explore, container, false);
attemptLogin();
return rootView;
}
public void attemptLogin() {
if (mAuthTask != null) {
return;
}
mAuthTask = new MyAsyncTask();
mAuthTask.execute((Void) null);
}
private class MyAsyncTask extends AsyncTask<Void, Void, Void>
{
#Override
protected void onPostExecute(Void result) {
//mProgressDialog.dismiss();
}
#Override
protected void onPreExecute() {
Toast.makeText(getActivity(),
"Loading Explore", Toast.LENGTH_LONG).show();
}
#Override
protected Void doInBackground(Void... params) {
// my network operation
return null;
}
}
}
I think it a may be a couple issues.
Multiple Asynctasks cannot be run at the same time and with Viewpagers it loads 3 views by default. I believe you need to call: (whereever you don't want a code to be run for all the views which need to be loaded)
if(getUserVisibleHint()) {
//logic in here
attemptLogin();
}
I believe this will stop your onCreateView() method being called 3 times. So pretty much because a view pager has this method: mPager.setOffscreenPageLimit(1); which does this:
Set the number of pages that should be retained to either side of the current page
in the view hierarchy in an idle state.
By default it is at 1, which means if it will load the fragment to the left and right to make scrolling smooth. (You can't change this to 0). And so the getUserVisibleHint will check if the current view is the one the suer can see and call whatever stuff you put inside it, only when its visible. (because by default it would call your asynctask 3 times, and they cannot be run at the same time.
I may be wrong though.
Edit #1:
First fragment fixed by setting asynctask back to null in onPostExecute.