Android项目框架之MVP+Dagger.Android+LiveData

个人博客:haichenyi.com。感谢关注

  之前的那个系列从零开始搭建一个主流的项目框架(一 ~ 八),尽管把dagger2中inject activity 优化了一下,但是依然显得繁琐,每一个activity里面都要写一个inject方法。Dagger.Android只用在基类里面inject一次,子类里不用管,直接用。

  还有就是之前的MVP架构,每次更新页面的时候都要在每个页面对应的Contract——View里面写方法,在P层去实现然后在Activity里面也要实现一遍,这样太繁琐,现在用上LiveData,解决了这个问题,并且LiveData的优点:

  1. 能保证UI与数据保持一致。LiveData是观察者模式,与EventBus一样,一个地方注册observer,另一个地方去响应,调用setValue()方法通知页面更新。
  2. 与activity的生命周期同步,不会出现内存泄漏。LiveData的observer对象是与lifeCycle绑定的,当lifeCycle对象被onDestory的时候,observer对象也被clean up了
  3. 当activity处于stop activity状态时,不会崩溃。当observer处于inactive状态时,例如,activity被按了返回键,observer将不会响应来自LiveData的事件
  4. 不需要更多的手动管理生命周期。LiveData负责自动管理生命周期
  5. 保证数据是最新的。比如处于后台的activity,返回到前台是时,他会自动获取最新数据。
  6. 响应屏幕旋转等配置变化。
  7. 共享资源。新建一个专门的LiveData管理类,通过单例模式,在项目的任意位置都可以访问的到。

官方介绍

Dagger.Android

依赖的库

    implementation 'com.google.dagger:dagger:2.17'
    implementation 'com.google.dagger:dagger-android:2.16'
    implementation 'com.google.dagger:dagger-android-support:2.16'
    annotationProcessor 'com.google.dagger:dagger-android-processor:2.16'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.16'

集成

  1. 集成到application中
  2. 集成到activity中
  3. 集成到fragment中

Application

新建Application
package com.haichenyi.aloe.demo1.base;

import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.support.multidex.MultiDex;

import com.haichenyi.aloe.demo1.di.component.DaggerAppComponent;
import com.haichenyi.aloe.tools.LogUtils;
import com.haichenyi.aloe.tools.ToastUtils;

import javax.inject.Inject;

import dagger.android.AndroidInjector;
import dagger.android.DispatchingAndroidInjector;
import dagger.android.HasActivityInjector;

/**
 * @Title: BaseApp
 * @Des: Application
 * @Author: haichenyi
 * @Date: 2018/11/20 0020
 * @Email: [email protected]
 */
public class BaseApp extends Application implements HasActivityInjector {

    @Inject
    DispatchingAndroidInjector dispatchingActivityInjector;

    @Override
    public void onCreate() {
        super.onCreate();
        setInstance(this);
        DaggerAppComponent.create().inject(this);
    }
    
    @Override
    public AndroidInjector activityInjector() {
        return dispatchingActivityInjector;
    }
}

  实现HasActivityInjector接口,这部分可以直接复制过去就可以了

新建AppComponent,AppModule
@Singleton
@Component(modules = {AndroidInjectionModule.class, AppModule.class})
public interface AppComponent {
    void inject(BaseApp baseApp);
}

@Module
public class AppModule {

}

这都没有什么要说的,看好注解就行了。

Activity

新建BaseActivity
public class BaseActivity extends SupportActivity{
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
    }
}

  在super前面添加AndroidInjection.inject(this);

新建ActComponent
package com.haichenyi.aloe.demo1.di.component;

import com.haichenyi.aloe.demo1.base.BaseActivity;

import dagger.Subcomponent;
import dagger.android.AndroidInjectionModule;
import dagger.android.AndroidInjector;

/**
 * @Title: ActComponent
 * @Des:
 * @Author: haichenyi
 * @Date: 2018/11/21 0021
 * @Email: [email protected]
 */
@Subcomponent(modules = {AndroidInjectionModule.class})
public interface ActComponent extends AndroidInjector {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder {

    }
}

  这里实现AndroidInjector接口,这里的泛型传你的BaseActivity,然后添加抽象的Builder类

新建AllActivitiesModule
package com.haichenyi.aloe.demo1.di.module;

