The author:JessYan

Address: http://www.jianshu.com/p/75a5c24174b2

Disclaimer: This article isJessYan original, published with its permission, please do not reprint without the permission of the original author

preface

It’s been more than two months since the last article was published, and I haven’t written in the past two months, but I’ve been updating my MVPArms framework and moving it toward a configurable integration framework

How to package BaseActivity with the ToolBar in just a few lines of code

My MVPArms framework has also been updated with a new feature:

Implement some common logic that needs to be encapsulated in a BaseActivity Fragment by inheriting it, and listen for all activities and fragments in the App , including tripartite libraries, and can insert code into its life cycle

How can I get Activty to implement the Toolbar without writing a line of code without using inheritance

Why do I advocate less encapsulation and BaseActvity inheritance

One of the most important things about BaseActivity encapsulation, besides being difficult to manage, is that Java can only be inherited. What do you do if your Activity needs to use a tripartite library that must let you inherit from its Activity, but you also need some of the BaseActivity features that you’ve wrapped yourself? You can’t change the Activity from the tripartite library, so you have to change your BaseActivity to inherit from the tripartite library, but when you change BaseActivity, you find that there are many activities that inherit from BaseActivity When you’re forced to inherit an Activity from a library that you don’t need, you have to rewrap a BaseActivity

When this happens more and more, you have more and more BaseActiviys, so it’s a vicious circle. So I advocate not only App developers to wrap BaseActivity less and use inheritance less, but also three-party library developers to wrap BaseActivity less and use inheritance less. Why? Because when an App developer’s Activity needs to use two tripartite libraries, both of which need to inherit their Activity, what do you tell the App developer to do? So as the author of a configurable integration framework, I can’t ask developers to change my BaseActivity directly and I have to solve this problem through other extensions

Get into the business

To solve the above problem, we need to think about why we must encapsulate BaseActivity by inheriting some of the Activity’s public logic, but can’t encapsulate the public logic in other classes?

The answer is simple, because we must use some lifecycle of the Activity and execute the corresponding logic in the corresponding lifecycle. This is why we cannot implement it by encapsulating other classes. Finding the key to the problem, let’s start with the lifecycle

ActivityLifecycleCallbacks

Refers to the Activity of the life cycle, then I will introduce an interface, it is called ActivityLifecycleCallbacks, don’t know how students learn it before? It doesn’t matter if you don’t know it. Let me introduce it now

ActivityLifecycleCallbacks is declared in the Application of an internal interface, let’s take a look at its structure

public interface ActivityLifecycleCallbacks {

       void onActivityCreated(Activity activity, Bundle savedInstanceState);        void onActivityStarted(Activity activity);        void onActivityResumed(Activity activity);        void onActivityPaused(Activity activity);        void onActivityStopped(Activity activity);        void onActivitySaveInstanceState(Activity activity, Bundle outState);        void onActivityDestroyed(Activity activity);    }

What’s the use of this interface?

Application provides a registerActivityLifecycleCallbacks () method, need the incoming parameters is the ActivityLifecycleCallbacks Interface, as you guessed it, is that after you call this method and pass in the interface implementation class, the system will call the corresponding method in the implementation class after each Activity completes the corresponding lifecycle, remember each!

At this point we’ll come up with a requirement implementation that shuts down all activities! You are also adding BaseActivity to the collection in BaseActivity onCreate by inheriting BaseActivity.

If you open an Activity from another library in your App, that library cannot inherit your BaseActivity, what do you do? How to do?

ActivityLifecycleCallbacks will come in handy at this moment, all Activity as long as the execution of the life cycle of the App will call the corresponding method of interface implementation class, Then you can add all activities to the collection in onActivityCreated, so I can iterate through the collection and finish all activities, whether you’re an Activity in a tripartite library or not

Using ActivityLifecycleCallbacks achieve the ToolBar

Set the NoActionBar theme

<style name=”AppTheme” parent=”Theme.AppCompat.Light.NoActionBar”>

   <item name=”colorPrimary”>@color/colorPrimary</item>    <item name=”colorPrimaryDark”>@color/colorPrimaryDark</item>    <item name=”colorAccent”>@color/colorAccent</item></style>

