java - 具有多种不同 fragment 类型的 Android BaseFragment 类

标签 java android android-fragments

我创建了一个基本 fragment 类,用于处理设置工具栏标题、注册 fragment 附加时间、设置菜单图标和其他一些事情。我的问题是,我决定使用 PreferencesFragmentCompat 作为我的设置 fragment ,并且我无法同时扩展我的 BaseFragment 和 androids PreferencesFragmentCompat。在这里使用接口(interface)没有帮助,因为我的 BaseFragment 有很多功能,而且我不想将其复制到每个 fragment 类中。通常要扩展两个类,您只需在两个单独的文件中执行即可,但因为两个文件都已经扩展了 Android Fragment 类,所以我不知道这是怎么可能的。有更好的方法吗?

enter image description here

基础 fragment :

 public abstract class BaseFragment extends Fragment {

    protected View rootView;
    protected AppSettings settings;
    protected LayoutInflater inflater;

    public static void startFragment(Activity activity, BaseFragment newFragment) {
        FragmentManager fragManager = ((AppCompatActivity) activity).getSupportFragmentManager();
        BaseFragment currentFragment = (BaseFragment) fragManager.findFragmentById(R.id.fragment_container);

        // Start the transactions
        FragmentTransaction transaction = fragManager.beginTransaction();
        transaction.replace(R.id.fragment_container, newFragment);

        // If there is already a fragment then we want it on the backstack
        if (currentFragment != null) {
            transaction.addToBackStack(null);
        }

        // Show it
        transaction.commit();
    }

    @TargetApi(21)
    private void lockMode(boolean start) {
        if (android.os.Build.VERSION.SDK_INT >= 16) {
            if (start) {
                getActivity().startLockTask();
            } else {
                getActivity().stopLockTask();
            }
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Get a reference to the app settings
        settings = AppSettings.getInstance(getActivity());

        // Don't want keyboard to stay open between fragments
        hideKeyboard();

        ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
        if (actionBar != null) {
            if (toolbarElevation()) {
                actionBar.setElevation(4 * getActivity().getResources().getDisplayMetrics().density);
            } else {
                actionBar.setElevation(0);
            }
        }

        setHasOptionsMenu(true);
    }

    @Override
    public void onResume() {
        super.onResume();

        // Set the title up
        Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar);
        toolbar.setTitle(getTitle());

        // Enable the home button in the action bar
        ((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayShowHomeEnabled(true);

        // Change the home button icon for menu or back
        if (showUpNavigation()) {
            toolbar.setNavigationIcon(R.drawable.ic_navigation_back_white);
        } else {
            toolbar.setNavigationIcon(R.drawable.ic_menu_white);
        }

        if (isAppInLockTaskMode() == true && pinnedMode() == false) {
            lockMode(false);
        }

        setDrawerMenu();
    }

    public boolean getAuthRequired() {
        return true;
    }

    public boolean isBackAllowed() {
        return true;
    }

    public boolean toolbarElevation() {
        return true;
    }

    public String getTitle() {
        return "ISOPED";
    }

    public boolean pinnedMode() {
        return false;
    }

    public boolean showUpNavigation() {
        return false;
    }

    public void hideKeyboard() {
        InputMethodManager inputManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);

        // check if no view has focus:
        View v = getActivity().getCurrentFocus();
        if (v == null) {
            return;
        }

        inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
    }

    public void setDrawerMenu() {
        NavigationView navigationView = (NavigationView) getActivity().findViewById(R.id.drawer_navigation);
        Integer menuID = null;
        Integer currentMenuId = null;

        if (settings.isType(AppSettings.TYPES.PERSONAL)) {
            menuID = R.menu.drawer_personal;
        } else if (settings.isType(AppSettings.TYPES.PROFESSIONAL)) {
            if (getAuthRequired() == true) {
                menuID = R.menu.drawer_professional_locked;
            } else {
                menuID = R.menu.drawer_professional_unlocked;
            }
        }

        if (menuID != null) {
            if (navigationView.getTag() != null) {
                currentMenuId = (Integer) navigationView.getTag();
            }

            if (currentMenuId == null || navigationView.getMenu().size() == 0 || currentMenuId != menuID) {
                navigationView.getMenu().clear();
                navigationView.inflateMenu(menuID);
                navigationView.setTag(Integer.valueOf(menuID));
            }
        }
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        menu.clear();

        if (settings.isType(AppSettings.TYPES.PROFESSIONAL) && pinnedMode() && false == isAppInLockTaskMode()) {
            inflater.inflate(R.menu.pin_menu, menu);
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        DrawerLayout drawer = (DrawerLayout) getActivity().findViewById(R.id.drawer_layout);

        switch (item.getItemId()) {
            case android.R.id.home:
                if (showUpNavigation()) {
                    getActivity().onBackPressed();
                } else {
                    drawer.openDrawer(GravityCompat.START);
                }
                return true;
            case R.id.menu_pin:
                if (isAppInLockTaskMode()) {
                    PinDialog dialog = new PinDialog((AppCompatActivity) getActivity(), new NavigationCallback((AppCompatActivity) getActivity()) {
                        @Override
                        public void run() {
                            lockMode(false);
                        }
                    });
                    dialog.show();
                } else {
                    lockMode(true);
                }
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private boolean isAppInLockTaskMode() {
        ActivityManager activityManager;

        activityManager = (ActivityManager)
                getActivity().getSystemService(Context.ACTIVITY_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // For SDK version 23 and above.
            return activityManager.getLockTaskModeState()
                    != ActivityManager.LOCK_TASK_MODE_NONE;
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            // When SDK version >= 21. This API is deprecated in 23.
            return activityManager.isInLockTaskMode();
        }

        return false;
    }
}

最佳答案

这是一个很好的例子,您应该在其中应用 Joshua Bloch "Favor composition over inheritance" 习语。

您可以将应用于 BaseFragment 的所有逻辑委托(delegate)给某个类 FragmentHelper:

public class FragmentHelper {

    private final Fragment fragment;

    public FragmentHelper(Fragment fragment) {
        this.fragment = fragment;
    }

    public void create(Bundle bundle) {
      // `BaseFragment`'s code goes here
    }

    public void resume() {
      // `BaseFragment`'s code goes here
    }

    ...
}

现在在你的 BaseFragment 中:

public class BaseFragment {

    private FragmentHelper fragmentHelper;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        fragmentHelper = new FragmentHelper(this);
        fragmentHelper.create(savedInstanceState);
    }

    @Override
    public void onResume() {
        fragmentHelper.resume();
    }
}

同样的情况也应该应用于扩展 PreferenceFragment 的类。

因此,您可以避免代码重复。

引用:

  • Joshua Bloch - 《Effective Java》第二版,第 16 项。

关于java - 具有多种不同 fragment 类型的 Android BaseFragment 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43238529/

相关文章:

android - 我的 Android 应用程序需要 Play 商店中的 "Other"权限 - 这意味着什么以及如何修复?

android - ViewPager 以编程方式设置当前页面

java - Box Java SDK - 404 在公开可用文档中未找到文件

java - 在运行时编译java代码

java - 有没有办法让 tika 在找到匹配项后停止解析文件?

java - 异步任务,此标记后预期的维度

android - 确定主屏幕的 appwidgets 空间网格大小

java - 从生成的jaxb类中的抽象Java类实现抽象方法(继承)

Android View 绑定(bind) - 多模块项目中 Unresolved 引用

android - 如何将 Activity 代码更改为 fragment 代码?