An overview of the

Inheritance relationships

Java.lang.object ↳ android. Support. The v4. App. FragmentsCopy the code
Java.lang.object ↳ android. The content. The Context ↳ android. The content. ContextWrapper ↳ android. The ContextThemeWrapper ↳ android.app.ActivityCopy the code

The fragment is directly inherited from object and has nothing to do with any of the four components.

The “connection” between the two

In the process of project development, there will be many modules, and each module realizes several specific similar functions. Here, we can use one activity to realize a module, and the corresponding pages of several similar functions in this module will be processed with several fragments.

Scenario analysis

rendering

As shown in the figure, the user login registration module has three functions: login, registration and password change (corresponding to three interfaces respectively); From the registration page, click “Return” to return to the main login interface. Click “Forget password” to return to the “Change password” interface. Similarly, click “Return” to return to the main login interface.

The code analysis

From the above analysis, it can be seen that only one activity (corresponding module) and one to three fragments (corresponding to three functional interfaces) are needed here.

activity

/** * Created by zhulei on 16/5/27. */
public abstract class AppActivity extends AppCompatActivity{

    // Since some jumps do not require parameters, there is no need for abstract methods here
    protected void handleIntent(Intent intent){};protected abstract int getContentViewId(a);
    protected abstract BaseFragment getFirstFragment(a);
    protected abstract int getFragmentContainerId(a);

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Write vertical
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        // Handle intEnts to retrieve the parameters they carry
        if(getIntent() ! =null){
            handleIntent(getIntent());
        }
        / / set the contentView
        setContentView(getContentViewId());
        // Add the first fragment at the bottom of the stack
        if (getSupportFragmentManager().getBackStackEntryCount() == 0) {if(getFirstFragment() ! =null){
                pushFragment(getFirstFragment());
            }else {
                throw new NullPointerException("getFirstFragment() cannot be null"); }}}public void pushFragment(BaseFragment fragment){
        if(fragment ! =null){ getSupportFragmentManager().beginTransaction() .replace(getFragmentContainerId(), fragment) .addToBackStack(((Object)fragment).getClass().getSimpleName()) .commitAllowingStateLoss(); }}public void popFragment(a){
        if (getSupportFragmentManager().getBackStackEntryCount() > 1){
            getSupportFragmentManager().popBackStack();
        }else{ finish(); }}@Override
    public boolean onSupportNavigateUp(a) {
        if (getSupportFragmentManager().getBackStackEntryCount() > 1){
            getSupportFragmentManager().popBackStack();
            return true;
        }
        return super.onSupportNavigateUp();
    }

    @Nullable
    @Override
    public Intent getSupportParentActivityIntent(a) {
        Intent intent = super.getSupportParentActivityIntent();
        if (intent == null){
            finish();
        }
        return intent;
    }

    // Rollback key processing
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (KeyEvent.KEYCODE_BACK == keyCode){
            if (getSupportFragmentManager().getBackStackEntryCount() == 1){
                finish();
                return true; }}return super.onKeyDown(keyCode, event); }}Copy the code

Here are five things abstracted:

  • Set the parameter (handleIntent ()) that is carried into the activity before the contentView is processed.
  • Set the ContentView, where the layout ID of the ContentView is abstracted for each concrete class to implement (getContentViewid ());
  • Add a fragment to your activity. You need to implement getFirstFragment () externally and add the firstfragment at initialization.
  • Popfragment, throw fragment from rollback stack;
  • Handling the fallback, here I use the actionbar, dealt with the two combined popfragment callback: onSupportNavigateUp () and getSupportParentActivityIntent ();

Take a look at the base code:

/** * Created by zhulei on 16/5/27. */
public abstract class BaseActivity extends AppActivity {
    @Override
    protected int getContentViewId(a) {
        return R.layout.activity_base;
    }

    @Override
    protected int getFragmentContainerId(a) {
        returnR.id.fragment_container; }}Copy the code

This is just implementing a basic layout

Finally, see the code for this module’s activity:

/** * Created by zhulei on 16/5/27. */
public class LoginActivity extends BaseActivity {

    @Override
    protected BaseFragment getFirstFragment(a) {
        return newLoginFragment(); }}Copy the code

Here you can see that it is very simple, because the basic work is done at the bottom, and this is only responsible for the main interface fragment to be added

fragment

/** * Created by zhulei on 16/5/27. */
public abstract class AppFragment extends Fragment {

    protected abstract int getLayoutId(a);

    protected abstract void initView(View view, Bundle savedInstanceState);
    protected void releaseView(a){};protected abstract void initActionBar(ActionBar actionBar);

