Encapsulation of BaseActivity, the Android Base Class

Keywords: network

abstract

This article summarizes the BaseActivity written by predecessors, and also adds, deletes and alters it in the process of development. Now I summarize it.

A lot of knowledge has been learned and used for reference in this article. Know about Thank you for your big answer from iYng. By the way, link to the original text:
https://www.zhihu.com/question/47045239/answer/105086885

text

Generally speaking, the BaseActivities of different projects are different, and there are many differences according to different business logic and functional requirements. Here are some summaries, as follows:

View correlation

In general, there are many findViewById methods used in Activity, and each time the type conversion is mandatory. This will be very cumbersome. If it is encapsulated in BaseActivity, it will save time:

protected <T extends View> T findView(int id) {
    return (T) findViewById(id);
}

This makes it easy to use Linear Layout llContent = findView (R.id.ll_content) as long as BaseActivity is inherited; it eliminates the hassle of many types of conversion.

Then, when it comes to views, you need to initialize views and data in general activities, so you can expose two methods, initView() and initData():

public abstract void initData();

public abstract void initView();

Then call it in setContentView, usually first initView, then initData:

 @Override
public void setContentView(@LayoutRes int layoutResID) {
    super.setContentView(layoutResID);
    initView();
    initData();
}

@Override
public void setContentView(View view) {
    super.setContentView(view);
    initView();
    initData();
}

In this way, initView() and initData() must be rewritten in subclasses, and the logic can be clearer, otherwise everything will be in onCreate, which will be very confusing.

User Module (Business Related [Optional]

However, as long as the general app is logged in, there will be user modules and some network operations based on user id, so user modules can expose some methods in BaseActivity, such as user id acquisition:

public int getUid() {
    if (UserManager().getUid() != null) {
        if (UserManager().getUid().equals("")) {
            return 0 ;
        }
    }
    return Integer.parseInt(UserManager().getUid()) ;
}

This is to return the user id stored in Shared Preference. In the case of a large number of user IDs being used, such encapsulation is necessary and more convenient to use. Of course, if it's just a display app, it won't necessarily be needed, maybe it's superfluous.

Inter-Interface Jump Reference Transfer

Many times, activities pass parameters between them, so you can encapsulate a parameter processing function initParam(), in Base Activity's onCreate to determine whether there are parameters passed in;

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

    ......

    if (savedInstanceState != null) {
            initParam(savedInstanceState);
        } else if (getIntent() != null && getIntent().getExtras() != null) {
            initParam(getIntent().getExtras());
    }
}

Then the initParam() method is exposed to subclasses:

protected void initParam(Bundle bundle) {

}

This method does not have to be rewritten, because there are not as many references as you think, and there is no need to force rewriting this method.

Debugging and toast

In general, an isDebug is defined in the Application class to determine whether debugging (developer mode) is turned on or not:

public class TApplication extends Application {

    public static boolean isDebug = true ;
    public static String APP_NAME  ;
}

In BaseActivity, we can use isDebug as the main switch and then control whether debugging information is displayed or not.

public void TLog(String msg) {
    if (isDebug) {
        Log.d(APP_NAME, msg);
    }
}

Would it be nice to close the debugging with this button without deleting the logs in the project one by one?

Every time Toast is used, Toast.makeText(...).show(); is it annoying? Then it can be encapsulated in BaseActivity, such as:

public void toast(String text) {
    ToastUtils.show(text);
}

public void toast(int resId) {
    ToastUtils.show(String.valueOf(resId));
}

Here, ToastUtils is a Toast encapsulation class, which is supposed to be understood by everyone. Then, when all the subclasses are in use, just write a toast("xxxx") freely. Of course, you can also package Toast.LENGTH_LONG and Toast.LENGTH_SHORT together. Encapsulate them on demand.

Other

Soft keyboard

In some app s, user input scenarios will be more, at this time, the hiding of the soft keyboard will be more useful. After user input, or user clicks on the screen blank, they should hide the soft keyboard. In this case, we can consider writing the hiding method in BaseActivity:

/**
 * Hidden Software Disk
 */
public void hideSoftInput() {
    InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
    if (getCurrentFocus() != null) {
        imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
    }
}

/**
 * Hide the software disk by clicking on the blank space outside the soft keyboard
 * @param ev
 * @return
 */
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        View v = getCurrentFocus();
        if (ToolUtil.isShouldHideInput(v, ev)) {

            InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            if (imm != null) {
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            }
        }
        return super.dispatchTouchEvent(ev);
    }
    // Necessary, otherwise all components will not have TouchEvent
    if (getWindow().superDispatchTouchEvent(ev)) {
        return true;
    }
    return onTouchEvent(ev);
}