<application

android:allowBackup=”true” android:icon=”@mipmap/ic_launcher” android:label=”@string/app_name” android:theme=”@style/AppTheme”> … </application>

Create the layout for the ToolBar and reference it

Don’t worry about the layout of my Toolbar, this is just the implementation of the idea, you can change the layout of your own

<me.jessyan.art.widget.autolayout.AutoToolbar

xmlns:android=”http://schemas.android.com/apk/res/android” xmlns:app=”http://schemas.android.com/apk/res-auto” xmlns:tools=”http://schemas.android.com/tools” android:id=”@+id/toolbar” android:layout_width=”match_parent” Attr /colorPrimary” app:contentInsetStart=”0dp” > // Toolbar <com.zhy.autolayout.AutoRelativeLayout android:id=”@+id/toolbar_back” android:layout_width=”wrap_content” android:layout_height=”match_parent” android:gravity=”left” > <ImageView android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:layout_marginLeft=”30px” android:layout_marginRight=”30px” android:layout_centerVertical=”true” android:src=”@mipmap/login_return”/> </com.zhy.autolayout.AutoRelativeLayout> // Toolbar title name <TextView Android :id=”@+ ID /toolbar_title” Android: Layout_width =”wrap_content” android:layout_height=”wrap_content” android:textSize=”18dp” android:textColor=”#fff” android:layout_gravity=”center” tools:text=”MVPArt”/></me.jessyan.art.widget.autolayout.AutoToolbar>

Include the layout above the Activity layout you need for the Toolbar

<? The XML version = “1.0” encoding = “utf-8”? >

<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android” xmlns:tools=”http://schemas.android.com/tools” Android :layout_width=”match_parent” Android: Layout_height =”match_parent” Android :orientation=”vertical” > // Will Toolbar Wrapped in < the include layout = “@ layout/include_title” / > <. Android support. The v4. Widget. SwipeRefreshLayout android:id=”@+id/swipeRefreshLayout” android:layout_width=”match_parent” android:layout_height=”match_parent” android:paddingLeft=”15px” android:paddingTop=”15px” > <android.support.v7.widget.RecyclerView android:id=”@+id/recyclerView” android:layout_width=”match_parent” android:layout_height=”match_parent” android:scrollbars=”vertical” tools:listitem=”@layout/recycle_list” /> </android.support.v4.widget.SwipeRefreshLayout></LinearLayout>

Implement ActivityLifecycleCallbacks and register to the Application

The following is a simple setup for the ToolBar, and you can configure more complex functionality yourself, as powerful as your imagination