import com.haichenyi.aloe.demo1.di.component.ActComponent;

import dagger.Module;
import dagger.android.ContributesAndroidInjector;

/**
 * @Title: AllActivitiesModule
 * @Des:
 * @Author: haichenyi
 * @Date: 2018/11/21 0021
 * @Email: [email protected]
 */
@Module(subcomponents = ActComponent.class)
public abstract class AllActivitiesModule {

}

  这里的module注解里面传你上面创建的ActivityComponent类

重要的事情说三遍,不然报错都不知道为什么

重要的事情说三遍,不然报错都不知道为什么

重要的事情说三遍,不然报错都不知道为什么

  接下来,在你创建的AppComponent类里面,的注解@Component,添加AllActivitiesModule.class,如下:

@Singleton
@Component(modules = {AndroidInjectionModule.class, AppModule.class, AllActivitiesModule.class})
public interface AppComponent {
    void inject(BaseApp baseApp);
}

  然后,你新建Activity就直接继承你创建的BaseActivity,然后,在你上面创建的AllActivitiesModule里面添加如下代码即可:

package com.haichenyi.aloe.demo1.di.module;

import com.haichenyi.aloe.demo1.di.component.ActComponent;
import com.haichenyi.aloe.demo1.ui.activity.FragmentActivity;
import com.haichenyi.aloe.demo1.ui.activity.SwipeBackActivity;
import com.haichenyi.aloe.demo1.ui.activity.WelcomeActivity;

import dagger.Module;
import dagger.android.ContributesAndroidInjector;

/**
 * @Title: AllActivitiesModule
 * @Des:
 * @Author: haichenyi
 * @Date: 2018/11/21 0021
 * @Email: [email protected]
 */
@Module(subcomponents = ActComponent.class)
public abstract class AllActivitiesModule {

    @ContributesAndroidInjector
    abstract WelcomeActivity contributeWelcomeActivityInjector();

    @ContributesAndroidInjector
    abstract FragmentActivity contributeFragmentActivityInjector();

    @ContributesAndroidInjector
    abstract SwipeBackActivity contributeSwipeBackActivityInjector();

}

  这里是我的demo里面创建的三个activity:WelcomeActivity,FragmentActivity,SwipeBackActivity,这样就可以用了。

Fragment

重要的事情说三遍,不然报错都不知道为什么

重要的事情说三遍,不然报错都不知道为什么

重要的事情说三遍,不然报错都不知道为什么

  官方文档上面介绍的是app包下面fragment的集成方式,实现的是HasFragmentInjector接口。

  我这里介绍的是v4包下面的fragment的集成方式,绝大多数情况下,我们用的都是v4包下面的fragment,实现的是HasSupportFragmentInjector接口。

  强调一遍,一个是HasSupportFragmentInjector,一个是HasFragmentInjector,带Support的是v4包下的,不带的是app包下的。

  进入正题,fragment依赖activity存在,我们这里,需要对包含fragment的activity做额外的操作。如下:

新建fragment需要依赖的activity
package com.haichenyi.aloe.demo1.ui.activity;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;

import com.haichenyi.aloe.demo1.R;
import com.haichenyi.aloe.demo1.base.BaseActivity;
import com.haichenyi.aloe.demo1.base.BaseFragment;
import com.haichenyi.aloe.demo1.presenter.EmptyPresenter;
import com.haichenyi.aloe.demo1.ui.frag.Fragment01;
import com.haichenyi.aloe.demo1.ui.frag.Fragment02;
import com.haichenyi.aloe.demo1.ui.frag.Fragment03;
import com.haichenyi.aloe.demo1.ui.frag.Fragment04;
import com.jaeger.library.StatusBarUtil;

import java.util.ArrayList;

import javax.inject.Inject;

import dagger.android.AndroidInjector;
import dagger.android.DispatchingAndroidInjector;
import dagger.android.support.HasSupportFragmentInjector;

/**
 * @Title: FragmentActivity
 * @Des:
 * @Author: haichenyi
 * @Date: 2018/11/29 0029
 * @Email: [email protected]
 */
public class FragmentActivity extends BaseActivity implements HasSupportFragmentInjector {
    @Inject
    DispatchingAndroidInjector fragmentInjector;