/**
 * Display Soft Keyboard
 */
public void showInputMethod(){
    if (getCurrentFocus() != null){
        InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
        imm.showSoftInputFromInputMethod(getCurrentFocus().getWindowToken(),0);
    }
}

The above three methods are also very practical. The dispatchTouchEvent method does not need to be called manually, as long as there is a click event and the click is outside the soft keyboard and EditText area, the soft keyboard will be hidden.

Prevent quick clicks

Sometimes, users (especially test apes) will click on apps crazily. The reason and significance of this action is not clear, but we can set up to prevent the damage and burden of fast clicking on apps:

 private boolean fastClick() {
    long lastClick = 0;
    if (System.currentTimeMillis() - lastClick <= 1000) {
        return false;
    }
    lastClick = System.currentTimeMillis();
    return true;
}

This will only respond once in a second, and Ma Ma will no longer have to worry about my hand cramps.
So how to use it? Take a chestnut for example. You can judge it in onClick interface.

/** View Click**/
public abstract void widgetClick(View v);

@Override
public void onClick(View v) {
    if (fastClick())
        widgetClick(v);
}

In this way, the subclass must override the method of widgetClick(View v), which is actually encapsulated outside of onClick. Use widgetClick as onClick. Personally, I don't like to write a bunch of abstract methods in BaseActivity, so this widgetClick can be referred to as appropriate.

Page Jump: startActivity, startActivity ForResult

This is also optional and can be encapsulated to achieve parameters such as this or XXXXX.this without passing each jump:

 public void startActivity(Class<?> clz) {
    startActivity(clz, null);
}

/**
 *Page jump with data
 * @param clz
 * @param bundle
 */
public void startActivity(Class<?> clz, Bundle bundle) {
    Intent intent = new Intent();
    intent.setClass(this, clz);
    if (bundle != null) {
        intent.putExtras(bundle);
    }
    startActivity(intent);
}

/**
 * Containing Bundle opens the editing interface through Class
 *
 * @param cls
 * @param bundle
 * @param requestCode
 */
public void startActivityForResult(Class<?> cls, Bundle bundle,
                                   int requestCode) {
    Intent intent = new Intent();
    intent.setClass(this, cls);
    if (bundle != null) {
        intent.putExtras(bundle);
    }
    startActivityForResult(intent, requestCode);
}

These methods are still very convenient, you can use startActivity(MainActivity.class) simply; you can also pass Bundle parameters.

Is Full Screen Allowed

Set a member variable mAllowFullScreen:

/** Is Full Screen Allowed**/
private boolean mAllowFullScreen = true;

By judging mAllowFullScreen in BaseActivity's onCreate method to set whether full screen is allowed:

if (mAllowFullScreen) {
            this.getWindow().setFlags(
                    WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
        }

Then expose a method for subclasses to set mAllowFullScreen:

 public void setAllowFullScreen(boolean allowFullScreen) {
    this.mAllowFullScreen = allowFullScreen;
}

Setting Immersion Status Bar

Same as setting full screen:

/** Immersion status bar**/
private boolean isSetStatusBar = true;

Then in BaseActivity's onCreate:

if (isSetStatusBar) {
            steepStatusBar();
        }

Then the steepStatusBar() method is defined to set the immersive status bar:

private void steepStatusBar() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        // Transparent status bar
        getWindow().addFlags(
                WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        // Transparent navigation bar
        getWindow().addFlags(
                WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
    }
}

It's time to judge the system version. Only above KITKAT can it work.
Finally, the subclass is exposed and the isSetStatusBar value is set:

/**
 * Whether to set immersion status bar
 * @param isSetStatusBar
 */
public void setSteepStatusBar(boolean isSetStatusBar) {
    this.isSetStatusBar = isSetStatusBar;
}

Set whether screen rotation is allowed

As with the previous two ideas, by judging variables, set it in onCreate:

/** Is Screen Rotation Prohibited**/
private boolean isAllowScreenRoate = false;

The onCreate method in BaseActivity:

if (!isAllowScreenRoate) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        } else {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }

Finally, the exposure method sets the value of isAllowScreenRoate:

public void setScreenRoate(boolean isAllowScreenRoate) {
    this.isAllowScreenRoate = isAllowScreenRoate;
}

summary

Most of the above methods are commonly used. Some of them are not very common, but it will be more convenient to write. Take this article as a summary, and then use it on demand.

Posted by show8bbs on Thu, 11 Jul 2019 17:34:42 -0700