So I want to create 3 tabs, all different from each other. The xml I have that covered. But not how to create the tabs without it crashing my app.
I have implemented the swipe tab with viewpage.
http://developer.android.com/training/implementing-navigation/lateral.html
http://www.androidhive.info/2013/10/android-tab-layout-with-swipeable-views-1/
and part of
http://www.java2s.com/Code/Android/UI/Demonstrateshowfragmentscanparticipateintheoptionsmenu.htm
When I try to go to the next tab(swipe does work no problem) I get an error:
07-08 22:07:57.414: E/AndroidRuntime(6865): FATAL EXCEPTION: main
07-08 22:07:57.414: E/AndroidRuntime(6865): Process: com.cyberdog.magiceasydraft, PID: 6865
07-08 22:07:57.414: E/AndroidRuntime(6865): java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v4.view.ViewPager.setCurrentItem(int)' on a null object reference
07-08 22:07:57.414: E/AndroidRuntime(6865): at com.cyberdog.magiceasydraft.addPlayersfragmentTab.doPositiveClick(addPlayersfragmentTab.java:113)
07-08 22:07:57.414: E/AndroidRuntime(6865): at com.cyberdog.magiceasydraft.addPlayersfragmentTab$MyAlertDialogFragment$1.onClick(addPlayersfragmentTab.java:165)
07-08 22:07:57.414: E/AndroidRuntime(6865): at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:160)
07-08 22:07:57.414: E/AndroidRuntime(6865): at android.os.Handler.dispatchMessage(Handler.java:102)
07-08 22:07:57.414: E/AndroidRuntime(6865): at android.os.Looper.loop(Looper.java:135)
07-08 22:07:57.414: E/AndroidRuntime(6865): at android.app.ActivityThread.main(ActivityThread.java:5274)
07-08 22:07:57.414: E/AndroidRuntime(6865): at java.lang.reflect.Method.invoke(Native Method)
07-08 22:07:57.414: E/AndroidRuntime(6865): at java.lang.reflect.Method.invoke(Method.java:372)
07-08 22:07:57.414: E/AndroidRuntime(6865): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:909)
07-08 22:07:57.414: E/AndroidRuntime(6865): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:704)
So.. what am I doing wrong here? I can see that there is a null reference to my create round fragment... but I have no clue how to fix this. This is my first time working with fragments and tabs.
code:
main activity:
public class CreateDraft extends FragmentActivity implements
ActionBar.TabListener {
private ViewPager viewPager;
private fragmentPageAdapter mAdapter;
private ActionBar actionBar;
private Fragment addPlayer, createRound,score;
private String[] tabs = { "Add players", "Create round", "Score" };
public static final String CuSToM_FRAGMENT_KEY ="ADD_PLAYER_TAB";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_draft);
viewPager = (ViewPager) findViewById(R.id.activity_viewpager_main);
actionBar = getActionBar();
mAdapter = new fragmentPageAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
if(savedInstanceState == null){
FragmentManager fm = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction ft = fm.beginTransaction();
addPlayer = fm.findFragmentByTag("Add Players");
if(addPlayer == null){
addPlayer = new addPlayersfragmentTab();
ft.add(addPlayer, "Add players");
}
createRound = fm.findFragmentByTag("Create round");
if(createRound == null){
createRound = new createRoundfragmentTab();
ft.add(createRound, "Create round");
}
score = fm.findFragmentByTag("Score");
if(score == null){
score = new scoreResultfragmentTab();
ft.add(score, "Score");
}
ft.commit();
}
//
for (String tab_name : tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name)
.setTabListener(this));
}
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
public void passBundleToFragment(int position){
if(true){
}
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
View focus = getCurrentFocus();
if (focus != null) {
hiddenKeyboard(focus);
}
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// on tab selected
// show respected fragment view
viewPager.setCurrentItem(tab.getPosition());
View focus = getCurrentFocus();
if (focus != null) {
hiddenKeyboard(focus);
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
View focus = getCurrentFocus();
if (focus != null) {
hiddenKeyboard(focus);
}
}
private void hiddenKeyboard(View v) {
InputMethodManager keyboard = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
keyboard.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
One of the fragments(others don't contain much code yet):
public class addPlayersfragmentTab extends Fragment {
private Button addPlayer, createDraft;
private EditText evAddPlayer;
private ViewPager viewPager;
private List<Player> players;
private ListView lvAddedPlayers;
ListAdapter adapter;
private boolean buttonCreateDraftPressed= false;
public boolean isButtonCreateDraftPressed() {
return buttonCreateDraftPressed;
}
public void setButtonCreateDraftPressed(boolean buttonCreateDraftPressed) {
this.buttonCreateDraftPressed = buttonCreateDraftPressed;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.draft_adding_players,
container, false);
initialiseEditAndText(rootView);
players = new ArrayList<Player>();
lvAddedPlayers = (ListView) rootView.findViewById(
R.id.lv_players_adding);
adapter = new ListAdapter(rootView.getContext(), players);
lvAddedPlayers.setAdapter(adapter);
addPlayer = (Button) rootView.findViewById(R.id.button_total_player);
createDraft = (Button) rootView.findViewById(R.id.button_create_draft);
addPlayer.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Player player = new Player(evAddPlayer.getText().toString());
players.add(player);
adapter.notifyDataSetChanged();
InputMethodManager imm = (InputMethodManager) getActivity()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getView().getWindowToken(), 0);
}
});
createDraft.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (adapter != null && players != null) {
createdraft(players.size());
} else {
Toast.makeText(getActivity(),
"Add minimal 3 players to start the draft.",
Toast.LENGTH_LONG).show();
}
}
});
return rootView;
}
public void showDialog(){
DialogFragment newFragment = new MyAlertDialogFragment().newInstance(R.string.recreate_draft);
newFragment.show(getFragmentManager(), "dialog");
}
public void doPositiveClick(){
viewPager.setCurrentItem(1);
}
public void doNegativeClick(){
}
public int getTotalPlayers() {
return players.size();
}
public List<Player> getPlayersNames() {
return players;
}
public void initialiseEditAndText(View rootView) {
evAddPlayer = (EditText) rootView.findViewById(R.id.et_player_name);
}
public void createdraft(int totalplayers) {
if (totalplayers >= 3 && totalplayers <= 16) {
showDialog();
} else {
Toast.makeText(getActivity(),
"Minimum of 3 and maximum of 16 players.",
Toast.LENGTH_LONG).show();
}
}
public class MyAlertDialogFragment extends DialogFragment{
public MyAlertDialogFragment newInstance(int title){
MyAlertDialogFragment frag = new MyAlertDialogFragment();
Bundle args = new Bundle();
args.putInt("title", title);
frag.setArguments(args);
return frag;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
int title = getArguments().getInt("title");
return new AlertDialog.Builder(getActivity())
.setIcon(R.drawable.abc_ic_search)
.setTitle(title)
.setPositiveButton("R.string.alert_dialog_ok",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
addPlayersfragmentTab.this.doPositiveClick();
}
}
)
.setNegativeButton("R.string.alert_dialog_cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
addPlayersfragmentTab.this.doNegativeClick();
}
}
)
.create();
}
}
}
EDIT:
pageadpter:
public fragmentPageAdapter(FragmentManager fm) {
super(fm);
// TODO Auto-generated constructor stub
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
// Top Rated fragment activity
return new addPlayersfragmentTab();
case 1:
// Games fragment activity
return new createRoundfragmentTab();
case 2:
// Movies fragment activity
return new scoreResultfragmentTab();
}
return null;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return 3;
}
}
edit 2:
I followed the passing of data to the activity, that did work, however if I wanted to pass the data from the activity(that got the data from the addPlayerTab) i am getting a null reference again, this time i think becuase the id is wrong. but my layoutfile dont use . So how will i find the fragment?
code:
the interface implementation of the addPlayerTab:
#Override
public void onButtonClickCreateRound(int position, List<Player> players) {
viewPager.setCurrentItem(position);
this.players = players;
GetPlayer();
}
code in addPlayerTab:
public interface GoToCreateRoundListener{
public void onButtonClickCreateRound(int position, List<Player> players);
}
public void onAttach(Activity activity){
super.onAttach(activity);
try{
goCreateRound = (GoToCreateRoundListener)activity;
}catch(ClassCastException e){
throw new ClassCastException(activity.toString()+" must implement GoToRoundListener");
}
}
public void createdraft(int totalplayers) {
if (totalplayers >= 3 && totalplayers <= 16) {
goCreateRound.onButtonClickCreateRound(1, players);
} else {
Toast.makeText(getActivity(),
"Minimum of 3 and maximum of 16 players.",
Toast.LENGTH_LONG).show();
}
}
this is the interface implementation for passing the data to the createroundtab:
#Override
public void GetPlayer() {
createRoundfragmentTab createRoundfragmentTab = (createRoundfragmentTab)getSupportFragmentManager().findFragmentById(R.layout.create_round);
createRoundfragmentTab.makeRandomFirstRound(players);
}
code in the createroundTab:
public interface GetPlayersFromAddPlayersListener{
public void GetPlayer();
}
public void onAttach(Activity activity){
super.onAttach(activity);
try{
getPlayers = (GetPlayersFromAddPlayersListener)activity;
}catch(ClassCastException e){
throw new ClassCastException(activity.toString()+" must implement GetPlayersFromAddPlayersListener");
}
}
I've already shared my point on Fragment instantiation above so I'll just quote myself again.
That whole if (savedInstance == null) block is not required because Fragment instantiation is the job of your PagerAdapter. The ViewPager will call PagerAdapter#getItem() when it sees fit to.
Although, it's fairly obvious that the NullPointerException is caused by an uninitialized ViewPager reference inside your addPlayersfragmentTab, the whole approach of either passing the view pager to the fragment at creation or the fragment accessing it through a getter is wrong.
The reason is that a fragment is a self-contained reusable implementation of a part of your UI and hence it should not couple itself with the activity hosting it. Once you couple it with your view pager, you can never host this fragment in any other normal activity again. In short, the fragment does not remain reusable anymore.
So, then how is a fragment supposed to communicate with its host activity? Well, using Callback Interfaces. Here is a short tutorial from the official Android developers site: Communicating with Other Fragments but it works the same for requesting the activity to do anything on behalf of the fragment.
In your case, you would inform the main activity that the user pressed OK at the alert dialog and the activity would respond to that by moving to the next tab using the view pager.
Usually when you want to catch hold of a Fragment again, you either use findFragmentById() or its custom tag with findFragmentByTag(). But, the whole ViewPager and its PagerAdapter doesn't expose these properties to us.
So, to enable the fragment look-ups, you need to hold references to them inside your PagerAdapter. Something along the lines of the following.
Map<String, Fragment> mFragments = new HashMap<>(3);
...
#Override
public Fragment getItem(int index) {
...
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
// super calls getItem() if fragment is not already instantiated
Fragment fragment = (Fragment) super.instantiateItem(container, position);
mFragments.put(fragment.getClass().getSimpleName(), fragment);
return fragment;
}
public Fragment getFragment(String name) {
return mFragments.get(name);
}
#Override
public int getCount() {
return 3;
}
With the above changes, your GetPlayer() implementation would now become
#Override
public void GetPlayer() {
createRoundfragmentTab createRoundfragmentTab = (createRoundfragmentTab)
((fragmentPageAdapter) mAdapter).getFragment("createRoundfragmentTab");
createRoundfragmentTab.makeRandomFirstRound(players);
}
To understand this approach in more details please do read ViewPager and fragments — what's the right way to store fragment's state?.
As an aside, please also take a look at Java naming conventions recommended by Oracle. Long story short, you need to start your class names with an upper case letter and do the opposite with your method names. Following these conventions would make your code easier to read and thus more understandable. Currently, all your class names appear as variable names to seasoned Java developers.
You didn't initialize viewPager field of your fragment (addPlayersfragmentTab.viewPager). That's why you got NullPointerException.
You can do getViewPager() method in activity and after that call it from fragment, i.e. ((CreateDraft) getActivity()).getViewPager().setCurrentItem(1)
Related
public class MainLibraryFragment extends Fragment implements PlaylistChangedInterface {
AudioItemSelectedListener mCallback;
// Container Activity must implement this interface
public interface AudioItemSelectedListener {
// public void onAudioItemSelected(int position);
public void onAudioItemSelected(Audio audioSelected);
}
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private Context context;
private ArrayList<Audio> listToDisplay;
private String TAG = "MainLibraryFragment";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
context = getActivity();
MemoryManagement memoryManagement = new MemoryManagement(context);
listToDisplay = memoryManagement.loadAudioList(MemoryManagement.MAIN_LIST_KEY);
try {
//Expression is meaningless but tests if null.
//TODO, should catch this in loadAudioList.
if (listToDisplay.isEmpty()){}
} catch (NullPointerException e){
defaultList();
}
View rootView = inflater.inflate(R.layout.fragment_top_rated, container, false);
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.my_recycler_view);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerView.setHasFixedSize(true);
// use a linear layout manager
mLayoutManager = new LinearLayoutManager(getContext());
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.addItemDecoration(new DividerItemDecoration(getContext(), LinearLayoutCompat.VERTICAL));
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.addOnItemTouchListener(new CustomTouchListener(context, new onItemClickListener() {
#Override
public void onClick(View view, int index) {
mCallback.onAudioItemSelected(listToDisplay.get(index));
}
}));
mAdapter = new SongListAdapter2(listToDisplay, context);
mRecyclerView.setAdapter(mAdapter);
return rootView;
}
private void defaultList(){
listToDisplay = new ArrayList<>();
listToDisplay.add(new Audio("You need to add some songs!"));
}
#Override
public void playListChanged(ArrayList<Audio> arrayList) {
Log.d(TAG, "updateTop: in.");
if (!arrayList.isEmpty()) {
listToDisplay = arrayList;
}else {
defaultList();
}
updateListView();
Log.d(TAG, "updateTop: out.");
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
context = getContext();
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (AudioItemSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement AudioItemSelectedListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mCallback = null;
}
private void updateListView(){
Log.d(TAG, "updateTop: in.");
((SongListAdapter2) mAdapter).refreshList(listToDisplay);
Log.d(TAG, "updateTop: out.");
}
}
I have added refreshList():
public void refreshList(ArrayList<Audio> list) {
this.list = list;
notifyDataSetChanged();
}
And then the error message:
--------- beginning of crash
06-09 15:14:24.275 9114-9114/com.bteq.audia E/AndroidRuntime: FATAL
EXCEPTION: main
Process: com.bteq.audia, PID: 9114
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.bteq.audia.SongListAdapter2.refreshList(java.util.ArrayList)' on a null object reference
at com.bteq.audia.MainLibraryFragment.updateListView(MainLibraryFragment.java:128)
at com.bteq.audia.MainLibraryFragment.playListChanged(MainLibraryFragment.java:100)
at com.bteq.audia.MainActivity.onDialogPositiveClick(MainActivity.java:195)
at com.bteq.audia.AddSongDialog$2.onClick(AddSongDialog.java:47)
at android.support.v7.app.AlertController$ButtonHandler.handleMessage(AlertController.java:166)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6753)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:482)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
06-09 15:14:24.281 9114-9114/com.bteq.audia W/OPDiagnose:
getService:OPDiagnoseService NULL
The MainActivity that contains the Pager. I tried to remove as much code as I could that wasn't relevant.
public class MainActivity extends AppCompatActivity implements MainLibraryFragment.AudioItemSelectedListener, AddSongDialog.NoticeDialogListener, ShowQueueDialog.ShouldClearAll {
private MemoryManagement memoryManagement;
private ViewPager viewPager;
private com.bteq.audia.PagerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
memoryManagement = new MemoryManagement(this);
setContentView(R.layout.activity_main);
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(myToolbar);
initialiseViews();
}
public void initialiseViews() {
//Fills the titles of all the tabs.
String[] tabTitles = getTabTitles();
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabLayout);
for (int i = 0; i < tabTitles.length; i++) {
tabLayout.addTab(tabLayout.newTab().setText(tabTitles[i]));
}
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
//Sets up the ViewPager and creates the functionality to make them changeable.
viewPager = (ViewPager) findViewById(R.id.pager);
adapter = new PagerAdapter(getSupportFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
setupBottomView();
}
//method used as main control to the service from this activity.
private void audioActionDo(String audioAction) {
Intent intent = new Intent("audio_control_intent");
intent.putExtra("button_pressed", audioAction);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
/*
Method tells the activity which item in the shown playlist has been selected. This should then cause that item to play if possible.
//TODO, fill in body of method.
*/
#Override
public void onAudioItemSelected(Audio audio) {
songSelected(audio);
Log.d("MainActivity", "onAudioItemSelected: At end");
}
#Override
public void onDialogPositiveClick(String titleString, String artistString, String albumString, String genreString) {
Audio audioToAdd = new Audio(genreString, titleString, albumString, artistString);
memoryManagement.addAudioToList(audioToAdd, MemoryManagement.MAIN_LIST_KEY);
Fragment fragment = adapter.getItem(0);
PlaylistChangedInterface playlistChangedInterface = (PlaylistChangedInterface) fragment;
playlistChangedInterface.playListChanged(memoryManagement.loadAudioList(MemoryManagement.MAIN_LIST_KEY));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_top, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_settings:
//TODO, take the user to the app settings page.
// User chose the "Settings" item, show the app settings UI...
return true;
case R.id.action_favorite:
//TODO, make this favourite the current Audio.
// User chose the "Favorite" action, mark the current item
// as a favorite...
memoryManagement.clearPrefsValue(MemoryManagement.MAIN_LIST_KEY);
return true;
case R.id.action_add_new_song:
showAddSongDialog();
return true;
case R.id.action_show_queue:
showQueueDialog();
return true;
case R.id.action_add_from_internal:
return true;
default:
// If we got here, the user's action was not recognized.
// Invoke the superclass to handle it.
return super.onOptionsItemSelected(item);
}
}
public void showAddSongDialog() {
DialogFragment newFragment = new AddSongDialog();
newFragment.show(getSupportFragmentManager(), "missiles");
}
public void showQueueDialog() {
DialogFragment newFragment = new ShowQueueDialog();
newFragment.show(getSupportFragmentManager(), "showQueue");
}
//Should immediately play a song then be able to continue with the queued audio.
public void songSelected(Audio audioToAdd) {
}
//clears the entire queue but completes playback of current audio.
private void clearCurrentQueue() {
memoryManagement.clearPrefsValue(MemoryManagement.QUEUE_KEY);
}
// Utility method. Returns the locale titles for the tabs in the viewpager.
private String[] getTabTitles() {
return getResources().getStringArray(R.array.tab_titles);
}
#Override
public void clearAllPressed() {
clearCurrentQueue();
}
private void setupBottomView() {
ImageView playButton = (ImageView) findViewById(R.id.bottom_play);
ImageView replayButton = (ImageView) findViewById(R.id.bottom_replay);
ImageView skipBackButton = (ImageView) findViewById(R.id.bottom_skip_back);
ImageView skipForwardButton = (ImageView) findViewById(R.id.bottom_skip_next);
ImageView shuffleButton = (ImageView) findViewById(R.id.bottom_shuffle);
playButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// playAudio(storageUtility2.loadAudioIndex());
audioActionDo(getResources().getString(R.string.broadcast_action_playpause));
}
});
replayButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
audioActionDo(getResources().getString(R.string.broadcast_action_loop));
}
});
skipBackButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
audioActionDo(getResources().getString(R.string.broadcast_action_skip_back));
}
});
skipForwardButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
audioActionDo(getResources().getString(R.string.broadcast_action_skip_forward));
}
});
shuffleButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
audioActionDo(getResources().getString(R.string.broadcast_action_shuffle));
}
});
}
}
I get a null pointer exception whenever the method updateListView is called. The fragment initially displays with no problem, but when a new entry is added to the ArrayList and the updateListView is called - it stops. The log shows that mAdapter is null. I don't know enough about android yet to understand why mAdapter becomes null after it is used before.
Sorry for large amount of code but I'm completely stumped. Thanks.
In my opinion this is because your variable mAdapter is declared as of type RecyclerView.Adapter which is an interface which does not declare your method, refreshList(). Therefore if you intend to use the type RecyclerView.Adapter, only the methods declared in the interface could be called by using the reference variable. If you intend to call methods implemented by yourself other than whats overridden from the interface, the reference type SongListAdapter2 has to be used.
Simple fix is to change the RecyclerView.Adapter to SongListAdapter2 at the declaration of the mAdapter.
Ps. Check android docs to see the methods declared by the RecyclerView.Adapter.
It depends on how you are accessing the adapter in the RecyclerView. If you look at this line Fragment fragment = adapter.getItem(0), you are trying to access the first fragment in your ViewPager's adapter. getItem usually won't get called again after the ViewPager has layout its fragments which means your call to access the RecyclerView's adapter in the first fragment in the ViewPager will be pointing to a null adapter even though the fragment might exist (and you might even be calling a wrong fragment). Use this Fragment fragment = getChildFragmentManager().getFragments().get(0) to access the right fragment which will ensure the RecyclerView adapter won't be null. Change getChildFragmentManager() to getFragmentManager() if your ViewPager is in an Activity.
I am scracthing my head for past 1 day but unable to find the solution.
In mine application there are two tabs under the toolbar
First tab is USER-TAB
the second one is ADMIN-TAB
In both the tabs there are the listView. When a ListItem on the USER-TAB is clicked a dialog appears and user take some action.
Now after this when the ADMIN-TAB is Selected the Admin should get refreshed with new sets of data. But It's not. On selecting the ADMIN-TAB the onResume() method and everyting is getting called but it is not able to update the list.
I wont be able to write the Whole code, I am giving some snippet.
Basically I have taken the code from this link
https://github.com/codepath/android_guides/wiki/Sliding-Tabs-with-PagerSlidingTabStrip
In My Main Activity I have written the OpPageChangeListener.
public class MaterialTab extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.material_main_sample);
// Get the ViewPager and set it's PagerAdapter so that it can display items
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setAdapter(new SampleFragmentPagerAdapter(getSupportFragmentManager()));
// Give the PagerSlidingTabStrip the ViewPager
PagerSlidingTabStrip tabsStrip = (PagerSlidingTabStrip) findViewById(R.id.tabs);
// Attach the view pager to the tab strip
tabsStrip.setViewPager(viewPager);
tabsStrip.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
if(position == 0){
MileUserFragment userFragment = new MileUserFragment();
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.detach(userFragment);
ft.attach(userFragment);
ft.commit();
} if(position == 1){
MileAdminFragment adminFragment = new MileAdminFragment();
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.detach(adminFragment);
ft.attach(adminFragment);
ft.commit();
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
}
OnPageSelected You can see I am detaching and reattaching the fragment.Everything is working fine. Both Fragments OnResume() are getting called but the List is not getting changed. I don't undrstand why
For additional assistance i am adding snippet one Fragment. Hope this will give some Idea where i might be going wrong
public class MileUserFragment extends Fragment {
#Override
public void onResume() {
super.onResume();
new GetAdminDbTask().execute();
if(!internetUtil.isConnectedToInternet(getActivity())){
mSwipeRefreshLayout.setRefreshing(false);
mSwipeRefreshLayout.setEnabled(false);
}
}
public class GetAdminDbTask extends AsyncTask<Admin, Void, String> {
#Override
protected String doInBackground(Admin... parmas) {
_adminList = shipmentDbHandler.getAllAdmin();
return "";
}
#Override
protected void onPostExecute(String str) {
mAdminAdapter = new AdminAdapter(getActivity(), _adminList);
adminListView.setAdapter(mAdminAdapter);
mAdminAdapter.notifyDataSetChanged();
// Set the refresh Listener to false after the list has been loaded with new set of data
if (mSwipeRefreshLayout.isRefreshing()) {
mSwipeRefreshLayout.setRefreshing(false);
}
if(_adminList.size() > 0 ){
mAdminAdapter = new AdminAdapter(getActivity(), _adminList);
adminListView.setAdapter(mAdminAdapter);
mAdminAdapter.notifyDataSetChanged();
}
}
}
}
public class SampleFragmentPagerAdapter extends FragmentPagerAdapter {
final int PAGE_COUNT = 2;
private String tabTitles[] = new String[] { "Tab1", "Tab2" };
private FragmentManager fragmentManager;
public SampleFragmentPagerAdapter(FragmentManager fm) {
super(fm);
this.fragmentManager = fm;
}
#Override
public int getCount() {
return PAGE_COUNT;
}
#Override
public Fragment getItem(int position) {
FragmentTransaction ft = null;
if(position == 0){
MileUserFragment userFragment = new MileUserFragment();
return userFragment;
}
if(position == 1){
MileAdminFragment adminFragment = new MileAdminFragment();
return archiveFragment;
}
}
#Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
return tabTitles[position];
}
}
Haah.. Finally i got an answer to after an heck of losing almost 1 and half days. It might be not completely good answer but atleast it is one of the closest I got.
First of all MainActivity.java looks like:
tabs.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
int scrollPosition = 0;
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(position == 0){
scrollPosition = 0;
}
if(position == 1){
scrollPosition = 1;
}
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
if(state == pager.SCROLL_STATE_IDLE){
if(scrollPosition == 0 && application.isActiveAction()){
viewPagerAdapter.notifyDataSetChanged();
application.setActiveAction(false);
}
if(scrollPosition == 1 && application.isArchiveAction()){
viewPagerAdapter.notifyDataSetChanged();
application.setArchiveAction(false);
}
}
}
});
Now what I have done here is I have set OnPageChangeListener and in this I am keeping track of the position whenever the tabs are changing. For my needs what i have done is i have created two boolean variables and setting it when any content on those tab are changing in Application scope. Now when the contents on one tab has been changed or some Action are done I am calling
viewPagerAdapter.notifyDataSetChanged() // Now this is the real gem
after invoking this it will make a call to the ViewPagerAdapter function
#Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE; // This will get invoke as soon as you call notifyDataSetChanged on viewPagerAdapter.
}
Also the Point is your ViewPagerAdapter should extend FragmentStatePageAdapter. Now the Point is
PagerAdapter.POSITION_NONE
will not cache the fragment and reload a new fragment for that tab position.
Basic idea is we should not make or retutn PagerAdapter.POSITION_NONE everytime on sliding of tab since it destroys the cached element and reload the fragment which affects UI performance.
So finally the basic thing is always check that whether on calling viewPagerAdapter.notifyDataSetChanged() the function getItemPosition() should also gets invoked. Hope it will help somebody. For better perfomance you can make changes according to your requirement.
I got the needed breakthrough and understanding from this post : #Louth Answer
Remove Fragment Page from ViewPager in Android
Just put
viewPager.setCurrentItem(tab.getPosition());
in your onTabSelected method like:
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
I have a main activity which contains the action bar with 3 menu buttons in it.
I then have a fragment within this main activity which has a list.
I would like to be able to refresh the list in the fragment from the main activity, when one of the menu buttons is clicked, or preferably just removed all the rows from the list.
Any help is appreciated.
Thanks.
public class Favourite extends SherlockFragmentActivity {
ActionBar actionBar;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.favourite);
actionBar = getSupportActionBar();
actionBar.setDisplayShowTitleEnabled(false);
BitmapDrawable bg = (BitmapDrawable)getResources().getDrawable(R.drawable.actionbar_bg);
bg.setTileModeX(TileMode.REPEAT);
getSupportActionBar().setBackgroundDrawable(bg);
getSupportActionBar().setIcon(R.drawable.favourite_title);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tabAll = actionBar.newTab();
ActionBar.Tab tabfavs = actionBar.newTab();
ActionBar.Tab tabhist = actionBar.newTab();
tabAll.setText("all");
tabfavs.setText("favs");
tabhist.setText("hist");
tabAll.setTabListener(new MyTabListener());
tabfavs.setTabListener(new MyTabListener());
tabhist.setTabListener(new MyTabListener());
actionBar.addTab(tabAll);
actionBar.addTab(tabfavs);
actionBar.addTab(tabhist);
try{
}
catch(Exception e)
{
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.actionbar_itemlist_favourite, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.history:
break;
case R.id.favourite:
Intent favAct = new Intent(this, Favourite.class);
startActivity(favAct);
break;
case R.id.delete:
///I WANT TO BE ABLE TO REFRESH FRAGMENTLIST FROM HERE
}
return true;
}
}
class MyTabListener implements ActionBar.TabListener {
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if(tab.getPosition()==0)
{
FavouriteAllWords frag = new FavouriteAllWords();
ft.replace(android.R.id.content, frag);
}
else if(tab.getPosition()==1)
{
FavouriteFavWords frag = new FavouriteFavWords();
ft.replace(android.R.id.content, frag);
}
else if(tab.getPosition()==2)
{
FavouriteHistWords frag = new FavouriteHistWords();
ft.replace(android.R.id.content, frag);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
////////////////////MY LIST FRAGMENT CLASS
public class FavouriteAllWords extends ListFragment {
ArrayAdapter<String> adapter;
List<String> stringOfFavWords;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup group, Bundle saved)
{
adapter = new ArrayAdapter<String>(
inflater.getContext(), R.layout.row, stringOfFavWords);
setListAdapter(adapter);
return super.onCreateView(inflater, group, saved);
}
#Override
public void onActivityCreated (Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
}
}
You can easily achieve this using INTERFACE
MainActivity.java
public class MainActivity extends Activity {
public FragmentRefreshListener getFragmentRefreshListener() {
return fragmentRefreshListener;
}
public void setFragmentRefreshListener(FragmentRefreshListener fragmentRefreshListener) {
this.fragmentRefreshListener = fragmentRefreshListener;
}
private FragmentRefreshListener fragmentRefreshListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button b = (Button)findViewById(R.id.btnRefreshFragment);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(getFragmentRefreshListener()!=null){
getFragmentRefreshListener().onRefresh();
}
}
});
}
public interface FragmentRefreshListener{
void onRefresh();
}
}
MyFragment.java
public class MyFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = null; // some view
/// Your Code
((MainActivity)getActivity()).setFragmentRefreshListener(new MainActivity.FragmentRefreshListener() {
#Override
public void onRefresh() {
// Refresh Your Fragment
}
});
return v;
}
}
Just make your update/refresh method public and call it from your Activity.
OR
Use LocalBroadcastManager or EventBus to send event from your Activity, and by subscribing to this event in a Fragment - react to it and call refresh/update method.
Your activity can call methods in the fragment by acquiring a reference to the Fragment.
(1) Provide a tag when you add your fragment.
transaction.add(R.id.fragment_container, myFragment, "myfragmentTag");
(2) In your hosting activity you can find the fragment and have access to it's methods.
FragmentManager fm = getSupportFragmentManager();
myFragment f = (myFragment) fm.findFragmentByTag("myfragmentTag");
f.refreshAdapter()
(3) refreshAdapter() could now call adapter.notifyDataSetChanged().
This is one of the recommended ways to communicate up to a fragment.
The interface implementation is mainly for communicating back to the activity.
Biraj Zalavadia's answer is 100% right, you will call nay fragment methods from using interface....
this interface methods is running without error...
use this in MainActivity above oncreate
private FragmentRefreshListener fragmentRefreshListener;
public FragmentRefreshListener getFragmentRefreshListener() {
return fragmentRefreshListener;
}
public void setFragmentRefreshListener(
FragmentRefreshListener fragmentRefreshListener) {
this.fragmentRefreshListener = fragmentRefreshListener;
}
inside of Activity
private void refreshcall(String result2) {
// TODO Auto-generated method stub
if (getFragmentRefreshListener() != null) {
getFragmentRefreshListener().onRefresh(result2);
}
}
and put this in needed Fragment
private FragmentRefreshListener fragmentRefreshListener;
public FragmentRefreshListener getFragmentRefreshListener() {
return fragmentRefreshListener;
}
public void setFragmentRefreshListener(
FragmentRefreshListener fragmentRefreshListener) {
this.fragmentRefreshListener = fragmentRefreshListener;
}
Communicating with Other Fragments
http://developer.android.com/training/basics/fragments/communicating.html
This can also be used to communicate between an Activity and a Fragment.
When you click on ActionBar any Button then call interface to refresh the ListFragment. Because in java interface is used for inter-communication.
In Kotlin
Get the list of Support Fragment from the activity and check Instance and then call fragment function
val fragments = supportFragmentManager.fragments
for (fragment in fragments) {
if (fragment is HomeCategoriesFragment) {
fragment.updateAdapter() // Define function in Fragment
}
}
Hello I'm developing an android app using 3 Fragments (Fragment A, B, C) inside viewpager and tabs, the viewpager works fine. The fragment A contains a List View, when the user clicks a item, the app open a Fragment Dialog with information about the item selected. This dialog has a button called "Add to favorites". Now I want to do this when user press button:
close the fragment dialog
show the fragment B inside the view pager
send the information from dialog fragment to fragment B
How can I do this?
This is part of my code:
* MainFragmentActivity * (This works fine)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tube);
// Set up the action bar.
final ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// 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.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
// When swiping between different sections, select the corresponding
// tab. We can also use ActionBar.Tab#select() to do this if we have
// a reference to the Tab.
mViewPager
.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
actionBar.addTab(actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this));
}
}
#Override
public void onTabSelected(ActionBar.Tab tab,
FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in
// the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab,
FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabReselected(ActionBar.Tab tab,
FragmentTransaction fragmentTransaction) {
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
FragmentA a = new FragmentA();
Bundle args1 = new Bundle();
args1.putInt(FragmentA.ARG_SECTION_NAME , position + 1);
a.setArguments(args1);
return a;
case 1:
FragmentB b= new FragmentB();
Bundle args2 = new Bundle();
args2.putInt(FragmentB.ARG_SECTION_NAME , position + 2);
b.setArguments(args2);
return b;
case 2:
FragmentC c= new FragmentC();
Bundle args3 = new Bundle();
args3.putInt(FragmentC.ARG_SECTION_NAME , position + 3);
c.setArguments(args3);
return c;
default:
return null;
}
}
This is the Fragment Dialog
* FragmentDialogView *
public class FragmentDialogView extends DialogFragment implements OnClickListener {
private static final int REAUTH_ACTIVITY_CODE = 0;
private String videoId;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Bundle mArgs = getArguments();
View view = (View) inflater.inflate(R.layout.fragment_dialog_view, container, false);
//Buttons
Button button = (Button) view.findViewById(R.id.button_one);
button.setOnClickListener(this);
buttonDownload.setOnClickListener(this);
return view;
}
#Override
public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REAUTH_ACTIVITY_CODE) {
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_one:
//Here it should show the fragment B inside the viewpager
break;
default:
break;
}
}
}
To dismiss the Dialog include the following in your DialogFragment's class
private Dialog dialog;
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
dialog = new Dialog(getActivity());
return dialog;
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_one:
dismiss();
break;
default:
break;
}
}
And create a interface
Create the following Communicator.java
public interface Communicator {
public void respond(int i);
}
Implement this Communicator in your MainAcitvity
And create a instance of this Communicator in your fragment like this
public class FragmentDialogView extends DialogFragment implements OnClickListener {
private Communicator com;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
com = (Communicator) getActivity();
btn.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn:
com.respond(1);
break;
}
}
Whenever you click that button it sends the int to the method which is residing inside the MainActivity
which will look like following
#Override
public void respond(int i) {
// Receive a bundle here
// and pass the corresponding information to the FragmentB
// here i'm receving an int and pass it to the FragmentB as a String
FragmentManager fm = getFragmentManager();
FragmentB fragment = (FragmentB) fm.findFragmentByTag("FragmentB");
fragment.fromMainActivity(""+i);
// If the above the one doesn't work keep the instance as Static and then try
viewPager.invalidate();
pagerAdapter.notifyDataSetChanged();
viewPager.setCurrentItem(1, true);
// Inside the setCuttentItem() method 0 first tab
// 1 second tab
// 2 third tab and so on
}
Here I'm receiving an int . You can use a bundle to pass the corresponding information. This will change the viewPager to show the next tab as well
and keep any simple method insdie the FragmentB like the following
public void fromMainActivity(String sample) {
Toast.makeText(getActivity(), sample, duration).show();
}
I hope this would help :) Happy coding
1.Try this : getDialog().dismiss();
2.As I understood correctly, create a method like this in your fragment ,
public static FirstFragment newInstance(String text){
FirstFragment f= new FirstFragment();
return f;
}
Call it in your button onClick() such as FirstFragment.newInstance("Fragment, Instance 1");
3.Create Interface with the method in your DialogFragment can call to pass any data you want back to Fragment that created said DialogFragment. Also set your Fragment as target such as myFragmentDialog.setTargetFragment(this, 0). Then in dialog, get your target fragment object with getTargetFragment() and cast to interface you created. Now you can pass the data using ((MyInterface)getTargetFragment()).methodToPassData(data).
For more info : link
I'm using a viewpager to swipe between fragments and would like the back button to navigate to the previously viewed fragment rather than ending the activity. Sorry if this is a duplicate of this question however I didn't find the answer very helpful. Obviously onBackPressed needs to be overridden, but I don't know how to get and display the correct fragment. I assume that I should use the fragmentmanager's backstack, but getSupportFragmentManager().getBackStackEntryCount() always returns 0. Do I need to manually add fragments to the backstack using FragmentTransaction.addToBackStack()? If so, where would I add this in my adapter?
Here is the code for my activity,
public class PagerActivity extends FragmentActivity {
ArrayList<Sale> sales;
MyAdapter mAdapter;
ViewPager mPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent it = getIntent();
this.sales = (ArrayList<Sale>) it.getExtras().get("sales");
int position = it.getExtras().getInt("position");
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
setContentView(R.layout.fragment_pager);
mAdapter = new MyAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mPager.setCurrentItem(position);
}
public class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
#Override
public int getCount() {
return sales.size();
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
#Override
public Fragment getItem(int position) {
SalesThumbFragment frag = new SalesThumbFragment();
return frag.newInstance(sales.get(position));
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.sales_controller, menu);
return true;
}
#Override
public void onBackPressed() {
if(getSupportFragmentManager().getBackStackEntryCount() != 0) {
getSupportFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
}
In new design support library, i use this
I have same issue and i follow this step
In the main activity where there are 3 fragment in viewpager i create stack
and push and pop data.
//private Stack<Integer> stackkk; ==> As i get edit suggestion
private Stack<Integer> stackkk = new Stack<>(); // Edited
private ViewPager mPager;
private int tabPosition = 0;
mTabLayout.setupWithViewPager(mPager);
mPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout));
mTabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
tabPosition = tab.getPosition();
mPager.setCurrentItem(tab.getPosition());
if (stackkk.empty())
stackkk.push(0);
if (stackkk.contains(tabPosition)) {
stackkk.remove(stackkk.indexOf(tabPosition));
stackkk.push(tabPosition);
} else {
stackkk.push(tabPosition);
}
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
tabPositionUnselected = tab.getPosition();
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
and in the onBackPressed in activity,
#Override
public void onBackPressed() {
if (stackkk.size() > 1) {
stackkk.pop();
mPager.setCurrentItem(stackkk.lastElement());
} else {
}
}
Use this code in Fragment Activity class. Don't forget to add return true;
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
mViewPager.setCurrentItem(viewPageSelected - 1);
return true;
}
return super.onKeyDown(keyCode, event);
}
I had a similar problem, this is how I solved it. I think you can adapt the code to your problem, if I understood what you problem is. I had a ViewPager with 6 fragments and wanted to keep track of the page history and to be able to use the back button to navigate backwards in the history. I create a java.util.Stack<Integer> object, add fragment numbers to it (except when you use the back button, see below), and override onBackPressed() to make it pop the last viewed fragment instead of using the back stack, when my history stack is not empty.
You want to avoid pushing elements on the Stack when you press the back button, otherwise you will get stuck between two fragments if you keep using the back button, instead of eventually exiting.
My code:
MyAdapter mAdapter;
ViewPager mPager;
Stack<Integer> pageHistory;
int currentPage;
boolean saveToHistory;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAdapter = new MyAdapter(getSupportFragmentManager());
mPager = (ViewPager)findViewById(R.id.container);
mPager.setAdapter(mAdapter);
mPager.setOffscreenPageLimit(5);
pageHistory = new Stack<Integer>();
mPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int arg0) {
if(saveToHistory)
pageHistory.push(Integer.valueOf(currentPage));
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
saveToHistory = true;
}
#Override
public void onBackPressed() {
if(pageHistory.empty())
super.onBackPressed();
else {
saveToHistory = false;
mPager.setCurrentItem(pageHistory.pop().intValue());
saveToHistory = true;
}
};
If you use a field to keep track of the index of the previous page using mPager.getCurrentItem() after each time the user navigates to a new fragment, then in the onBackPressed() method, you should be able to call mPager.setCurrentItem(previousPage)
Or, if the user can only page in order, then you don't need a field at all, and you could just do mPager.setCurrentItem(mPager.getCurrentItem()-1)
I've made custom ViewPager and implement stack functionality in it.
public class CustomViewPager extends ViewPager {
private Stack<Integer> stack = new Stack<>();
#Override
public void setCurrentItem(int item, boolean smoothScroll) {
stack.push(getCurrentItem());
super.setCurrentItem(item, smoothScroll);
}
public int popFromBackStack(boolean smoothScroll) {
if (stack.size()>0) {
super.setCurrentItem(stack.pop(), smoothScroll);
return getCurrentItem();
} else return -1;
}