So.. I have a Fragment containing ViewPager with two more Fragments in it which serves as search tabs. That means 3 different Java classes, 1 for container, the 2 are for the contents.
The behavior I wanted was : When user presses the search button, types something, and submit the search in the base Activity, the app overrides onQueryTextSubmit to start the pager Fragment and getting the query there to directly search in the first Fragment in the pager. When user swipe to the next Fragment, the SearchView persists, along with its query and also perform search on the second Fragment using said query.
The behavior I am getting is.. When user swipes to the next Fragment, the searchmenu collapses and the keyword is gone..
This is how I code the SearchVenu in the Activity
#Override
public boolean onQueryTextSubmit(String query) {
searchFragment = new SearchFragment();
Bundle searchBundle = new Bundle();
keyword = searchView.getQuery().toString();
searchBundle.putString("searchQuery", keyword);
searchFragment.setArguments(searchBundle);
backstackCount = manager.getBackStackEntryCount();
if (backstackCount >= 2) {
manager.executePendingTransactions();
if (manager.getBackStackEntryAt(backstackCount - 1).getName().equals("searchTag")) {
} else {
replaceFragment(searchFragment, searchTag);
}
} else {
replaceFragment(searchFragment, searchTag);
}
return false;
The adapter :
mAdapter = new MyPagerAdapter(getChildFragmentManager(), bundle);
...
private class MyPagerAdapter extends FragmentStatePagerAdapter {
private Bundle fragmentBundle;
public MyPagerAdapter(FragmentManager fm, Bundle data) {
super(fm);
fragmentBundle = data;
}
#Override
public Fragment getItem(int pos) {
/*Fragment f = new Fragment();
f.setArguments(this.fragmentBundle);
return f;*/
switch(pos) {
case 0: return SearchFriendFragment.newInstance(fragmentBundle);
case 1: return SearchShopFragment.newInstance(fragmentBundle);
default: return SearchFriendFragment.newInstance(fragmentBundle);
}
}
#Override
public CharSequence getPageTitle(int position) {
return CONTENT[position % CONTENT.length];
}
#Override
public int getCount() {
//return 3;
return CONTENT.length;
}
}
This is how I initialize the search in one of the Fragments
#Override
public void onPrepareOptionsMenu(Menu menu) {
menu.clear();
super.onPrepareOptionsMenu(menu);
getActivity().getMenuInflater().inflate(R.menu.menu_search, menu);
searchViewBtn = menu.findItem(R.id.menu_search);
searchView = (SearchView) MenuItemCompat.getActionView(searchViewBtn);
I am well aware by doing menu.clear() will keep refreshing the menu on switching Fragment.. But I don't know what to do to get the correct behavior..
Update menu_search.xml
<item
android:id="#+id/menu_search"
android:orderInCategory="200"
android:title="Search"
android:icon="#drawable/iconcariheader"
app:showAsAction="ifRoom"
app:actionViewClass="android.support.v7.widget.SearchView"></item>
use my suggestion like this
public boolean onOptionsItemSelected(MenuItem item)
{
switch(item.getItemId())
{
case R.id.menu_search:
searchView = (SearchView) item.getActionView();
searchView.setOnQueryTextListener
(new SearchView.OnQueryTextListener()
{
#Override
public boolean onQueryTextSubmit(String query) {
// call your search function
return true;
}
#Override
public boolean onQueryTextChange(String newText) {
// call your search function
return true;
}
});
break;
}
return super.onOptionsItemSelected(item);
}
Hope this will help and let me know for further.
Related
My fragment is not refreshing when I swipe back, so I want to know how I can refresh it when I swipe it back. I have seen many different answers online, but I don't why they don't work in my situation. It would be highly appreciated if someone could help me out, thanks.
public class MainActivity extends AppCompatActivity {
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
}
#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_main, 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
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
Profile tab1 = new Profile();
return tab1;
case 1:
Puzzles tab2 = new Puzzles();
return tab2;
default:
return null;
}
}
#Override
public int getCount() {
// Show 3 total pages.
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Profile";
case 1:
return "Puzzles";
}
return null;
}
}
}
I have tried setOffscreenPageLimit(0), detach attach fragment in onTabSelected, using FragmentStatePagerAdapter, notifyDataSetChanged(), and even
public int getItemPosition(Object object) {
return POSITION_NONE;
}
this doesn't work too. So I hope someone could help.
If you want to refresh the data in a particular Fragment, you have to do 2 things,
Store the updated data into Activity
Show the updated data in onResume() in that particular Fragment
If you want your data to be saved even after killing the app, store it in SharedPreference. Hope it helps!
On your fragment class add this.
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
//Try adapter.notifyDataSetChanged or something like passing the new(updated) data to adapter from here.
}
}
Hope it helps.
I have many fragments they're shown in 2 tab layouts using FragmentStatePagerAdapter in each fragment there is a Recycler view and I want to use a search bar in the app bar to filter results.
First I did this using the onQueryTextChange listener in the onCreateOptionsMenu and it worked fine with a couple fragments but when I added the implementation to the other fragments (just ctrl+c and ctrl+v) it stopped working, no results even on fragments that used to work i then read here that it was better to stick the onQueryTextChange listener in onPrepareOptionsMenu in an attempt to avoid an issue with invalidateOptionsMenu but i decided to give that a try which also worked and then when i added the methods to all my other fragments yet again it fails but it does work on a handful of fragments, oddly these happen to be all attached to the same parent fragment but the code for the 4 parent fragments, and for calling them is identical.
A different way around this I've read is creating an interface and using that from my main activity by getting a reference to the current fragment but then id have to get the currently showing fragment from my viewpager which i dont know is possible can anyone weigh in on this for me,
Many thanks
And thanks for the great edit lol
EDIT
Tried the interface approach to no avail although I'm still a beginner i do need to find the attached fragment and with a fragmentstateviewpager its just not possible without using hacks there must be some reason why it works in some and not in others and sometimes not at all
Edit 2
So im still fiddling with this and ive had almost no replies so lets flesh this out a little so i was adding the menu layout in the main activity like this
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.dashboard, menu);
SearchView searchView =
(SearchView)menu.findItem(R.id.action_search).getActionView();
SearchManager searchManager = (SearchManager)
getSystemService(SEARCH_SERVICE);
searchView.setSearchableInfo(searchManager
.getSearchableInfo(getComponentName()));
return true;
}
and then adding a listener on to it from the fragment in onPrepareOptionsMenu like this
#Override
public void onPrepareOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
//in this instance we wont as it will create a duplicate
SearchView searchView = (SearchView)
menu.findItem(R.id.action_search).getActionView();
searchView.setOnQueryTextListener(null);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener(){
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
showResults(newText);
return false;
}
});
super.onPrepareOptionsMenu(menu);
}
and i have called setHasOptionsMenu(true) in onCreateView of the fragment, this works perfectly but i have about 20 fragments to cycle through and when I add this to the other fragments it fails it either does nothing or makes the view blank or in rare occasions works, but that for me says my code is okay and maybe its a lifecycle thing, ive tried calling it from the onCreateOptionsMenu of the fragments and achieved the same results, and ive tried not calling anything from the MainActivity in onCreateOptions except inflating the menu and allow the fragments to call the search activity using
SearchView searchView = (SearchView)menu.findItem
(R.id.action_search).getActionView();
SearchManager searchManager = (SearchManager)
getActivity().getSystemService(getActivity().SEARCH_SERVICE);
searchView.setSearchableInfo(searchManager.getSearchableInfo
(getActivity().getComponentName()));
which again works up to around 8 fragments but my 20 or so just causes it to fall on its sword, is there something im not doing that could help
Edit 3
Okay so by adding some, checking it, adding some more, checking it, it seems to be a problem with my parent fragments so I have main activity 4 fragments that each hold a fragment state pager that each holds 7 or so fragments if I add the methods for the query listener to the first 7 or so fragments in the first parent fragment they all work beautifully, if I then add the methods to the next set of 7 or so fragments in the second parent only the second parents child fragments work, if I then quit my app and open it again only the first parents fragments work, will continue investigating any help appreciated I'll post the code for my parent fragments here soon.
EDIT 4
Just going to add the code i use for the parent fragments and the fragmentstatepager from my main activity
so from my Main activity i set the fragmentstatepager like this
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new
ViewPagerAdapter(getSupportFragmentManager());
adapter.addFrag(new sentenceMakers(), "QUICKS");
adapter.addFrag(new tabFragOne(), "NOUNS");
adapter.addFrag(new tabFragTwo(), "VERBS");
adapter.addFrag(new tabFragThree(), "OBJECTS");
viewPager.setAdapter(adapter);
}
class ViewPagerAdapter extends FragmentStatePagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
//do nothing here! no call to super.restoreState(arg0, arg1);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFrag(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
and my parent fragments look like this
public class sentenceMakers extends Fragment{
public ImageView imageView;
private ViewPager viewPager;
public static TabLayout tabLayout;
public sentenceMakers() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate
(R.layout.tab_frag_one, container, false);
// Inflate the layout for this fragment
//setRetainInstance(true);
viewPager = (ViewPager) rootView.findViewById(R.id.viewpager);
setupViewPager(viewPager);
tabLayout = (TabLayout) rootView.findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
setupTabIcons();
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
}
private void setupTabIcons() {
TextView tabZero2 = (TextView)
LayoutInflater.from(getActivity()).inflate(R.layout.custom_tab, null);
tabZero2.setText("FAVOURITES");
//tabOne.setGravity(View.TEXT_ALIGNMENT_CENTER);
tabZero2.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.ic_star_white_24dp, 0, 0);
tabLayout.getTabAt(0).setCustomView(tabZero2);
TextView tabZero = (TextView)
LayoutInflater.from(getActivity()).inflate(R.layout.custom_tab, null);
tabZero.setText("FREQUENTS");
//tabOne.setGravity(View.TEXT_ALIGNMENT_CENTER);
tabZero.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.ic_people_outline_white_24dp, 0, 0);
tabLayout.getTabAt(1).setCustomView(tabZero);
TextView tabOne = (TextView)
LayoutInflater.from(getActivity()).inflate(R.layout.custom_tab, null);
tabOne.setText("PRONOUNS");
//tabOne.setGravity(View.TEXT_ALIGNMENT_CENTER);
tabOne.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.ic_accessibility_white_24dp, 0, 0);
tabLayout.getTabAt(2).setCustomView(tabOne);
TextView tabTwo = (TextView)
LayoutInflater.from(getActivity()).inflate(R.layout.custom_tab, null);
tabTwo.setText("CONJUCTIONS");
tabTwo.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.ic_add_white_24dp, 0, 0);
tabLayout.getTabAt(3).setCustomView(tabTwo);
TextView tabThree = (TextView)
LayoutInflater.from(getActivity()).inflate(R.layout.custom_tab, null);
tabThree.setText("ADJECTIVES");
tabThree.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.ic_favorite_border_white_24dp, 0, 0);
tabLayout.getTabAt(4).setCustomView(tabThree);
tabLayout.getTabAt(0).getCustomView().setSelected(true);
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new
ViewPagerAdapter(getChildFragmentManager());
adapter.addFrag(new favouriteCards(), "FAVOURITES");
adapter.addFrag(new predictedCards(), "FREQUENTS");
adapter.addFrag(new pronouns(), "PRONOUNS");
adapter.addFrag(new conjuctions(), "CONJUNCTIONS");
adapter.addFrag(new Others(), "ADJECTIVES");
viewPager.setAdapter(adapter);
}
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFrag(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
}
}
still struggling with this and i cannot for the life of me work out why it would work in one lot of fragments untill i add it to the next set, its the same thing with the same code it must just be initializing the last fragments that are asking for it can anyone help me here?
Thanks for any help
Basically, there is a thing that you have to keep in mind when you use fragments: do not keep references to your fragments: just create them and add to your layout, or provide to your ViewPager but then use other methods to retrieve them, like FragmentManager.findFragmentBy...
That said, your code shoud be (let me simplify with just two fragments):
Main activity
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new MyViewPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
}
class MyViewPagerAdapter extends FragmentStatePagerAdapter {
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
switch(position) {
case 0:
return new sentenceMakers();
case 1:
return new tabFragOne();
// add here fragments for any other position
}
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch(position) {
case 0:
return "QUICKS";
case 1:
return "NOUNS";
// add here titles for any other position
}
}
}
sentenceMakers
The code you will have to use in your sentenceMakers Fragment is very similar to the previous one, but you will have to use the child fragmentManager (as you did in your code) and again, do not keep your fragments in a List, let the system create them when needed.
ok i fixed it so the problem is that the parent fragmentstatepager loads fragmentA + fragmentB into memory, then the child fragmentstatepagers load there own childfragmentA + childfragmentB so we now have 2 parents and 4 children, onPrepareOptionsMenu is called from the child fragments so the the first is loaded childfragmentA(child of fragmentA) and then childFragmentA(child of fragmentB) is loaded and steals the search view, my 'fix' for this is probably a little crude i'm self taught and i'm not very aware of how to manage memory or if its bad to keep hold of references etc, i digress, in the parent fragment i check which fragment is visible using
setMenuVisibility(final boolean visible)
and in there i set a public static boolean and check for it in my childfragments and it works flawlessly for me as mentioned this is probably a terrible thing to do hopefully someone here can give a better solution
check which parent is visible
public static boolean tabFragOneVisible;
#Override
public void setUserVisibleHint(boolean isVisible){
super.setUserVisibleHint(isVisible);
if(!isVisible){
tabFragOneVisible = false;
}else{
tabFragOneVisible = true;
}
}
check if parent is visible hook up search view
#Override
public void onPrepareOptionsMenu(Menu menu) {
// need to check if fragment is visible
if (tabFragOne.tabFragOneVisible) {
SearchView searchView = (SearchView)
menu.findItem(R.id.action_search).getActionView();
SearchManager searchManager = (SearchManager) getActivity()
.getSystemService(getActivity().SEARCH_SERVICE);
searchView.setSearchableInfo(searchManager
.getSearchableInfo(getActivity().getComponentName()));
// searchView.setOnQueryTextListener(null);
searchView.setOnQueryTextListener(new
SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
showResults(newText);
return false;
}
});
}
else{
}
super.onPrepareOptionsMenu(menu);
}
Maybe, it'll still help someone struggling to make one SearchView work for multiple Fragments. I found that onQueryTextListener would work on Fragment 1 (where the SearchView is initially created) but would not fire on Fragment 2,3, etc.
Fragments 2 worked when onPrepareOptionsMenu is overridden and onViewCreated includes a setHasOptionsMenu(true). For example:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setHasOptionsMenu(true);
...the rest of your code goes here...
}
#Override
public void onPrepareOptionsMenu(Menu menu) {
MenuItem item = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) item.getActionView();
searchView.setOnQueryTextListener(this);
super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
Toast.makeText(getActivity(),"It Worked!!",Toast.LENGTH_SHORT).show();
return true;
}
I am trying to refresh the fragment depending on what drawer the user is on...
This was my attempt which does not do anything but does not give me an error.
Here is my code
public void fragmentRefresh() {
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragmentManager.findFragmentByTag("TagForRefresh"))
.commit();
}
Here is the drawer fragment code:
/**
* Diplaying fragment view for selected nav drawer list item
*/
private void displayView(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new HomeFragment();
break;
case 1:
fragment = new BrowseFragment();
break;
case 2:
fragment = new InviteFragment();
break;
case 3:
fragment = new ProfileFragment();
break;
case 4:
fragment = new SettingsFragment();
break;
case 5:
callConfirmLogout();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment, "TagForRefresh").commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
Implemented in a tab swiper fragment class:
public class ViewVotesActivity extends FragmentActivity implements ActionBar.TabListener{
//Tab options
private ViewPager viewPager;
private TabSwipeAdapter mAdapter;
private ActionBar actionBar;
// Tab titles
private String[] tabs = { "Created", "Up", "Down"};
//for custom menu to add progress bar to refresh
private MenuItem menuItem;
//Search view action bar
private SearchView search_action_bar;
//getApplicationContext().getString(R.string.created),getApplicationContext().getString(R.string.upvote), getApplicationContext().getString(R.string.downvote)
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_votes);
// Initializing tab
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
mAdapter = new TabSwipeAdapter(getSupportFragmentManager(), new UserCreatedFragment(), new UserUpVotesFragment(),new UserDownVotesFragment());
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(true);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Adding Tabs
for (String tab_name : tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name)
.setTabListener(this));
}
/**
* on swiping the viewpager make respective tab selected
* */
/**
* on swiping the viewpager make respective tab selected
* */
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) {
}
});
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// on tab selected
// show respected fragment view
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.home, menu);
setupActions(menu);
callSearchActionBar(menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar actions click
switch (item.getItemId()) {
case R.id.action_refresh:
menuItem = item;
menuItem.setActionView(R.layout.refresh_progress_bar);
//menuItem.expandActionView();
fragmentRefresh();
TestTask task = new TestTask();
task.execute("test");
return true;
case R.id.action_discover:
addNewItem();
return true;
case R.id.action_search:
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void addNewItem() {
// user redirect to register followup
Intent createItemIntent = new Intent(ViewVotesActivity.this, CreateItemActivity.class);
// Closing all the Activities
createItemIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// Add new Flag to start new Activity
createItemIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Staring Login Activity
startActivity(createItemIntent);
}
public void fragmentRefresh() {
// // Insert the fragment by replacing any existing fragment
// FragmentManager fragmentManager = getFragmentManager();
//
// fragmentManager.beginTransaction()
// .replace(R.id.frame_container, fragmentManager.findFragmentByTag("TagForRefresh"))
// .commit();
}
private class TestTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
// Simulate something long running
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
menuItem.collapseActionView();
menuItem.setActionView(null);
}
};
public void setupActions(Menu menu) {
MenuItem refreshItem = menu.findItem(R.id.action_refresh);
MenuItem discoverItem = menu.findItem(R.id.action_discover);
if (isAlwaysExpanded()) {
} else {
refreshItem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM
| MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
discoverItem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM
| MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
}
}
public void callSearchActionBar(Menu menu) {
//find the menu item and set search view at the same time
MenuItem searchItem = menu.findItem(R.id.action_search);
search_action_bar
= (SearchView) searchItem.getActionView();
if (isAlwaysExpanded()) {
search_action_bar.setIconifiedByDefault(false);
} else {
searchItem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM
| MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
}
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
if (searchManager != null) {
List<SearchableInfo> searchables = searchManager.getSearchablesInGlobalSearch();
SearchableInfo info = searchManager.getSearchableInfo(getComponentName());
for (SearchableInfo inf : searchables) {
if (inf.getSuggestAuthority() != null
&& inf.getSuggestAuthority().startsWith("applications")) {
info = inf;
}
}
search_action_bar.setSearchableInfo(info);
}
search_action_bar.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
public boolean onQueryTextChange(String newText) {
Log.e("Query = ", newText);
return false;
}
public boolean onQueryTextSubmit(String query) {
Log.e("Submit", "Submited " + query);
// user redirect to register followup
Intent searchIntent = new Intent(ViewVotesActivity.this, SearchActivity.class);
searchIntent.putExtra("search", query);
// Closing all the Activities
searchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// Add new Flag to start new Activity
searchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Staring Login Activity
startActivity(searchIntent);
return false;
}
public boolean onClose() {
Log.e("query close", "query closingggg");
return false;
}
});
}
protected boolean isAlwaysExpanded() {
return false;
}
}
UPDATE:
It looks like you're trying to tell an Activity that it's time to change the content fragment depending upon a selection in a Navigation Drawer.
This problem has two parts.
You need to provide a mechanism to communicate from your Drawer to your Activity, which, will, in turn, proceed to perform the necessary actions.
Your Fragments must either be Detached, Destroyed, Recreated and Reattached (inneficient, why?) or simply implement a mechanism that tells them: Hey, it's time to Refresh your content.
I don't see any reason why you need to completely destroy the Fragment's view if you only need to reset its data. Seems like a design flaw.
Replacing a Fragment should not mean you want to completely destroy it, since the user can simply go back or press the recently removed fragment. It would be inefficient to recreate it again.
Like I mentioned in the comments, more code is needed to see what your current approach is.
Normally a simple Interface (like the one I described below) should suffice. Your activity can receive the "clicks" in the Drawer and decide which fragment to replace (if needed).
Please be a lot more specific and provide more code.
Old Response:
Warning: if you're trying to replace the current fragment, make sure you're not getting the wrong FragmentManager. You do getFragmentManager() but I'm sure you're using the support library and therefore need to do getSupportFragmentManager();.
You've failed to mention what version you're targeting so it's hard to know.
On the other hand,
If what you want to do is tell the current visible fragment to refresh… you should use a more common approach to object-to-object communication.
You're over-complicating things.
(warning: pseudo code)
Create an interface like:
public interface Refreshable{
void onShouldRefresh();
}
Have a DrawerController capable of storing observers/listeners…
public class DrawerController {
private List<Refreshable> mListeners = new ArrayList<Refreshable>();
public void addRefreshListener(E listener) {
if (listener != null && !mListeners.contains(listener)) {
mListeners.add(listener);
}
}
public void removeRefreshListener(E listener) {
if (listener != null) {
mListeners.remove(listener);
}
}
}
Make your fragments implement it (and subscribe to the event when they are visible)
public class HomeFragment extends Fragment implements Refreshable {
// your fragment code
public void onShouldRefresh(){
// do the refresh
}
#Override
public void onResume() {
super.onResume();
yourDrawerController.addRefreshListener(this);
}
#Override
public void onPause() {
super.onPause();
yourDrawerController.removeRefreshListener(this);
}
}
Now make a method that will tell the interested parties (in this case your "Refreshable" objects) that it's time to refresh, add this to your DrawerController…
public void refresh(){
for (Refreshable listener : mListeners) {
if (listener != null) {
listener.onShouldRefresh();
}
}
}
Finally, in your code, call refresh() and have a beer.
Did I miss your point? it's not 100% clear to me.
I'm using ActionBarSherlock and ViewPagerIndicator to display Fragments as tabs. One of those Fragments adds items to ActionBar:
private String[] mapNames;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
// init an String array `mapNames` which is used when populating submenu
// ...
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_maps, menu);
SubMenu mapNamesMenu = menu.findItem(R.id.map_names).getSubMenu();
mapNamesMenu.clear();
for (int i=0; i<mapNames.length; i++) {
mapNamesMenu.add(1, i, Menu.NONE, mapNames[i]);
}
super.onCreateOptionsMenu(menu, inflater);
}
and in res/menu/fragment_maps.xml I have
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/map_names"
android:title="Maps"
android:icon="#drawable/maps_32"
android:showAsAction="always|withText">
<menu>
<item android:id="#+id/placeholder_maps" />
</menu>
</item>
</menu>
Everything is working fine until I rotate my phone. After orientation change this menu becomes inaccessible (nothing happens when icon is clicked). Then if I rotate my phone again I get this error:
FATAL EXCEPTION: main
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
at android.view.ViewRoot.setView(ViewRoot.java:532)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
at android.view.Window$LocalWindowManager.addView(Window.java:424)
at android.widget.PopupWindow.invokePopup(PopupWindow.java:912)
at android.widget.PopupWindow.showAsDropDown(PopupWindow.java:824)
at com.actionbarsherlock.internal.widget.IcsListPopupWindow.show(IcsListPopupWindow.java:226)
at com.actionbarsherlock.internal.view.menu.MenuPopupHelper.tryShow(MenuPopupHelper.java:129)
at com.actionbarsherlock.internal.view.menu.MenuPopupHelper.show(MenuPopupHelper.java:102)
at com.actionbarsherlock.internal.view.menu.ActionMenuPresenter.onSubMenuSelected(ActionMenuPresenter.java:273)
at com.actionbarsherlock.internal.view.menu.MenuBuilder.dispatchSubMenuSelected(MenuBuilder.java:263)
at com.actionbarsherlock.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:892)
at com.actionbarsherlock.internal.view.menu.ActionMenuView.invokeItem(ActionMenuView.java:510)
at com.actionbarsherlock.internal.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:145)
at android.view.View.performClick(View.java:2494)
at android.view.View$PerformClick.run(View.java:9122)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3806)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)
Any ideas how to solve it? I'm using Android 2.3.6
Edit: see test repository
I think , This is a Context problem. That's why BadTokenException is occurring.
There are many possibilities behind this exception:
1) May be you are using "this" as a context-reference at some place where it actually needs YourActivity.this or the parent activity's context.
OR
2) From the log-cat i am guessing, you are trying to display a Pop-up window.
The problem may be, you are displaying Pop-up window too early (i.e. before the Activity life cycle completes.).
So wait till the activity life cycle completes.
To defer showing the popup, you can refer this link.
In-short this problem is due to the below use-case:
An activity's reference is passed to the some component (i.e. like
Toast, alert dialog, pop-up etc), and activity destroyed but
that component is still alive or trying to use destroyed activity's
context.
So make sure that there isn't any situation like this.
Hope this will you give you some hint about solving the problem.
This is your MainActivity:
public class BaseSampleActivity extends SherlockFragmentActivity {
TestFragmentAdapter mAdapter;
ViewPager mPager;
PageIndicator mIndicator;
protected ListFragment mFrag;
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.themed_titles);
//This adapter can load as many fragment as you want with different content, see later
mAdapter = new TestFragmentAdapter(getSupportFragmentManager());
mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mPager.setCurrentItem(1);
mIndicator = (TitlePageIndicator)findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
//This show how to set up a Searhbar
SearchView searchView = new SearchView(getSupportActionBar().getThemedContext());
searchView.setQueryHint("Procure pelo nome");
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
// TODO Auto-generated method stub
// Intent search = new Intent(getApplicationContext(), SearchableActivity.class);
// search.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// search.putExtra("query", query);
// startActivity(search);
return true;
}
#Override
public boolean onQueryTextChange(String newText) {
// TODO Auto-generated method stub
return false;
}
});
menu.add("Search")
.setIcon(R.drawable.ic_search_inverse)
.setActionView(searchView)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
//This is how to set up a SubMenu
SubMenu subMenu1 = menu.addSubMenu("Action Item");
subMenu1.add(0, 1, 0, "Sample");
subMenu1.add(0, 2, 0, "Menu");
subMenu1.add(0, 3, 0, "Sair");
MenuItem subMenu1Item = subMenu1.getItem();
subMenu1Item.setIcon(R.drawable.ic_title_share_default);
subMenu1Item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
//This is a switch case to do when the SubMenu is clicked.
case 1:
Toast.makeText(BaseSampleActivity.this, "Now "+item.getItemId(), Toast.LENGTH_SHORT).show();
return true;
case 2:
Toast.makeText(BaseSampleActivity.this, "Now = "+item.getItemId(), Toast.LENGTH_SHORT).show();
return true;
case 3:
Toast.makeText(BaseSampleActivity.this, "Now = "+item.getItemId(), Toast.LENGTH_SHORT).show();
return true;
}
return super.onOptionsItemSelected(item);
}
}
This is your FragmentPagerAdapter:
class TestFragmentAdapter extends FragmentPagerAdapter implements IconPagerAdapter {
//Here you set up the title of each fragment, its in portuguese.
protected static final String[] CONTENT = new String[] { "CATEGORIAS", "PRINCIPAL", "AS MELHORES", };
protected static final int[] ICONS = new int[] {
R.drawable.perm_group_calendar,
R.drawable.perm_group_camera,
R.drawable.perm_group_device_alarms,
};
private int mCount = CONTENT.length;
public TestFragmentAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {Fragment f = null;
switch(position){
case 0:
{
//Here you can set up a lot of diferent fragment content, here I just created a simple //arraylistfragment
f = new ArrayListFragment();
// set arguments here, if required
Bundle args = new Bundle();
args.putInt(ArrayListFragment.ARG_position, position);
f.setArguments(args);
break;
}
case 1:
{
f = new ArrayListFragment();
// set arguments here, if required
Bundle args = new Bundle();
f.setArguments(args);
break;
}
case 2:
{
f = new ArrayListFragment();
// set arguments here, if required
Bundle args = new Bundle();
f.setArguments(args);
break;
}
default:
throw new IllegalArgumentException("not this many fragments: " + position);
}
return f;
}
#Override
public int getCount() {
return mCount;
}
#Override
public CharSequence getPageTitle(int position) {
return TestFragmentAdapter.CONTENT[position % CONTENT.length];
}
#Override
public int getIconResId(int index) {
return ICONS[index % ICONS.length];
}
public void setCount(int count) {
if (count > 0 && count <= 10) {
mCount = count;
notifyDataSetChanged();
}
}
}
I just done an easy sample that you can easy understand how to implements ActionBarSherlock and ViewPagerIndicator.
I´d like to upload this to github, but it will take a while to understand how to do it, maybe you can teach me later.
Then I upload this in 4shared. http://www.4shared.com/rar/zOWrvmyu/ViewpagerandSherlock.html
If you have any question, ask me later.
This worked for me but I don't know if there are some side effects.
Add this to Fragment's onCreate
setRetainInstance(true);
and this to AndroidManifest.xml to Activity containing the Fragment
android:configChanges="orientation"
I have an activity that uses a fragmentpageradapter to create an ics style actionBar. Each page needs to update the actionBar though. Is there a way I can call onCreateOptionsMenu in my onPageSelected?
I've trimmed a lot of the code out from the example below for simplicity's sake.
public class ListFragmentViewPagerActivity extends FragmentActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.thread_view);
ViewPager pager = (ViewPager) findViewById(android.R.id.list);
pager.setAdapter(new ExamplePagerAdapter(getSupportFragmentManager()));
TitlePageIndicator indicator = (TitlePageIndicator)findViewById(R.id.indicator);
indicator.setViewPager(pager);
indicator.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
});
}
public class ExamplePagerAdapter extends FragmentPagerAdapter implements TitleProvider{
public ExamplePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return URLS.size();
}
#Override
public Fragment getItem(int position) {
Fragment fragment = new ThreadFragment();
// set arguments here, if required
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
#Override
public String getTitle(int pos) {
return TITLES.get(pos);
}
}
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuinflate = new MenuInflater(this);
menuinflate.inflate(R.menu.thread_menu, menu);
if (type.equals("xda")) {
menu.removeItem(R.id.ss_view);
}
//This worked when I only needed to call it one time. I need to update this menu for each page in my viewPager though.
if (isFav) {
menu.getItem(2).setIcon(R.drawable.fav_ab);
}
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
break;
case R.id.ss_view:
Intent ssi = new Intent(this, SSActivity.class);
ssi.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Bundle b = new Bundle();
ssi.putExtras(b);
startActivity(ssi);
break;
case R.id.restart:
break;
case R.id.fav_ab:
break;
default:
return super.onOptionsItemSelected(item);
}
return false;
}
}
UPDATE
Calling invalidateOptionsMenu() in my onPageSelected() did the trick!
Use invalidateOptionsMenu() but make sure you wrap this in a trycatch if you are supporting anythign below 3.0, as this method does not exist and will crash!
If you want to update your menu on pre 3.0 devices, override the onPrepareOptionsMenu() as well, which will be called everytime the menu is opened.