public class WEApplication extends BaseApplication{

@Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {// Set the Activity toolbar and title globally. This is as powerful as you can imagine (activity.findViewById(R.id.toolbar) ! = null) {// Find the Toolbar and replace Actionbar if (activity instanceof appactivity) {((appactivity). activity).setSupportActionBar((Toolbar) activity.findViewById(R.id.toolbar)); ((AppCompatActivity) activity).getSupportActionBar().setDisplayShowTitleEnabled(false); } else { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { activity.setActionBar((android.widget.Toolbar) activity.findViewById(R.id.toolbar)); activity.getActionBar().setDisplayShowTitleEnabled(false); } } } if (activity.findViewById(R.id.toolbar_title) ! = null) {// Find the Toolbar title bar and set the title name ((TextView) activity.findViewById(R.id.toolBar_title)).settext (activity.getTitle()); } if (activity.findViewById(R.id.toolbar_back) ! FindViewById (R.id.toolbar_back).setonClickListener (v -> {// Locate the Toolbar back button and set the click event to close the Activity. activity.onBackPressed(); }); }}… }); }}

Set the Label in androidmanifest.xml

One day you want to have aActivityimplementationToolBar, just do two things:

1. In the layout file

<include layout=”@layout/include_title”/>

2. In androidmanifest.xml, set a Label for the Activity. This Label is the title name

<activity

     android:name=”.mvp.ui.activity.SplashActivity”      android:label=”@string/app_name”  />

Here’s a global way to configure all activities to enter and exit the transition animation, setting the Theme property

<style name=”AppTheme” parent=”Theme.AppCompat.Light.NoActionBar”>

<! — Customize your theme here. –> <item name=”colorPrimary”>@color/colorPrimary</item> <item name=”colorPrimaryDark”>@color/colorPrimaryDark</item> <item name=”colorAccent”>@color/colorAccent</item> <item name=”android:windowAnimationStyle”>@style/AnimaActivity</item> </style> <style name=”AnimaActivity”> <item name=”android:activityOpenEnterAnimation”>@anim/translate_right_to_center</item> <item name=”android:activityOpenExitAnimation”>@anim/translate_center_to_left</item> <item name=”android:activityCloseEnterAnimation”>@anim/translate_left_to_center</item> <item name=”android:activityCloseExitAnimation”>@anim/translate_center_to_right</item></style>

You don’t have to inherit any activities at all, and you can implement a lot of complicated functions without writing a single line of code

Many public logic can be written to ActivityLifecycleCallbacks, as long as dare to try, you have more rich imagination, there is more powerful

extension

Because when all activities are executing their life cycles, ActivityLifecycleCallbacks corresponding method will be called, some Activity may not need the Toolbar, such as tripartite library Activity, although the onActivityCreated method, determine the Toolbar The logic for setting the ToolBar is not executed if the Id of the ToolBar is not found, but it is not elegant enough

Custom Interface

In this case, instanceof is a custom interface. If you don’t implement this custom interface, then you don’t need to set the ToolBar, which is much more elegant

To store data

inActivityLifecycleCallbacksIn which allActivityAfter the corresponding lifecycle is executed, its corresponding method is called, so we must distinguish this ActivityWhich one is itActivity, soActivityLifecycleCallbacks Every method is passed inActivityAs a parameter, we can distinguishActivity

public void onActivityCreated(Activity activity, Bundle savedInstanceState){

   if (activity instanceof xxxActivity){        ….    }}

But there is a problem the ActivityLifecycleCallbacks is common, when an Activity in the onCreate method creates an object, we need in this Activity onDestroy execution How to use this object? Since each Activity to produce this object, we can’t store the object in the ActivityLifecycleCallbacks ah

Now you can use the activity. getIntent to store some data. The Intent holds a Bundle object that stores some data.

For example

We need to use ActivityLifecycleCallbacks implementation to all Activity execution ButterKnife. Bind (Activity)

A Bundle can store Parcelable objects

public class ActivityBean extends Parcelable {

   private Unbinder unbinder;    public void setUnbinder(Unbinder unbinder){        thid.unbinder = unbinder;    }        public Unbinder getUnbinder(){        return unbinder;    }}

In ActivityLifecycleCallbacks perform corresponding logic

public class WEApplication extends BaseApplication{

@Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { ActivityBean bean = new ActivityBean(); Unbinder unbinder = ButterKnife.bind(activity); bean.setUnbinder(unbinder); activity.getIntent().putExtra(“ActivityBean”, bean); }… @Override public void onActivityDestroyed(Activity activity) { ActivityBean bean = activity.getIntent().getParcelableExtra(“ActivityBean”); bean.getUnbinder().unbind(); }}}); }}

The Activity needs to initialize something or provide some data

BaseActivity sometimes requires a child Activity to implement some method or provide some data, such as initView, which returns the layout ID in setContentView() and implements initData Initialize some data, so that you can do not need the Activity to re-write the onCreate, achieve the purpose of the specification, such use ActivityLifecycleCallbacks also can do it, so what should I do?

You only need the Activity to implement a custom interface

public interface IActivity {

int initView(); void initData(); }

Then in ActivityLifecycleCallbacks onActivityCreated call these methods, can be achieved

public class WEApplication extends BaseApplication{

@Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { if (activity instanceof IActivity) { activity.setContentView(((IActivity)activity).initView()); ((IActivity)activity).initData(); }}… }}); }}

