65.9K
CodeProject 正在变化。 阅读更多。
Home

一个使用 MVP 模式的简单图片获取 Android 应用

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2017年7月10日

CPOL

3分钟阅读

viewsIcon

11820

downloadIcon

323

一个使用 MVP 模式的简单图片获取应用

引言

ImgurDner 是一款实验性的Android应用,用于从imgur.com下载热门图片。它采用了流行的MVP,即 Model View & Presenter 模式。

背景

虽然使用设计模式并不是开发移动应用的先决条件,但像MVC或MVP这样的架构模式有助于实现代码的关注点分离:区分负责视图的模块和负责业务逻辑的模块;建立GUI和后端数据之间有效的通信渠道。此外,单元测试也变得更容易,代码的可读性和可维护性也明显增强。

使用代码

为了进行一个简洁明了的演示,作者将代码保持简单,以便读者可以专注于代码的架构方面,从而理解在Android编程中使用MVP模式。

在MVP模式中,Presenter充当View和Model之间的“中间人”。它与View模块建立双向通信:从View获取Model请求的输入;同时,从Model检索结果并直接通过View的方法更新GUI(这是MVP与MVC模式的一个显著特征)。

该项目包含五个主要的Java文件

  • DownloadActivityDownloadFragment,这两个文件是View模块(尽管这主要是Fragment的工作。Android建议使用Fragment而不是Activity来处理UI);
  • DownloadContract,一个包含View子接口和Presenter接口的接口;
  • DownloadPresenter,Presenter接口的实现,充当View和Model之间的联络人
  • ImgurService,一个符合Retrofit HTTP客户端框架协议的接口类,用于方便和异步的Web服务访问。

DownloadActivity.java 负责创建Presenter的实例并将引用传递给Fragment组件;Activity类还负责将Fragment(这是一个View的实现)传递给Presenter。通过完成这两个步骤,View和Presenter现在拥有双向通信。请注意,MVP和MVC模式之间的一个区别在于,在MVP中,Presenter可以通过View引用操作UI渲染。

@Override
    protected void onCreate(Bundle savedInstanceState) {
		...
        //retrieve the reference to the fragment
        DownloadFragment downloadFragment = (DownloadFragment)getSupportFragmentManager().findFragmentById(R.id.contentFrame);
        if(downloadFragment == null){
            downloadFragment = DownloadFragment.newInstance();
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            transaction.add(R.id.contentFrame, downloadFragment);
            transaction.commit();
        }
        //crate a presenter
        downloadPresenter = new DownloadPresenter(downloadFragment); //pass the view reference to the presenter
        downloadFragment.setPresenter(downloadPresenter); //pass the presenter reference to the view
    }
...

在MVP模式中使用Contract接口是很常见的做法,它由两个子接口组成。

  • View接口。普通的Android Fragment类将实现此接口。
  • Presenter接口,其中包括基本的Presenter功能。任何具体的Presenter类都至少会实现此接口。
public interface DownloadContract {
    interface View extends BaseView<presenter> {
    }

    interface Presenter extends BasePresenter {
    }
}

public interface BasePresenter {
    void start();
}

public interface BaseView<T> {
    void setPresenter(T presenter);
}</presenter>

具体的Presenter类负责从Web服务获取数据。在这种情况下,我们使用imgur.com的API来访问其丰富的图片存储库。

为了访问imgur的Web服务,我们使用Retrofit HTTP客户端框架。下面显示了简要步骤
首先,我们定义一个带有Web服务URL的接口

public interface ImgurService {

    String URL = "https://api.imgur.com/3/gallery/hot/viral/0.json";

    @Headers({
            "Authorization: Client-ID XXXXXXXXX",
            "User-Agent: XXXXXXXXXXXXXXXXXXXXXXXXX"
    })
    @GET("/")
    void getAllImages(Callback<Image> cb);
}

然后,我们按照Retrofit的编码约定检索数据,一旦成功,Presenter调用View的方法来更新UI

ImgurService restInterface =  new RestAdapter.Builder().setEndpoint(ImgurService.URL).build().create(ImgurService.class);
            restInterface.getAllImages(new retrofit.Callback<Image>() {
                @Override
                public void success(Image model, retrofit.client.Response response) {
                    List<Datum> images = model.getData();
                    for(Datum img : images){
                        Log.d(TAG, img.getLink());
                    }
                    List<Datum> jpgImgs = Stream.of(images).filter(p -> p.getLink().contains(".jpg")||p.getLink().contains(".gif")).collect(Collectors.toList());
                    ImageRepo.newInstance().setImages(jpgImgs);
                    ((DownloadFragment)mDownloadView).updateUI();
                    ((DownloadFragment)mDownloadView).stopSpin();
                }

                @Override
                public void failure(RetrofitError error) {
                    Log.e(TAG, error.getMessage());
                }
            });

请注意:像DatumImage这样的类是从JSON流转换而来的Java类(imgur Web服务使用的数据格式)。处理Java对象比解析原始JSON流对开发人员来说更舒服。这种JSON<->Java对象转换被称为Marshalling/Unmarshalling,可以通过Jackson等技术实现。

等等,虽然我有一个更好的主意,请按照这两个简单的步骤

  • 使用HTTP客户端工具,我最喜欢的是Postman来获取JSON数据

  • 从上述结果中取一个数据单元,并将其粘贴到这个在线工具中,以便读取其模式来生成一堆Java类,只需单击一下。

关注点

如何使用代码

这很容易。启动Android Studio,加载下载的源代码并点击“运行”

  

参考

历史

  • 2017年7月7日,初始版本
© . All rights reserved.