    protected BaseActivity getHoldingActivity(a){
        if (getActivity() instanceof BaseActivity){
            return (BaseActivity)getActivity();
        }else {
            throw new ClassCastException("activity must extends BaseActivity"); }}protected void pushFragment(BaseFragment fragment){
        getHoldingActivity().pushFragment(fragment);
    }

    protected void popFragment(BaseFragment fragment){
        getHoldingActivity().popFragment();
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(getLayoutId(), container, false);
        initView(view, savedInstanceState);
        return view;
    }

    @Override
    public void onStart(a) {
        super.onStart();
        ActionBar actionBar = getHoldingActivity().getSupportActionBar();
        if(actionBar ! =null){ initActionBar(actionBar); }}@Override
    public void onDestroyView(a) {
        super.onDestroyView(); releaseView(); }}Copy the code

Six things are abstracted here:

  • Initview interface is provided before onCreateView to initialize all internal controls externally;
  • Oncreareview, where you need a layout ID of the view, get it from getLayoutId();
  • I’m using an Actionbar here, so I’m exposing an initActionBar interface to the outside world to set up the UI interaction on the Actionbar;
  • Pushfragment, which is published here because most of the interaction is inside the fragment
  • Popfragment, same as 4;
  • Releaseview, in onDestroyView to be handled externally (if necessary);

Look at baseFragment:

/** * Created by zhulei on 16/5/27. */
public abstract class BaseFragment extends AppFragment {

    @Override
    protected void initView(View view, Bundle savedInstanceState) {
        ButterKnife.bind(this, view);
    }

    @Override
    protected void initActionBar(ActionBar actionBar) {
        actionBar.setHomeButtonEnabled(true);
        actionBar.setDisplayHomeAsUpEnabled(true);
        actionBar.setDisplayShowHomeEnabled(true); }}Copy the code

Thanks to my use of the annotation framework ButterKnife, which I inject directly here, and the BASIC actions for UI interaction in the ActionBar

Then look at the two fragments corresponding to the three functions (login: loginfragment, register and modify password: verifyfragment).

/** * Created by zhulei on 16/5/27. ** create by zhulei on 16/5/27
public class LoginFragment extends BaseFragment {

    @BindView(R.id.check_visible)
    CheckBox mCheckVisible;
    @BindView(R.id.user_name)
    TextInputEditText mUserName;
    @BindView(R.id.user_password)
    TextInputEditText mUserPsw;

    @OnClick(R.id.login_btn)
    public void onLoginBtnClicked(a){}@OnClick(R.id.register_btn)
    public void onRegisterBtnClicked(a){
        pushFragment(VerifyFragment.newInstance(VerifyFragment.REGISTER));
    }
    @OnClick(R.id.forget_button)
    public void onForgetBtnClicked(a){
        pushFragment(VerifyFragment.newInstance(VerifyFragment.RESET));
    }

    @Override
    protected int getLayoutId(a) {
        return R.layout.fragment_login;
    }

    @Override
    protected void initActionBar(ActionBar actionBar) {
        super.initActionBar(actionBar); actionBar.setTitle(R.string.login); }}Copy the code
/** * Created by zhulei on 16/5/27. ** registered. Change password */
public class VerifyFragment extends BaseFragment {

    public static final String ARG_VERIFY = "verify";

    public static final int REGISTER = 0;
    public static final int RESET = 1;

    private int mAction;

    @Override
    protected int getLayoutId(a) {
        return R.layout.fragment_verify;
    }

    @Override
    protected void initActionBar(ActionBar actionBar) {
        super.initActionBar(actionBar);
        if (mAction == RESET){
            actionBar.setTitle(R.string.reset_psw);
        }else{ actionBar.setTitle(R.string.register); }}public static VerifyFragment newInstance(int action){
        VerifyFragment fragment = new VerifyFragment();
        Bundle arg = new Bundle();
        arg.putInt(ARG_VERIFY, action);
        fragment.setArguments(arg);
        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(getArguments() ! =null){ mAction = getArguments().getInt(ARG_VERIFY); }}}Copy the code

Here because of the registration and change password interface UI, only the difference between the text display, you can pass the mark bit to deal with the UI display logic;

conclusion

This blog post has a lot of code, but for a project, such a setup will have a positive impact on the subsequent addition of modules. There is no reason to add some other common logic that needs to be initialized in base (such as setting the color of the Actionbar). If there are shortcomings, please also point out more.

See my Github for more details:Android exercise mini project