美文网首页面试题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