    ArrayList list;
    ViewPager viewPager;

    @Override
    protected int layout(@Nullable Bundle savedInstanceState) {
        setAttachToolbar(false);
        setFullScreen(false);
        return R.layout.activity_fragment;
    }

    @Override
    protected void initView() {
        super.initView();
        viewPager = findViewById(R.id.viewPager);
    }

    @Override
    protected void initData() {
        super.initData();
        StatusBarUtil.setTranslucentForImageViewInFragment(this, null);
        StatusBarUtil.hideFakeStatusBarView(this);

        list = new ArrayList<>();
        list.add(new Fragment01());
        list.add(new Fragment02());
        list.add(new Fragment03());
        list.add(new Fragment04());
        viewPager.setOffscreenPageLimit(3);
        viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                return list.get(position);
            }

            @Override
            public int getCount() {
                return list.size();
            }
        });
    }

    @Override
    public AndroidInjector supportFragmentInjector() {
        return fragmentInjector;
    }
}

  如上,实现的是HasSupportFragmentInjector,然后实现supportFragmentInjector方法即可。

  记得,这里继承的是BaseActivity,要在前面创建的AllActivitiesModule中,把这个FragmentActivity添加进去。

新建FragmentActivity,需要的Component
package com.haichenyi.aloe.demo1.di.component;

import com.haichenyi.aloe.demo1.ui.activity.FragmentActivity;

import dagger.Subcomponent;
import dagger.android.AndroidInjectionModule;
import dagger.android.AndroidInjector;

/**
 * @Title: FragActivityComponent
 * @Des:
 * @Author: haichenyi
 * @Date: 2018/11/29 0029
 * @Email: [email protected]
 */
@Subcomponent(modules = {AndroidInjectionModule.class})
public interface FragActivityComponent extends AndroidInjector {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder {

    }
}

  这里的泛型传你上面创建的FragmentActivity

新建FragmentActivity,需要的Module
package com.haichenyi.aloe.demo1.di.module;

import android.app.Activity;

import com.haichenyi.aloe.demo1.di.component.FragActivityComponent;
import com.haichenyi.aloe.demo1.ui.activity.FragmentActivity;

import dagger.Binds;
import dagger.Module;
import dagger.android.ActivityKey;
import dagger.android.AndroidInjector;
import dagger.multibindings.IntoMap;

/**
 * @Title: FragActivityModule
 * @Des:
 * @Author: haichenyi
 * @Date: 2018/11/29 0029
 * @Email: [email protected]
 */
@Module(subcomponents = FragActivityComponent.class)
public abstract class FragActivityModule {

    @Binds
    @IntoMap
    @ActivityKey(FragmentActivity.class)
    abstract AndroidInjector.Factory bindDaggerFragmentActivityInjectorFactory(FragActivityComponent.Builder builder);

}
新建BaseFragment
public class BaseFragment extends Fragment{

    @Override
    public void onAttach(Context context) {
        AndroidSupportInjection.inject(this);
        super.onAttach(context);
    }

}

  在super前面添加AndroidSupportInjection.inject(this);

新建BaseFragment需要的Component
package com.haichenyi.aloe.demo1.di.component;

import com.haichenyi.aloe.demo1.base.BaseFragment;

import dagger.Subcomponent;
import dagger.android.AndroidInjectionModule;
import dagger.android.AndroidInjector;

/**
 * @Title: BaseFragComponent
 * @Des:
 * @Author: haichenyi
 * @Date: 2018/11/21 0021
 * @Email: [email protected]
 */
@Subcomponent(modules = {AndroidInjectionModule.class})
public interface BaseFragComponent extends AndroidInjector{
    @Subcomponent.Builder
    public abstract class Builder extends AndroidInjector.Builder{

    }
}
新建BaseFragment需要的Module
package com.haichenyi.aloe.demo1.di.module;

import com.haichenyi.aloe.demo1.di.component.BaseFragComponent;
import com.haichenyi.aloe.demo1.ui.frag.Fragment01;
import com.haichenyi.aloe.demo1.ui.frag.Fragment02;
import com.haichenyi.aloe.demo1.ui.frag.Fragment03;
import com.haichenyi.aloe.demo1.ui.frag.Fragment04;

