Using a generic class for multiple objects (ActionBar tabs)

I am currently using ABS, ActionBar tabs and TabsAdapter / ViewPager to create a nice tab layout for my application. I have category 5+ tabs up - eventually the user will be able to add new categories (I will also install this later). So, at the moment I have the main SherlockFragmentActivity with many files of the SherlockFragment category. In onCreate for the main SFA, I create an actionBar and add all its tabs, for example:

 mTabsAdapter.addTab(bar.newTab().setText(R.string.login), LoginFragment.class, null); mTabsAdapter.addTab(bar.newTab().setText("Geographics"), GeoFragment.class, null); mTabsAdapter.addTab(bar.newTab().setText(R.string.economics), EconFragment.class, null); mTabsAdapter.addTab(bar.newTab().setText(R.string.elections), ElectionsFragment.class, null); 

Instead, I would like to create a new CategoryFragment solution instead of using all the specific choices, Geo, Econ, etc. Can someone provide a solution? Ideally, I would just like to pass the string to the tab that is being added, so that CategoryFragment can just inflate based on the string. I would like this solution because the code is very redundant in several classes, when the whole class really works, this is the loading material from SQL dB online, receiving only data for its own category.

Here is my TabsAdapter class:

 public class TabsAdapter extends FragmentPagerAdapter implements ActionBar.TabListener, ViewPager.OnPageChangeListener { private final Context mContext; private Polling activity; private final ActionBar mActionBar; private final ViewPager mViewPager; private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); final class TabInfo { private final Class<?> clss; private final Bundle args; //private final String title; //This string is implemented only as part of my attempt! TabInfo(Class<?> _class, Bundle _args, String _title) { clss = _class; args = _args; title = _title; } } /*Constructor method that adds a TabsAdapter to each tab that is created. * It also adds the ViewPager to each tab so that the user can swipe to change tabs. */ public TabsAdapter(SherlockFragmentActivity activity, ViewPager pager) { super(activity.getSupportFragmentManager()); mContext = activity; this.activity = (Polling) activity; mActionBar = activity.getSupportActionBar(); mViewPager = pager; mViewPager.setAdapter(this); mViewPager.setOnPageChangeListener(this); } /*This is the method I've been trying to use to solve the problem, but it not really cutting it!*/ public void buildTabs() throws ClassNotFoundException { String [] tabs = {"Econ", "Elections", "Geo", "Politics", "Science", "Finance", "Religion", "Military", "International" }; final String resource = "R.string."; mTabsAdapter.addTab(bar.newTab().setText("Login"), LoginFragment.class, null, "Login"); for (int j = 0; j < tabs.length; j++) { String res = resource + tabs[j]; String clas = tabs[j] + "Fragment"; String total = "com.davekelley.polling." + clas; mTabsAdapter.addTab(bar.newTab().setText(tabs[j]), CategoryFragment.class, null, tabs[j]); } } /*A fairly simple method that sets the TabInfo for each tab so that the TabsAdapter * knows which class the tab that is being added actually belonds to. It also updates * the UI interface when each tab is added. */ public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args, String title) { TabInfo info = new TabInfo(clss, args, title); tab.setTag(info); tab.setTabListener(this); mTabs.add(info); mActionBar.addTab(tab); notifyDataSetChanged(); } public int getCount() { return mTabs.size(); } /*A method that is used in other classes to allow each tab Fragment to * access its inherited methods from a mother-class, in this case, SherlockFragment */ public int getPosition(SherlockFragment fragment) { for (int j = 1; j < mTabs.size(); j++) { TabInfo info = (TabInfo) mActionBar.getTabAt(j).getTag(); if (info.title.matches(mTabs.get(j).title)) { return j; } } return -1; } public SherlockFragment getItem(int position) { TabInfo info = mTabs.get(position); return (SherlockFragment)Fragment.instantiate(mContext, info.clss.getName(), info.args); } /*This method reads the user selection for a new tab and sets that tab as * the new current focus.*/ public void onPageSelected(int position) { mActionBar.setSelectedNavigationItem(position); selectInSpinnerIfPresent(position, true); } private void selectInSpinnerIfPresent(int position, boolean animate) { try { View actionBarView = findViewById(R.id.abs__action_bar); if (actionBarView == null) { int id = getResources().getIdentifier("action_bar", "id", "android"); actionBarView = findViewById(id); } Class<?> actionBarViewClass = actionBarView.getClass(); Field mTabScrollViewField = actionBarViewClass.getDeclaredField("mTabScrollView"); mTabScrollViewField.setAccessible(true); Object mTabScrollView = mTabScrollViewField.get(actionBarView); if (mTabScrollView == null) { return; } Field mTabSpinnerField = mTabScrollView.getClass().getDeclaredField("mTabSpinner"); mTabSpinnerField.setAccessible(true); Object mTabSpinner = mTabSpinnerField.get(mTabScrollView); if (mTabSpinner == null) { return; } Method setSelectionMethod = mTabSpinner.getClass().getSuperclass().getDeclaredMethod("setSelection", Integer.TYPE, Boolean.TYPE); setSelectionMethod.invoke(mTabSpinner, position, animate); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } public void onPageScrollStateChanged(int state) {} public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} /* This is the method that actually draws the newest tab onto the screen when * it is selected.*/ public void onTabSelected(Tab tab, FragmentTransaction ft) { mViewPager.setCurrentItem(tab.getPosition()); sp = getSharedPreferences("prefs", MODE_PRIVATE); SharedPreferences.Editor preferencesEditor = sp.edit(); preferencesEditor.putInt("lastPosition", mViewPager.getCurrentItem()); preferencesEditor.commit(); } public void onTabUnselected(Tab tab, FragmentTransaction ft) {} public void onTabReselected(Tab tab, FragmentTransaction ft) {} public void onTabReselected(Tab tab, android.app.FragmentTransaction ft) {} public void onTabUnselected(Tab tab, android.app.FragmentTransaction ft) {} } 
+6
source share
2 answers

Well, you want to use one fragment class, say BaseFragment , instead of several classes; This can be done by passing a string (identifier) ​​for this new fragment. You also have code in all of these snippets, so it would be preferable to use the new approach.

However, passing the identifier to this BaseFragment will cause its code to be messy, and you will have to handle all these if...else when it is really associated with that identifier and your code is actually the same because you have to move the code specific fragments in this BaseFragment. Therefore, in this approach there is no added value. You can store all of your fragments and actually use this “identifier” when you add tabs to select the correct fragment to add.


As for your code, which runs in many of your snippets. This is a very simple approach:

Create a BaseFragment class that extends the fragment. (I'm naive here) Add a common() function that will do this common thing. Finally, let all of your fragments extend this base fragment instead of a fragment. Now you can call common() . (Again you will need common1() , common2() , ... ).

+1
source

For your classes you need to use Reflection; this is not enough to just have a string name; so you probably have to write something like:

 String clas = tabs[j] + "Fragment"; String total = "com.davekelley.polling." + clas; Class<?> theClass = Class.forName (total); 

For a resource, you cannot just write something like String res = "R.string" + tabs[j]; , you will need to use the getIdentifier() ; see Dynamic Download Android resource .

+1
source

Source: https://habr.com/ru/post/917403/


All Articles