We want to develop an APP. The first task is to build the package structure, build the framework, encapsulate the base class, import the third-party libraries into the project and so on. Today we will talk about how to complete this process.
(Note: Everyone has their own code style, so there is no good or bad code that suits them.)
Through this article, you can Get to the following skills:
1. How to build the package structure of new projects;
2. Encapsulation of common base classes for new projects.
text
Construction of package structure
When it comes to subcontracting, everyone must have their own way. The most common way is to put activities together, fragment s together and so on. Of course, I also subcontract in this way (hey hey). Below is my subcontract chart:
Here I use MVP mode, so there is a MVP in the subcontract. If the custodians don't need mvp, it's simpler. Then replace MVP and put model, activity and fragment outside.
Here constants are constants and widget s are custom view s. Looking at the name of other bags, you can see what's going to be put in them, so there's no need to explain too much here. Just take a look at it, gentlemen.
Encapsulation of Common Base Classes
The following is the focus of this article, encapsulation of common base classes. Let's start with Application, in order, without much nonsense, with code first:
/**
* @author: X_Meteor
* @description: Customized BaseApplication
* @version: V_1.0.0
* @date: 2017/4/21 16:34
* @email: lx802315@163.com
*/
public class BaseApplication extends Application {
/**
* Maintaining a global context object
*/
public Context context;
/**
* Used to store current users (if any)
*/
// private static UserInfo currentUser;
//Singleton pattern
private static BaseApplication myApplication = null;
public static BaseApplication getInstance() {
return myApplication;
}
/**
* Get the current user object
*
* @param currentUser
*/
// public UserInfo getCurrentUser() {
// UserInfo user = currentUser;
// if (user != null) {
// return user;
// }
// return null;
// }
/**
* Setting the current user object
*
*/
// public void setCurrentUser(UserInfo currentUser) {
// this.currentUser = currentUser;
// }
/**
* Define a tag
*/
private static String TAG;
@Override
public void onCreate() {
super.onCreate();
//Define TAG as the class name of the current class
TAG = this.getClass().getSimpleName();
//Since the Application class itself is singleton, it can be processed directly as follows.
myApplication = this;
context = getApplicationContext();
//Global exception handling
if(Constants.isCollectException){
CrashHandlerUtils crashHandler = CrashHandlerUtils.getInstance();
crashHandler.init(getApplicationContext());
}
}
}
As you can see, there are three main things we do in Base Application:
- Get the current system user (if there is a user module)
- A TAG for printing log s is defined, with the class name of the current class as the value.
- A global error exception class is defined to catch exceptions when an exception occurs in a program. (Exception handling classes will be posted later)
Next, BaseActivity:
/**
* @author: Meteor
* @description: Base Classes of All Activities
* @version: V 1.0
* @date: 2016/12/28 0028 15:33
* @company:
* @email: lx802315@163.com
*/
public abstract class BaseActivity extends AppCompatActivity {
//Declare a build object to create a warning dialog
private AlertDialog.Builder builder;
//Used to create a progress bar dialog box
private ProgressDialog dialog;
//Used for printing log
private final String TAG = "BaseActivity";
//Declare an activity management stack
private static Stack<Activity> activities = new Stack<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Add activities to the activity stack
activities.add(this);
//Fixed screen orientation
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
//Set the input method not to open by default when the activity starts
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
initRootView();
ButterKnife.bind(this);
initView();
initData();
initListener();
//Print the current class name
String msg = this.getClass().getName();
LogUtils.print(msg);
}
/**
* Initialize the root layout file
*/
public abstract void initRootView();
/**
* Initialization control
*/
public abstract void initView();
/**
* Initialization data
*/
public abstract void initData();
/**
* Initialization interface
*/
public abstract void initListener();
/**
* Implement an immersive notification bar so that the color of the notification bar is the same as that of the APP title.
*/
protected void immersiveNotification() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//Navigation Bar Transparency
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//Bottom virtual button transparent
// getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
}
/**
* Display a warning dialog box, no button, you need to set it yourself
*
* @param title Title
* @param msg content
* @param flag Can we cancel it?
* @return
*/
protected AlertDialog.Builder showAlertDialog(String title, String msg, boolean flag) {
if (builder == null) {
//Create a builder object
builder = new AlertDialog.Builder(this);
builder.setTitle(title).setMessage(msg).setCancelable(flag);
}
return builder;
}
/**
* Function: Cancel Warning Dialog Box
*/
protected void dismissAlertDialog(android.app.AlertDialog alertDialog) {
if (alertDialog != null) {
//Cancel warning dialog box
alertDialog.dismiss();
}
}
/**
* Function: Display a progress bar dialog box
*/
protected void showProcessDialog(String title, String msg, boolean falg) {
if (dialog == null) {
dialog = new ProgressDialog(this);
}
dialog.setTitle(title);
dialog.setMessage(msg);
dialog.setCancelable(falg);
dialog.show();
}
/**
* Function: Cancel a progress bar dialog box
*/
protected void dismissProcessDialog() {
if (dialog != null) {
dialog.dismiss();
}
}
/**
* Determine whether the user has logged in
*
* @return true For successful landing false for no landing
*/
protected boolean isLogin() {
//Do your own logical processing here
return true;
}
/**
* Exit all activities and exit the current application
*/
public static void exitApplication() {
for (Activity activity : activities) {
if (activity != null) {
activity.finish();
}
}
System.exit(0);
android.os.Process.killProcess(android.os.Process.myPid());
}
}
As you can see, we did a lot of work in BaseActivity:
- Define an Alert Dialog, Warning Dialog
- Define a ProgressDialog, Progress Dialog
- A method to judge whether a user is logged in or not is implemented.
- Maintaining an activity stack and opening up a way to exit all activities
- Four abstract methods are defined: initRootVeiw();initView;initData();initListener.
(Note: The initRootView here is specifically defined to use butterknife, and we need to put setContentView in an integrated subclass.)
Specifically, you can see the code: onCreate () of BaseActivity
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Add activities to the activity stack
activities.add(this);
//Fixed screen orientation
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
//Set the input method not to open by default when the activity starts
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
initRootView();
//Add ButterKnife Annotation Framework
ButterKnife.bind(this);
initView();
initData();
initListener();
//Print the current class name
String msg = this.getClass().getName();
LogUtils.print(msg);
}
Inherited subclass, MainActivity:
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void initRootView() {
setContentView(R.layout.activity_main);
}
@Override
public void initView() {
}
@Override
public void initData() {
}
@Override
public void initListener() {
}
}
Next, BaseFragment:
/**
* @author: Meteor
* @description: Base Classes of All Fragment s
* @version:
* @date: 2016/12/28 0028 16:16
* @company:
* @email: lx802315@163.com
*/
public abstract class BaseFragment extends Fragment {
//Define a recycle pool for repeated views
private View contentView = null;
/**
* Fragment Is the current state visible
*/
protected boolean isVisible;
private AlertDialog.Builder builder;
private AlertDialog alertDialog;
private ProgressDialog dialog;
//Binding for Butterknife
Unbinder unbinder;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
if (contentView == null) {//Judging whether the recycling pool is empty
contentView = initLayout(inflater, container, false);
unbinder = ButterKnife.bind(this, contentView);
}
if (contentView != null) {
unbinder = ButterKnife.bind(this, contentView);
return contentView;
}
return super.onCreateView(inflater, container, savedInstanceState);
}
/**
* Initialize the layout of Fragment, which is called when an attempt is to be created
*
* @param inflater Layout Filler
* @param container ViewGroup
* @param b sign
* @return view Return View
*/
protected abstract View initLayout(LayoutInflater inflater, ViewGroup container, boolean b);
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//Initialization data
initData(savedInstanceState);
}
/**
* Initialize data and call this method when ViewCreate is created
* @param savedInstanceState
*/
protected abstract void initData(Bundle savedInstanceState);
@Override
public final void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (getUserVisibleHint()) {
isVisible = true;
onVisible();
} else {
isVisible = false;
onInvisible();
}
}
/**
* So
*/
protected void onVisible() {
lazyLoad();
}
/**
* Invisible
*/
protected void onInvisible() {
}
/**
* Delayed loading
* Subclasses must override this method
*/
protected abstract void lazyLoad();
@Override
public final void onDestroyView() {
//Remove the current view to prevent repeated loading of the same view causing the program to flip back
((ViewGroup) contentView.getParent()).removeView(contentView);
super.onDestroyView();
unbinder.unbind();
}
/**
* Determine whether the user has logged in
*
* @return true For successful landing false for no landing
*/
protected boolean isLogin() {
return false;
}
/**
* Function: Display a warning dialog box
*/
protected void showAlertDialog(String title,String text){
if (builder==null){
//Create a builder object
builder = new AlertDialog.Builder(getContext());
builder.setTitle(title).setMessage(text).setCancelable(false);
builder.setPositiveButton("Set up", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//Jump to System Network Settings
Intent intent = new Intent(Settings.ACTION_WIRELESS_SETTINGS);
startActivity(intent);
}
}).setNegativeButton("cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//Exit Virtual Machine
System.exit(0);
}
});
}
alertDialog = builder.show();
}
/**
* Function: Cancel Warning Dialog Box
*/
protected void dismissAlertDialog(){
if (alertDialog!=null){
//Cancel warning dialog box
alertDialog.dismiss();
}
}
/**
* Function: Display a progress bar dialog box
*/
protected void showProcessDialog(String title,String msg,boolean falg){
if(dialog==null){
dialog = new ProgressDialog(getContext());
}
dialog.setTitle(title);
dialog.setMessage(msg);
dialog.setCancelable(falg);
dialog.show();
}
/**
* Function: Cancel a progress bar dialog box
*/
protected void dismissProcessDialog(){
if(dialog!=null){
dialog.dismiss();
}
}
public interface BackHandledInterface {
public abstract void setSelectedFragment(BaseFragment selectedFragment);
}
}
In addition to the display dialog box similar to BaseActivity, there are mainly several lazy loading methods, and the knowledge about lazy loading can be explained by Baidu.
Subclass inheritance is used as follows:
/**
* @author: X_Meteor
* @description: Class Description
* @version: V_1.0.0
* @date: 2017/4/22 16:37
* @email: lx802315@163.com
*/
public class homeFragment extends BaseFragment {
@Override
protected View initLayout(LayoutInflater inflater, ViewGroup container, boolean b) {
View rootView = inflater.inflate(R.layout.activity_main, null);
return rootView;
}
@Override
protected void initData(Bundle savedInstanceState) {
}
@Override
protected void lazyLoad() {
}
}
The most commonly used base classes here are encapsulated. Of course, there is no best one but the most suitable one. The project has been uploaded to the following address:
Demo
That's all for today. I'll write about the simple encapsulation of rxjava2 + retrofit2's network request framework later. Welcome to discuss learning together.