import dagger.Module;
import dagger.android.ContributesAndroidInjector;

/**
 * @Title: AllFragmentModule
 * @Des:
 * @Author: haichenyi
 * @Date: 2018/11/29 0029
 * @Email: [email protected]
 */
@Module(subcomponents = BaseFragComponent.class)
public abstract class AllFragmentModule {

    @ContributesAndroidInjector
    abstract Fragment01 contributeFragment01Injector();

    @ContributesAndroidInjector
    abstract Fragment02 contributeFragment02Injector();

    @ContributesAndroidInjector
    abstract Fragment03 contributeFragment03Injector();

    @ContributesAndroidInjector
    abstract Fragment04 contributeFragment04Injector();
}

  跟activity一样,把继承BaseFragment的fragment,都添加到这里来

  然后就是把这个AllFragmentModule添加到AppComponent的@Component注解上就可以了。

至此

至此

至此

  到这里,这个dagger.android就添加依赖完了,后面我们新建activity,直接继承BaseActivity就可以直接用了。新建fragment,直接继承BaseFragment就可以直接用了

LiveData

依赖的库

现在项目创建完,都是自带的。lifecycle,不需要额外添加依赖库

用法

  很简单,观察者模式,类似于EventBus的用法。一个地方注册,一个地方触发。

MutableLiveData liveData1 = new MutableLiveData<>();
liveData1.observe(this, new Observer() {
            @Override
            public void onChanged(@Nullable String s) {
                Log.v("wz",s);
            }
        });
liveData1.setValue("123");

  简单的来说,就像上面这样,新建一个LiveData对象,注册一个observer,然后,setValue去触发这个onChange方法。

  LiveData提供了两个方法触发onChange方法,一个是setValue:在当前线程触发回调;另一个postValue:在主线程触发回调。

  前面我们说过共享资源,LiveData是全局的,我们可以新建一个管理类,我这里给出来了。通过map简单的封装了一下添加,移除的方法(通过键,或者通过类名称移除当前类的所有观察者),项目里面有,有点长,就不贴出来了,我贴出来方法

  在我的BaseActivity或者BaseFragment,添加如下方法:

/**
     * 设置LiveData的Observer(需要通过类名称手动移除Observer)
     *
     * @param aClass   当前类对象
     * @param key      键
     * @param observer 监听器
     * @param       数据类型
     */
    protected synchronized  void setObserver(final Class aClass, final String key, final Observer observer) {
        BaseLiveData liveData = new BaseLiveData<>();
        liveData.observe(this, observer);
        LiveDataManager.getInstance().putLiveData(aClass, key, liveData);
    }

    /**
     * 设置LiveData的Observer(不需要通过类名称手动移除Observer)
     *
     * @param key      键
     * @param observer 监听器
     * @param       数据类型
     */
    protected synchronized  void setObserver(final String key, final Observer observer) {
        BaseLiveData liveData = new BaseLiveData<>();
        liveData.observe(this, observer);
        LiveDataManager.getInstance().putLiveData(key, liveData);
    }

  在子类里面调用:

@Override
    protected void initData() {
        super.initData();
        this.setObserver("internet", ToastUtils::showTipMsg);
        this.setObserver("internet2", ToastUtils::showTipMsg);
    }

  在P层里面去触发回调:

package com.haichenyi.aloe.demo1.presenter;

import com.haichenyi.aloe.demo1.base.BasePresenter;
import com.haichenyi.aloe.demo1.base.BaseView;
import com.haichenyi.aloe.demo1.impl.LiveDataManager;

import javax.inject.Inject;

/**
 * @Title: WelcomePresenter
 * @Des:
 * @Author: haichenyi
 * @Date: 2018/11/21 0021
 * @Email: [email protected]
 */
public class WelcomePresenter extends BasePresenter {

    @Inject
    public WelcomePresenter() {
        //Dagger2 generate object.
    }

    public void getData() {
        LiveDataManager.getInstance().getLiveData("internet").callbackUI("123");
    }

    public void getData2() {
        LiveDataManager.getInstance().getLiveData("internet2").callbackUI("321");
    }
}

  如上所示,我们的P层代码与之前的框架相比,简洁了很多。

项目链接

你可能感兴趣的:(Android项目框架之MVP+Dagger.Android+LiveData)