Matters needing attention

Due to all the methods in the ActivityLifecycleCallbacks call time is the Activity of corresponding Super method of life cycle, so in the Activity’s onCreate method using the setContentView Must be super. OnCreate (savedInstanceState); Before, otherwise findViewById would not be found in the onActivityCreated method

@Override

   protected void onCreate(Bundle savedInstanceState) {        setContentView(R.layout.activity_home);        super.onCreate(savedInstanceState);    }

You can also use a custom interface in combination with the above method by calling initView and finding the ToolBar in findViewById()

Accidentally implement so many functions that you had to write into BaseActivity to achieve through inheritance, and find that there is no BaseActivity, and there is no uncomfortable place, suddenly feel so awesome 🤒, please follow me, although I do not update my blog regularly, but the quality of my updated articles is absolutely guaranteed!

conclusion

It is worth noting that the ActivityLifecycleCallbacks can register multiple, can be added according to different situations according to needs to carry on the combination of various ActivityLifecycleCallbacks so as to achieve the different needs, and Okhttp Interceptor similar

Now all Activity and Fragment calls in the entire App will be intercepted as long as they are called during their lifetimes. Applying to my framework can dynamically insert arbitrary code into the corresponding lifetimes of all activities and fragments, such as LeakCanary RefWatcher. Watch (fragment) can also be inserted directly into the fragment of a three-party library, and there is no need to modify the base class if any code changes

The ideas and solutions mentioned above have been used in my MVPArms Framework, want to know more detailed usage can go to see my framework implementations, all I mentioned above, are some of the most simple requirements, believe that has toppled the implementation of the way before, and more elegant (because I am standing on three sides put forward the function of the library designers point of view, I must be the only inheritance opportunities for other activities If you feel less elegant than the previous approach, forget it.) and don’t worry about Java’s single-inheritance constraints

But don’t think, ActivityLifecycleCallbacks can only achieve these simple requirements, it can also used more complex functions, one still before me, As long as you dare to try, how rich your imagination, here is how powerful, ideas and solutions have been introduced very clearly, as for the realization of more requirements depends on everyone to try, although I am not sure that all the functions of the previous package BaseActivity through inheritance can be ActivityLifecycleCallbacks replaced, but I think most of the functionality or can achieve

Everyone is sharing their packaging BaseActivity before, maybe one day you begin to share their writing ActivityLifecycleCallbacks! When the previous way can not meet our needs, dare to jump out of the traditional way, try different solutions, to broaden their horizons, grow their own technology, MVPArms is constantly working hard!

I would also like to say that everyone has different ideas and perspectives. It is good for you to agree with me. Don’t agree with me or not, will not affect my unknown, at least I was using my train of thought innovation, to solve some I think it is necessary to solve the problem, and the previous article, I just like to use different ideas to solve the same problem, whether or not you think it possible, I thought at least you think with this unacceptable realized I wanted to reach the effect, how to see Benevolence sees wisdom, if our thinking does not collide, then please cherish the fruits of my labor

I’ll say one more thing about some of the comments, RegisterActivityLifecycleCallbacks () is the internal ActivityLifecycleCallbacks added to a collection, so ActivityLifecycleCallbacks can add multiple, and ActivityLifecycleCallbacks just comes to the collection when project initialization, anything does not initialize, and adding the listener a truth, using the observer pattern, so don’t say so will how how Application code, The Okhttp Interceptor has more code, which was also added during Okhttp initialization. Do you think it will have any impact?


Hello, my name is Jessyan. If you like my articles, you can follow me on the following platforms

  • GitHub:  https://github.com/JessYanCoding

  • The Denver nuggets: https://juejin.cn/user/976022014539326

  • Jane: http://www.jianshu.com/u/1d0c0bc634db

  • Weibo: http://weibo.com/u/1786262517

Recommended reading

1, Android frosted glass blur effect, I use OpenCV to do

Android DataBinding & MVVM

3. Why don’t programmers have professional certifications