在Android中正确实现MVVM

geo*_*_mx 14 android mvvm

我一直在努力寻找在Android中实现MVVM的正确方法.

整个想法对我来说仍然模糊,模式是有一个单独的层,逻辑完成(ViewModel).

这段代码只能动画一堆片段所在的背景的alpha.

public class StartActivity extends AppCompatActivity implements EntryFragment.EntryFragementListener {

    private static final float MINIMUM_ALPHA = 0.4f;
    private static final float MAXIMUM_ALPHA = 0.7f;

    @State
    float mCurrentAlpha = MINIMUM_ALPHA;

    @State
    String mCurrentTag = EntryFragment.TAG;

    private ActivityStartBinding mBinding;

    private StartViewModel mStartViewModel = new StartViewModel();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_start);
        mBinding.setStartViewModel(mStartViewModel);
        mBinding.bgBlackLayer.setAlpha(mCurrentAlpha);

        if (getSupportFragmentManager().findFragmentByTag(mCurrentTag) == null) {
            switch (mCurrentTag) {
                case EntryFragment.TAG:
                    setEntryFragment();
                    break;
                case FreeTrialFragment.TAG:
                    setFreeTrialFragment();
                    break;
            }
        }
    }

    private void setEntryFragment() {
        mCurrentAlpha = MINIMUM_ALPHA;
        mCurrentTag = EntryFragment.TAG;
        FragmentManager fm = getSupportFragmentManager();
        Fragment fragment = new EntryFragment();
        fm.beginTransaction().
                add(R.id.fragment_content, fragment, EntryFragment.TAG).commit();
    }

    private void setFreeTrialFragment() {
        mCurrentTag = FreeTrialFragment.TAG;
        Fragment fragment = new FreeTrialFragment();
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.setCustomAnimations(R.anim.anim_enter_right, R.anim.anim_exit_left, R.anim.anim_enter_left, R.anim.anim_exit_right);
        ft.replace(R.id.fragment_content, fragment, FreeTrialFragment.TAG);
        ft.addToBackStack(FreeTrialFragment.TAG);
        ft.commit();
        StartViewModel.setAnimation(mBinding.bgBlackLayer,true, MAXIMUM_ALPHA);
    }

    private void setForgotPasswordFragmet() {
    }

    private void setLoginFragment() {
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        StartViewModel.setAnimation(mBinding.bgBlackLayer,true, MINIMUM_ALPHA);
        mCurrentAlpha = MINIMUM_ALPHA;
    }

    @Override
    public void onEntryLoginButton() {
        setLoginFragment();
    }

    @Override
    public void onEntryFreeTrialButton() {
        setFreeTrialFragment();
    }
}
Run Code Online (Sandbox Code Playgroud)

-ViewModel只执行动画中的逻辑-Fragments有一个监听器将事件传递给活动-Binding有助于定义视图

public class StartViewModel {

    public ObservableBoolean hasToAnimate = new ObservableBoolean(false);
    public float alpha;

    @BindingAdapter(value={"animation", "alpha"}, requireAll=false)
    public static void setAnimation(View view, boolean hasToAnimate, float alpha) {
        if (hasToAnimate) {
            view.animate().alpha(alpha);
        }
    }    
}
Run Code Online (Sandbox Code Playgroud)

问题是,是否所有逻辑都存在于视图模型中,包括片段事务,方向变更管理等等?有没有更好的方法来实现MVVM?

Yur*_*sap 8

至于我 - MVVM,MVP和其他非常酷的模式真的很酷的家伙没有简单的收据/流量.当然,您有很多教程/建议/模式和方法如何实现它们.但这实际上就是所有编程的内容 - 您只需要提出一个满足您需求的解决方案.根据您的开发人员愿景,您可以将许多原则应用于您的解决方案,以便更容易/更快地开发/测试/支持.
在你的情况下,我认为最好将这种逻辑移动到Fragment过渡(正如你所做的那样setFreeTrialFragment()),它更易于定制和使用.但是,如果你的方法应该保持不变 - 现有方法是正常的.实际上@BindingAdapter更适合xml属性然后直接使用.
至于我 - 所有的UI逻辑都应该驻留在Activity中,主要目的是将业务逻辑与UI分开.因为所有的动画,片段交易等都是在活动内部处理的 - 这是我的方法.ViewModel - 负责通知视图相应模型中的某些内容已更改,并且视图应自行安排这些更改.在完美的世界中,你应该能够实现像双向绑定这样的流行术语,但并不总是必要的,并且不应总是在ViewModel内部处理UI更改.像往常一样,过多的MVVM对你的项目不利.它可以导致意大利面条代码,"它来自哪里?","如何回收视图?" 和其他流行的问题.因此,它应该只用于让生活变得更加生动,而不是让一切都变得理想,因为像其他所有模式一样,它会让人头疼,有人会仔细查看你的代码会说"OVERENGINEERING !! 11".

每个请求,MVP示例:

这里有一些有用的文章:

简短示例(通用),您应该适合您的架构:

包装代表:
在此输入图像描述

实施:

型号:

public class GalleryItem {

    private String mImagePath;
    //other variables/getters/setters
}
Run Code Online (Sandbox Code Playgroud)

主持人 :

//cool presenter with a lot of stuff
public class GalleryPresenter {

    private GalleryView mGalleryView;

    public void loadPicturesBySomeCreteria(Criteria criteria){
        //perform loading here
        //notify your activity
        mGalleryView.setGalleryItems(yourGaleryItems);
    }

    //you can use any other suitable name
    public void bind(GalleryView galleryView) {
        mGalleryView = galleryView;
    }

    public void unbind() {
        mGalleryView = null;
    }

    //Abstraction for basic communication with activity.
    //We can say that this is our protocol
    public interface GalleryView {
        void setGalleryItems(List<GalleryItem> items);

    }
}
Run Code Online (Sandbox Code Playgroud)

查看:

public class NiceGalleryView extends View {
    public NiceGalleryView(Context context) {
        super(context);
    }

    public NiceGalleryView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    // TODO: 29.12.16 do your stuff here
}
Run Code Online (Sandbox Code Playgroud)

并且cource活动代码:

public class GalleryActivity extends AppCompatActivity implements GalleryPresenter.GalleryView {

    private GalleryPresenter mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gallery);
        //init views and so on
        mPresenter = new GalleryPresenter();
        mPresenter.bind(this);

    }

    @Override
    public void setGalleryItems(List<GalleryItem> items) {
        //use RecyclerView or any other stuff to fill your UI
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mPresenter.unbind();
    }
}
Run Code Online (Sandbox Code Playgroud)

还要注意,在使用MVP时,您甚至有很多不同的方法.我只想强调,我更喜欢在活动中初始化视图,而不是将它们从活动中传递出去.您可以通过界面进行管理,这不仅适用于开发,甚至适用于仪器测试.