美文网首页面试题android收集android
Android mvvm架构demo(DataBinding+L

Android mvvm架构demo(DataBinding+L

作者: 灰丨色 | 来源:发表于2019-07-27 16:43 被阅读0次

1.实现效果

实现页面加载Bing每日一图的功能

2.项目结构

image(忽略没有按分类创建).png

3.实现过程

1.注入依赖
//ViewModel与LiveData
implementation "android.arch.lifecycle:extensions:1.1.1"
//图片加载
implementation 'com.github.bumptech.glide:glide:4.9.0'
//网络请求
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
implementation 'io.reactivex.rxjava2:rxjava:2.1.12'
//GSON解析
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'


同时需要启用DataBinding
android {
        ..........
    dataBinding {
        enabled = true
    }
}
2.接口请求

https://cn.bing.com/HPImageArchive.aspx?format=js&idx=1&n=1
其中 format为请求格式,包含JSON、XML等,
idx为请求ID,n为每次请求的个数
(在AndroidManifest.xml文件内添加网络权限)
接口返回参数样式如下

{"images":[{"startdate":"20190724","fullstartdate":"201907241600","enddate":"20190725","url":"/th?id=OHR.CathedralMountBuffalo_ZH-CN4341947983_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp","urlbase":"/th?id=OHR.CathedralMountBuffalo_ZH-CN4341947983","copyright":"清晨暴雨中的Cathedral,澳大利亚布法罗山 (© Ilya Genkin/Alamy)","copyrightlink":"https://www.bing.com/search?q=Cathedral&form=hpcapt&mkt=zh-cn","title":"","quiz":"/search?q=Bing+homepage+quiz&filters=WQOskey:%22HPQuiz_20190724_CathedralMountBuffalo%22&FORM=HPQUIZ","wp":true,"hsh":"5c4b7b7d11456918494bc1ecea07951c","drk":1,"top":1,"bot":1,"hs":[]}],"tooltips":{"loading":"正在加载...","previous":"上一个图像","next":"下一个图像","walle":"此图片不能下载用作壁纸。","walls":"下载今日美图。仅限用作桌面壁纸。"}}

利用AS内GsonFormat插件自动生成ImageBean实体类

3.创建基础接受类BaseData
public class BaseData<T> {
    private T data;
    private String message;

    public BaseData() {
    }

    public BaseData(T data, String message) {
        this.data = data;
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
4.搭建基础网络请求框架

采用了Retrofit+Rxjava作为网络访问框架(都是些基础使用)

public class NetUtil {

    private Retrofit retrofit;

    public NetUtil() {
        retrofit = new Retrofit.Builder()
                .baseUrl("https://cn.bing.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
    }

    public interface ImageService {
        @GET("HPImageArchive.aspx")
        Observable<ImageBean> getBingImage(@Query("format") String format,
                                     @Query("idx") int idx,
                                     @Query("n") int n);
    }

    public Observable<ImageBean> getBingImage(String format, int idx, int n) {
        return retrofit.create(ImageService.class).getBingImage(format, idx, n);
    }

}
5.搭建Repository模块即具体的网络请求模块
public class ImageRepository {

    private static final String TAG = "ImageRepository";

    private NetUtil netUtil = new NetUtil();
    private MutableLiveData<BaseData<ImageBean>> imageBean1 = new MutableLiveData<>();

    private int idx = 1;

    /**
     * 获取图片
     */
    public MutableLiveData<BaseData<ImageBean>> getBingImage() {
        netUtil.getBingImage("js", idx, 1)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<ImageBean>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(ImageBean imageBean) {
                        imageBean1.setValue(new BaseData<>(imageBean, null));
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });
        return imageBean1;
    }

    /**
     * 获取下一张图片
     */
    public MutableLiveData<BaseData<ImageBean>> getNextImage() {
        if (idx > 6) {
            imageBean1.setValue(new BaseData<ImageBean>(null, "已经是最后一张啦"));
            return imageBean1;
        }
        ++idx;
        return getBingImage();
    }

    /**
     * 获取上一张图片
     */
    public MutableLiveData<BaseData<ImageBean>> getPreviousImage() {
        if (idx < 1) {
            imageBean1.setValue(new BaseData<ImageBean>(null, "已经是第一张啦"));
            return imageBean1;
        }
        --idx;
        return getBingImage();
    }
}

即使Repository模块看起来没有必要,它也有着重要的作用。它从应用程序的其余部分提取数据源。现在我们的ViewModel不知道数据是由NetUtil获取的,这意味着我们可以根据需要将其交换为其他实现。所以下一步就是创建对应的ViewModel

6.创建对应的ViewModel
public class DemoActivityViewModel extends AndroidViewModel {

    private ImageRepository imageRepository ;
     //存放从网络上获取的图片信息
    private MutableLiveData<BaseData<ImageBean>> imageBean ;

    public DemoActivityViewModel(@NonNull Application application) {
        super(application);
        imageRepository=new ImageRepository();
        imageBean=new MutableLiveData<>();
    }

    public MutableLiveData<BaseData<ImageBean>> getImageBean() {
        return imageBean;
    }

    /**
     * 获取图片
     */
    public void getImage() {
        imageBean = imageRepository.getBingImage();
    }

    /**
     * 获取下一张
     */
    public void getNextImage() {
        imageBean = imageRepository.getNextImage();
    }

    /**
     * 获取上一张
     */
    public void getPreviousImage() {
        imageBean = imageRepository.getPreviousImage();
    }
}
7.Activity内使用
public class DemoActivity extends AppCompatActivity {
    private ActivityDemoBinding activityDemoBinding;
    private DemoActivityViewModel demoActivityViewModel;
    private ProgressDialog progressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        activityDemoBinding = DataBindingUtil.setContentView(this, R.layout.activity_demo);
        demoActivityViewModel = ViewModelProviders.of(this).get(DemoActivityViewModel.class);
       //绑定ViewModel
        activityDemoBinding.setViewModel(demoActivityViewModel);
       //绑定点击事件
        activityDemoBinding.setEventListener(new OnEventListener());
        progressDialog = new ProgressDialog(DemoActivity.this);
        progressDialog.setMessage("加载中。。。。");
       //获取第一张网络图片
        demoActivityViewModel.getImage();
        progressDialog.show();
        demoActivityViewModel.getImageBean().observe(this, new Observer<BaseData<ImageBean>>() {
            @Override
            public void onChanged(BaseData<ImageBean> imageBeanBaseData) {
                if (imageBeanBaseData.getData() != null) {
                    //1.直接代码赋值
                    Glide.with(DemoActivity.this)
                            .load("https://www.bing.com" + imageBeanBaseData.getData().getImages().get(0).getUrl())
                            .into(activityDemoBinding.ivImg);
                    activityDemoBinding.tvContent.setText(imageBeanBaseData.getData().getImages().get(0).getCopyright());

                    //2.利用DataBinding直接赋值
                    activityDemoBinding.setImage(imageBeanBaseData.getData().getImages().get(0));
                } else {
                    Toast.makeText(DemoActivity.this, imageBeanBaseData.getMessage(), Toast.LENGTH_SHORT).show();
                }
                progressDialog.dismiss();
            }
        });
    }

    public class OnEventListener {
        public void onClick(View view) {
            progressDialog.show();
            switch (view.getId()) {
                case R.id.tv_previous:
                    //获取上一张
                    demoActivityViewModel.getPreviousImage();
                    break;
                case R.id.tv_next:
                   //获取下一张
                    demoActivityViewModel.getNextImage();
                    break;
                default:
                    break;
            }
        }
    }

}

与其对应的xml文件为:

<?xml version="1.0" encoding="utf-8"?>
<layout 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">

    <data>

        <variable
            name="viewModel"
            type="com.example.myapplication.demo.DemoActivityViewModel" />

        <variable
            name="image"
            type="com.example.myapplication.demo.ImageBean.ImagesBean" />

        <variable
            name="eventListener"
            type="com.example.myapplication.demo.DemoActivity.OnEventListener" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".demo.DemoActivity">

        <TextView
            android:id="@+id/tv"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:text="Bing每日一图"
            android:textColor="#000000"
            app:layout_constraintBottom_toTopOf="@id/iv_img" />

        <ImageView
            android:id="@+id/iv_img"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            url="@{"https://www.bing.com"+image.url}"       //此处需自定义BindingAdapter
            app:layout_constraintTop_toBottomOf="@id/tv" />

        <TextView
            android:id="@+id/tv_content"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_margin="15dp"
            android:textColor="#000000"
            android:textSize="15sp"
            android:text="@{image.copyright}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/iv_img" />

        <Button
            android:id="@+id/tv_previous"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_marginStart="15dp"
            android:layout_marginTop="15dp"
            android:gravity="center"
            android:text="上一张"
            android:onClick="@{eventListener::onClick}"
            app:layout_constraintEnd_toStartOf="@id/tv_next"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/tv_content" />

        <Button
            android:id="@+id/tv_next"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_marginStart="15dp"
            android:layout_marginTop="15dp"
            android:layout_marginEnd="15dp"
            android:gravity="center"
            android:text="下一张"
            android:onClick="@{eventListener::onClick}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@id/tv_previous"
            app:layout_constraintTop_toBottomOf="@id/tv_content" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

在ImageView内自定义了一个url属性,此时需使用BindingAdapter去自定义实现,实现起来很简单:

public class DataBindingUtil {
    @BindingAdapter(value = {"url"})
    public static void loadImage(ImageView view, String url) {
        Glide.with(view.getContext()).load(url).into(view);
    }
}

至此一个很简单的MVVM架构的小demo就实现了。

相关文章

网友评论

    本文标题:Android mvvm架构demo(DataBinding+L

    本文链接:https://www.haomeiwen.com/subject/jneerctx.html