I have one SherlockFragmentActivity with 3 fragments. Everything works fine but when I swipe from fragment to fragment, wrong menus are shown. Fragment1 is showing menu from fragment2, SearchView on Fragment1 is filtering data on Fragment2. Here is the code for SherlockFragmentActivity
public class MainHolder extends SherlockFragmentActivity {
private static final String[] CONTENT = new String[] { "FRAGMENT1", "FRAGMENT2", "FRAGMENT3" };
FragmentAdapter mAdapter;
ViewPager mPager;
TabPageIndicator mIndicator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_holder);
mAdapter = new FragmentAdapter(getSupportFragmentManager());
mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mIndicator = (TabPageIndicator)findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
}
class FragmentAdapter extends FragmentPagerAdapter {
public FragmentAdapter(FragmentManager fm) {
super(fm);
}
public Fragment getItem(int position) {
switch(position)
{
case 0:
return Fragment1.newInstance(CONTENT[position % CONTENT.length]);
case 1:
return Fragment2.newInstance(CONTENT[position % CONTENT.length]);
case 2:
return Fragment3.newInstance(CONTENT[position % CONTENT.length]);
default:
return null;
}
}
#Override
public CharSequence getPageTitle(int position) {
return CONTENT[position % CONTENT.length].toUpperCase();
}
#Override
public int getCount() {
return CONTENT.length;
}
}
#Override
public void onBackPressed() {
Fragment fragment = (Fragment) getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":"+mPager.getCurrentItem());
if (fragment != null) // could be null if not instantiated yet
{
if (fragment.getView() != null) {
// Pop the backstack on the ChildManager if there is any. If not, close this activity as normal.
if (!fragment.getChildFragmentManager().popBackStackImmediate()) {
finish();
}
}
}
}
}
And here is for the fragment
public class Fragment1 extends SherlockFragment {
private static final String KEY_CONTENT = "Fragment1:Content";
LazyAdapter fragment1adapter;
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.clear();
inflater.inflate(R.menu.fragment1, menu);
MenuItem searchItem = menu.findItem(R.id.menu_search);
final SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setQueryHint("Pretraga ...");
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextChange(String newText) {
if (newText.length() != 0) {
fragment1adapter.getFilter().filter(newText);
return true;
}
return false;
}
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
});
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
#Override
public boolean onClose() {
fragment1adapter.getFilter().filter("");
return false;
}
});
}
public static Fragment1 newInstance(String content) {
Fragment1 fragment = new Fragment1();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 20; i++) {
builder.append(content).append(" ");
}
builder.deleteCharAt(builder.length() - 1);
fragment.mContent = builder.toString();
return fragment;
}
private String mContent = "???";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if ((savedInstanceState != null) && savedInstanceState.containsKey(KEY_CONTENT)) {
mContent = savedInstanceState.getString(KEY_CONTENT);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment1, container, false);
setRetainInstance(true);
setHasOptionsMenu(true);
setMenuVisibility(true);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(KEY_CONTENT, mContent);
}
}
Other fragments are the same, with their separate menus and layouts. Can anyone give me some hints why is this happening?
The solution is to remove setMenuVisibility(true); from fragments onCreateView.
Related
I have a problem pass or intent data from (activity) to (Fragment) containing 3 (TabLayout ).
How can I transfer data to a specific (TabLayout) of the third that I own.
by RecyclerView onItemClick.
This is code of RecyclerView onItemClick.I was send it From first activity to secand activity like this As follows..
Pass data first activity
public static final String EXTRA_FROM = "FROMPL";
#Override
public void onItemClick(int position) {
Intent detailIntent = new Intent(this,
com.example.myapplication.Fragmant.StatusFragment.class);
ExampleItem clickedItem = mExampleList.get(position);
detailIntent.putExtra(EXTRA_FROM, clickedItem.getCreator());
startActivity(detailIntent);
}
secand activity get data
Intent i = getIntent();
final String FROMPL = i.getStringExtra("FROMPL");
textfrom.setText(FROMPL);
But now like that not work.I don’t know how I can pass it to a specific (TabLayout)to work as Fragment in (MainActivityFargmain).
I want each (TabLayout) in (MainActivityFargmain) has specific data.
So Anyone have a solution for that؟
all my code
public class MainActivityFargmain extends AppCompatActivity {
Toolbar toolbar;
TabLayout tabLayout;
ViewPager viewPager;
PageAdapter pageAdapter;
TabItem tabChats;
TabItem tabStatus;
TabItem tabCalls;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_m);
toolbar = findViewById(R.id.toolbar);
toolbar.setTitle(getResources().getString(R.string.app_name));
setSupportActionBar(toolbar);
tabLayout = findViewById(R.id.tablayout);
tabChats = findViewById(R.id.tabChats);
tabStatus = findViewById(R.id.tabStatus);
tabCalls = findViewById(R.id.tabCalls);
viewPager = findViewById(R.id.viewPager);
pageAdapter = new PageAdapter(getSupportFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(pageAdapter);
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
if (tab.getPosition() == 1) {
toolbar.setBackgroundColor(ContextCompat.getColor(MainActivityFargmain.this,
R.color.colorAccent));
tabLayout.setBackgroundColor(ContextCompat.getColor(MainActivityFargmain.this,
R.color.colorAccent));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(ContextCompat.getColor(MainActivityFargmain.this,
R.color.colorAccent));
}
} else if (tab.getPosition() == 2) {
toolbar.setBackgroundColor(ContextCompat.getColor(MainActivityFargmain.this,
android.R.color.darker_gray));
tabLayout.setBackgroundColor(ContextCompat.getColor(MainActivityFargmain.this,
android.R.color.darker_gray));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(ContextCompat.getColor(MainActivityFargmain.this,
android.R.color.darker_gray));
}
} else {
toolbar.setBackgroundColor(ContextCompat.getColor(MainActivityFargmain.this,
R.color.colorPrimary));
tabLayout.setBackgroundColor(ContextCompat.getColor(MainActivityFargmain.this,
R.color.colorPrimary));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(ContextCompat.getColor(MainActivityFargmain.this,
R.color.colorPrimaryDark));
}
}
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
}
}
public class PageAdapter extends FragmentPagerAdapter {
private int numOfTabs;
PageAdapter(FragmentManager fm, int numOfTabs) {
super(fm);
this.numOfTabs = numOfTabs;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new ChatFragment();
case 1:
return new StatusFragment();
case 2:
return new CallFragment();
default:
return null;
}
}
#Override
public int getCount() {
return numOfTabs;
}
}
public class StatusFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
setHasOptionsMenu(true);
return inflater.inflate(R.layout.fragment_status, container, false);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_status, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_status) {
Toast.makeText(getActivity(), "Clicked on " + item.getTitle(), Toast.LENGTH_SHORT)
.show();
}
return true;
}
}
public class ChatFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
setHasOptionsMenu(true);
return inflater.inflate(R.layout.fragment_chat, container, false);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_chats, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_chat) {
Toast.makeText(getActivity(), "Clicked on " + item.getTitle(), Toast.LENGTH_SHORT)
.show();
}
return true;
}
}
You are passing the data to fragment from first activity and you are fetching data from second activity.
But in a proper scenario you should pass the data to second activity. Then after you can fetch it.
public static final String EXTRA_FROM = "FROMPL";
#Override
public void onItemClick(int position) {
Intent detailIntent = new Intent(this,
MainActivityFargmain.class);
ExampleItem clickedItem = mExampleList.get(position);
detailIntent.putExtra(EXTRA_FROM, clickedItem.getCreator());
startActivity(detailIntent);
}
Fetch the data in MainActivityFragmain using below code.
Intent i = getIntent();
final String FROMPL = i.getStringExtra("FROMPL");
pageAdapter = new PageAdapter(getSupportFragmentManager(), tabLayout.getTabCount(),FROMPL);
viewPager.setAdapter(pageAdapter);
Update your Pager adapter class like below.
public class PageAdapter extends FragmentPagerAdapter {
private int numOfTabs;
private String FROMPL;
PageAdapter(FragmentManager fm, int numOfTabs, String FROMPL) {
super(fm);
this.numOfTabs = numOfTabs;
this.FROMPL = FROMPL;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new ChatFragment();
case 1:
StatusFragment statusFragment = new StatusFragment();
Bundle bundle=new Bundle();
bundle.putString("FROMPL", FROMPL);
statusFragment.setArguments(bundle);
return statusFragment;
case 2:
return new CallFragment();
default:
return null;
}
}
#Override
public int getCount() {
return numOfTabs;
}
}
I want to create a createOrderActivity where has three fragments like Service info, ScheduleInfo, confirmation
the service info fragment has editText
if click NextButton(which is situated CreateOrderActivity) check validation editText first. then move ScheduleFragment page.
if first two pages validation ok then move to Confirmation Fragment page.
Here is the FragmentViewpagerAdapter class
public class FragmentViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> fragmentList = new ArrayList<>();
private final List<String> fragmentTitleList = new ArrayList<>();
public FragmentViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
#Override
public int getCount() {
return fragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
fragmentList.add(fragment);
fragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return fragmentTitleList.get(position);
}
}
In CreateOrderActivity class
#Override
public void onPageSelected(int position) {
boolean checkSch= false;
if (position == 1) {
ServiceInfoFragment serviceInfoFragment = new ServiceInfoFragment();
//checking validation from ServiceInfoFragment fragment Class
if (serviceInfoFragment.checkServiceValidation()) {
checkSch = true;
//Toast.makeText(CreateOrderActivity.this, "Validation okay", Toast.LENGTH_SHORT).show();
}else {
checkSch = false;
// Toast.makeText(CreateOrderActivity.this, "Please check validation", Toast.LENGTH_SHORT).show();
pagerCreateOrder.setCurrentItem(position-1);
}
}
if (position == 2) {
if (checkSch){
ScheduleFragment scheduleFragment = new ScheduleFragment();
if (scheduleFragment.checkScheduleValidation()) {
Toast.makeText(CreateOrderActivity.this, "Validation okay", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(CreateOrderActivity.this, "Please check S validation", Toast.LENGTH_SHORT).show();
pagerCreateOrder.setCurrentItem(position-1);
}
}else {
Toast.makeText(CreateOrderActivity.this, "Please check validation", Toast.LENGTH_SHORT).show();
pagerCreateOrder.setCurrentItem(position-2);
}
}
}
//checking checkScheduleValidation() in ScheduleFragment class. return null exception
*bellow mehtod declear in Fragment *
public boolean checkServiceValidation(){
return true;
}
I upload this Image
I used this Reference
I found a solution in my way. I have loaded three fragments in a viewpager. In the second fragment, there is one edittext. on clicking the next button, there is a validation for checking email. On the basis of validation next fragment is loaded. All the Fragments are loaded as singleton . You might have caused null pointer exception , because of multiple instance of fragments.
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private SectionsPagerAdapter mSectionsPagerAdapter;
private FragmentTwo fragmentTwo;
private ViewPager mViewPager;
Button back, next;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
back = findViewById(R.id.back);
next = findViewById(R.id.next);
next.setOnClickListener(this);
back.setOnClickListener(this);
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.vp_viewpager);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i1) {
}
#Override
public void onPageSelected(int i) {
if (i==2){
if (!fragmentTwo.checkEditText()) {
Toast.makeText(getApplicationContext(),"False",Toast.LENGTH_LONG).show();
mViewPager.setCurrentItem(i-1);
return;
}
}
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
}
private void changeViewPagerPosition(int position) {
int totalCount = mViewPager.getAdapter().getCount();
if (position < 0 || position >= totalCount) {
return;
}
mViewPager.setCurrentItem(position);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public void onClick(View view) {
int currentViewpagerPosition = mViewPager.getCurrentItem();
switch (view.getId()) {
case R.id.back:
changeViewPagerPosition(currentViewpagerPosition - 1);
break;
case R.id.next:
if (currentViewpagerPosition==1){
if (!fragmentTwo.checkEditText()) {
Toast.makeText(getApplicationContext(),"Falsee",Toast.LENGTH_LONG).show();
return;
}
}
changeViewPagerPosition(currentViewpagerPosition + 1);
break;
}
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return FragmentOne.newInstance(position);
case 1:
return fragmentTwo=FragmentTwo.getInstance();
case 2:
return FragmentThree.newInstance(position);
default:
return FragmentThree.newInstance(position);
}
}
#Override
public int getCount() {
return 3;
}
}
}
The Fragment 2
public class FragmentTwo extends Fragment {
EditText email;
private static FragmentTwo fragment=null;
public FragmentTwo() {
}
public static FragmentTwo getInstance() {
if (fragment == null){
fragment = new FragmentTwo();
}
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_two, container, false);
return rootView;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
email = getView().findViewById(R.id.editText);
}
public boolean emailValidator()
{
Pattern pattern;
Matcher matcher;
final String EMAIL_PATTERN = "^[_A-Za-z0-" +
"9-]+(\\.[_A-Za-z0-9-]+)*#[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
pattern = Pattern.compile(EMAIL_PATTERN);
matcher = pattern.matcher(email.getText().toString());
return matcher.matches();
}
public Boolean checkEditText(){
if (emailValidator()){
return true;
}
return false;
}
}
I've 2 fragments in viewpager and I want to add callback methods using interface in both. I add the interface listener while initiating fragments in viewpager adapter but only the last fragment's is being called. That's why when I click on the MainActivity's menu option, only the Toast in MyFragB is being called even if MyFragA is showing.
Both Fragments... Only Activity calling MyFragB Toast is showing when wither fragment is opened
public class MyFragA extends Fragment implements FragmentCaller {
private TextView myTxt;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.myfraga, container, false);
}
#Override
public void CallFragment() {
if(getActivity()!=null)
Toast.makeText(getActivity(), "Activity calling MyFragA", Toast.LENGTH_SHORT).show();
}
}
public class MyFragB extends Fragment implements FragmentCaller{
private TextView myTxt;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.myfragb, container, false);
}
#Override
public void CallFragment() {
if(getActivity()!=null)
Toast.makeText(getActivity(), "Activity calling MyFragB", Toast.LENGTH_SHORT).show();
}
}
Main Activity
public class MainActivity extends AppCompatActivity {
TabLayout tabs;
ViewPager viewpager;
FragmentCaller fragListerner = null;
public interface FragmentCaller {
void CallFragment();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabs = (TabLayout)findViewById(R.id.tabs);
viewpager = (ViewPager)findViewById(R.id.viewpager);
SimpleFragmentPagerAdapter adapter = new SimpleFragmentPagerAdapter(this, getSupportFragmentManager());
viewpager.setAdapter(adapter);
tabs.setupWithViewPager(viewpager);
} // onCreate ends
public class SimpleFragmentPagerAdapter extends FragmentStatePagerAdapter {
private Context mContext;
public SimpleFragmentPagerAdapter(Context context, FragmentManager fm) {
super(fm);
mContext = context;
}
// This determines the fragment for each tab
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
if (position == 0) {
fragment = new MyFragA();
fragListerner = (FragmentCaller) fragment;
return fragment;
} else if (position == 1){
fragment = new MyFragB();
fragListerner = (FragmentCaller)fragment;
return fragment;
}
return null;
}
// This determines the number of tabs
#Override
public int getCount() {
return 2;
}
// This determines the title for each tab
#Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
switch (position) {
case 0:
return mContext.getString(R.string.fraga);
case 1:
return mContext.getString(R.string.fragb);
default:
return null;
}
}
}
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.callback, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()){
case R.id.call:
if(fragListerner!=null){
if(fragListerner instanceof MyFragA){
fragListerner.CallFragment();
}else if(fragListerner instanceof MyFragB){
fragListerner.CallFragment();
}
}
break;
}
return true;
}
}
I used rick's answer from here.
public class MainActivity extends AppCompatActivity {
TabLayout tabs;
ViewPager viewpager;
public static int currentFrag=0;
SimpleFragmentPagerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabs = (TabLayout)findViewById(R.id.tabs);
viewpager = (ViewPager)findViewById(R.id.viewpager);
adapter = new SimpleFragmentPagerAdapter(this, getSupportFragmentManager());
viewpager.setAdapter(adapter);
tabs.setupWithViewPager(viewpager);
viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
System.out.println("sammy_current_position: "+position);
currentFrag = position;
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
} // onCreate ends
public class SimpleFragmentPagerAdapter extends FragmentStatePagerAdapter {
private Context mContext;
public SimpleFragmentPagerAdapter(Context context, FragmentManager fm) {
super(fm);
mContext = context;
}
#Override
public Fragment getItem(int position) {
if (position == 0) {
return new MyFragA();
} else if (position == 1){
return new MyFragB();
}
return null;
}
#Override
public int getCount() {
return 2;
}
// This determines the title for each tab
#Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
switch (position) {
case 0:
return mContext.getString(R.string.fraga);
case 1:
return mContext.getString(R.string.fragb);
default:
return null;
}
}
}
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.callback, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()){
case R.id.call:
if(currentFrag == 0) {
MyFragA frag1 = (MyFragA)viewpager.getAdapter().instantiateItem(viewpager, viewpager.getCurrentItem());
frag1.specialCase();
}
break;
}
return true;
}
}
but only the last fragment's is being called
Of Course ! because at pos == 0 you are setting fragListerner = (FragmentCaller) fragment then at again in pos == 1 you re-set fragListerner = (FragmentCaller)fragment;. So this condition, fragListerner instanceof MyFragB will always be true!
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
if (position == 0) {
fragment = new MyFragA();
fragListerner = (FragmentCaller) fragment;
return fragment;
} else if (position == 1){
fragment = new MyFragB();
fragListerner = (FragmentCaller)fragment;
return fragment;
}
return null;
}
So, you are trying to communicate from activity to fragment
okay, if you still want to use interfaces, you can do it like that:
create an instance of your interface for each fragment! and in getItem assign them both,
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
if (position == 0) {
fragment = new MyFragA();
fragAListerner = (FragmentCaller) fragment;
return fragment;
} else if (position == 1){
fragment = new MyFragB();
fragBListerner = (FragmentCaller)fragment;
return fragment;
}
return null;
}
But, there is an easier way to call fragment's methods from it's parent activity, which is like follows, for ex:
Fragment fragment = adapter.getItem(0); // MyFragA is at pos 0
fragment.<specific_function_name>();
Or, by using it's id!
MyFragA fragment = (MyFragA) getFragmentManager().findFragmentById(R.id.MyFragAId);
fragment.<specific_function_name>();
Or, by using it's tag!
MyFragA fragment = (MyFragA) getFragmentManager().findFragmentByTag("MyFragATag");
fragment.<specific_function_name>();
I'm having a strange problem using an ActionView in my Actionbar (specifically ActionbarSherlock). This issue is only happening in devices below SDK 3.0 (basically Gingerbread devices is all I'm testing on).
My app has a ViewPager and I am animating one of my menu items while an AsyncTask is running. If I touch the ActionView before swiping everything is ok, if I swipe to any of the views, then go back to the first view, which is the only view to have the ActionView, and touch the ActionView the icon is doubling up on itself, like so:
I had this same issue previously, before I implemented a ViewPager, and I fixed it by stopping and starting the animation in onCreateOptionsMenu and calling invalidateMenuOptions, which is why I have ActivityCompat.invalidateOptionsMenu(this); in onResume of the Activity. I was hoping, by calling that, the menu would refresh itself and fix the duplicating, but it isn't.
UPDATE Using getSherlock().dispatchInvalidateOptionsMenu(); seems to, at least, get the menu to refresh itself, but it causing the ActionView to go nuts.
ViewPager:
public class Main extends SherlockFragmentActivity
{
private static List<Integer> mIds;
private static SparseArray<Fragment> mPageReferenceMap = new SparseArray<Fragment>();
#Override
public void onCreate(final Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.main);
mViewPager = (ViewPager)findViewById(R.id.viewpager);
mMyFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mMyFragmentPagerAdapter);
mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
GetListingFragment().StopAnimation(); //needed to add this because the ActionView was showing on the other views when swiping
}
#Override
public void onPageScrolled(int position, float offset, int offsetPixel) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
mIds = new ArrayList<Integer>();
mIds.add(0);
mIds.add(1);
mIds.add(2);
}
#Override
public void onResume()
{
super.onResume();
ActivityCompat.invalidateOptionsMenu(this);
}
private ListingFragment GetKeywordsFragment()
{
ListingFragment lf = (ListingFragment)getSupportFragmentManager().findFragmentById(R.id.fragmentListing);
if (lf == null)
{
final MyFragmentPagerAdapter fpa = (MyFragmentPagerAdapter)mViewPager.getAdapter();
lf = (ListingFragment)fpa.getFragment(0);
}
return lf;
}
private static class MyFragmentPagerAdapter extends FragmentStatePagerAdapter {
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
if (index == 0)
{
final ListingFragment lf = ListingFragment.newInstance();
mPageReferenceMap.put(index, lf);
return lf;
}
else
{
final DetailFragment df = DetailFragment.newInstance(mIds.get(index));
mPageReferenceMap.put(index, df);
return df;
}
}
public Fragment getFragment(int key) {
return mPageReferenceMap.get(key);
}
#Override
public int getCount() {
return 3;
}
}
}
Fragment:
public class ListFragment extends SherlockListFragment
{
private int mId;
private MenuItem refreshItem;
private AsyncTask<Void, String, Void> gi;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
public static ListingFragment newInstance(int id) {
ListingFragment lf = new ListingFragment();
Bundle bundle = new Bundle();
bundle.putInt("id", id);
lf.setArguments(bundle);
return lf;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (getArguments() != null)
mId = getArguments().getInt("id");
return inflater.inflate(R.layout.listing, container, false);
}
private class GetItems extends AsyncTask<Void, String, Void> {
#Override
protected void onPreExecute()
{
StartAnimation();
}
#Override
protected Void doInBackground(Void... unused)
{
//background process to get items
}
protected void onPostExecute(final Void unused)
{
StopAnimation();
}
}
#Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
inflater.inflate(R.menu.keyword_menu, menu);
StopAnimation();
refreshItem = menu.findItem(R.id.refresh);
if (fi != null && fi.getStatus() == AsyncTask.Status.RUNNING)
StartAnimation();
super.onCreateOptionsMenu(menu, inflater);
}
private void StartAnimation() {
if (refreshItem != null && refreshItem.getActionView() == null)
{
final LayoutInflater inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final ImageView ivRefresh = (ImageView)inflater.inflate(R.layout.refresh_view, null);
final Animation rotation = AnimationUtils.loadAnimation(activity, R.anim.refresh);
ivRefresh.startAnimation(rotation);
refreshItem.setActionView(ivRefresh);
}
}
public void StopAnimation()
{
if (refreshItem != null && refreshItem.getActionView() != null)
{
refreshItem.getActionView().clearAnimation();
refreshItem.setActionView(null);
}
}
#Override
public boolean onOptionsItemSelected(final MenuItem item)
{
if (item.getItemId() == R.id.getitems) {
gi = new GetItems(getActivity(), null);
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
}
Looks like this is a known bug in ABS:
https://github.com/JakeWharton/ActionBarSherlock/issues/331
My app uses a ViewPager in portrait mode and a dual-fragment layout in landscape.
I am trying to kick off an AsyncTask, that is in the Fragment, from Activity. The AsyncTask is normally started from a menu item in the Actionbar, but I have a need to start it programatically from the Activity.
The menu item is an ImageView and I'm animating it while the AsyncTask is running. The code I have works fine in the dual-fragment landscape view, but I'm getting a NullPointerException on the menu item when in portrait mode.
Activity
public class Main extends SherlockFragmentActivity
{
private static List<Integer> mIds;
private static SparseArray<Fragment> mPageReferenceMap = new SparseArray<Fragment>();
#Override
public void onCreate(final Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.main);
mViewPager = (ViewPager)findViewById(R.id.viewpager); //view pager exists, so we are using the portait layout
if (mViewPager != null)
{
mIds = new ArrayList<Integer>();
mIds.add(0);
mIds.add(1);
mIds.add(2);
}
else //in landscape
{
ListFragment lf = (ListFragment)getSupportFragmentManager().findFragmentById(R.id.fragmentList);
if (lf == null)
lf = new ListFragment();
DetailFragment df = (DetailFragment)getSupportFragmentManager().findFragmentById(R.id.fragmentDetail);
if (df == null)
{
df = new DetailFragment();
df.setArguments(getIntent().getExtras());
}
getSupportFragmentManager().beginTransaction().add(R.id.fragmentList, lf).commit();
getSupportFragmentManager().beginTransaction().add(R.id.fragmentDetail, df).commit();
}
final MyFragmentPagerAdapter fpa = (MyFragmentPagerAdapter)mViewPager.getAdapter();
ListFragment lf2 = (ListFragment)fpa.getFragment(0);
//this works if I use:
//(ListFragment)getSupportFragmentManager().findFragmentById(R.id.fragmentList);
lf2.RunTask();
}
private static class MyFragmentPagerAdapter extends FragmentStatePagerAdapter {
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
if (index == 0)
{
ListFragment lf = ListFragment.newInstance();
mPageReferenceMap.put(index, lf);
return lf;
}
else
{
DetailFragment df = DetailFragment.newInstance(mIds.get(index-1));
mPageReferenceMap.put(index, df);
return df;
}
public Fragment getFragment(int key) {
return mPageReferenceMap.get(key);
}
public void destroyItem(View container, int position, Object object) {
super.destroyItem(container, position, object);
mPageReferenceMap.remove(position);
}
#Override
public int getCount() {
return 4;
}
}
}
Fragment
public class ListingFragment extends SherlockListFragment
{
private MenuItem refreshItem;
public static ListingFragment newInstance() {
ListingFragment lf = new ListingFragment();
return lf;
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.listing_layout, container, false);
}
private void StartAnimation() {
final LayoutInflater inflater = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final ImageView ivRefresh = (ImageView)inflater.inflate(R.layout.refresh_view, null);
final Animation rotation = AnimationUtils.loadAnimation(getActivity(), R.anim.refresh);
ivRefresh.startAnimation(rotation);
//this is null
refreshItem.setActionView(ivRefresh);
}
public void StopAnimation()
{
if (refreshItem != null && refreshItem.getActionView() != null)
{
refreshItem.getActionView().clearAnimation();
refreshItem.setActionView(null);
}
}
public void RunTask()
{
new GetItems().execute();
}
private class GetItems extends AsyncTask<Void, Void, Void>
{
#Override
protected void onPreExecute()
{
StartAnimation();
}
#Override
protected Void doInBackground(Void... unused)
{
...
}
protected void onPostExecute(final Void unused)
{
StopAnimation();
}
}
#Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
inflater.inflate(R.menu.keyword_menu, menu);
refreshItem = menu.findItem(R.id.get);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(final MenuItem item)
{
if (item.getItemId() == R.id.get) {
gi = new GetItems(getActivity(), null);
gi.execute();
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
}
I think following link provide you with your answer on how to avoid the nullpointer exception.
Fragment's instances may be recreated by the system at any time, that's why it's not easy to "hold a reference to them". You have to use the fragmentmanager.
adapter instance gone in fragment with listview