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