Android开发 - Presenter抽象类使用与管理视图显示与行为解析

Presenter是什么

  • 职责

    • Presenter 的主要职责是管理视图(通常是用户界面组件)的显示和行为

    • 它不处理数据的逻辑,而是专注于如何展示数据

  • 在 Leanback 库中的作用

    • Leanback 库是为 Android TV 设计的一个库,提供了一些特殊的 UI 组件,比如 BrowseFragment

    • Presenter 在 Leanback 库中用于定义每个项目(比如电影、电视节目等)在屏幕上的显示方式

  • 类结构

    • Presenter 是一个抽象类,你需要继承它并实现三个主要方法

      • onCreateViewHolder(ViewGroup parent)创建初始化视图组件,用于显示单个项目

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent) {
            // 创建一个新的 ImageView 作为项目的视图
            ImageView imageView = new ImageView(parent.getContext());
            imageView.setLayoutParams(new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT
            ));
            imageView.setPadding(10, 10, 10, 10); // 设置内边距
            return new ViewHolder(imageView); // 返回 ViewHolder,包含这个 ImageView
        }
        
        • 参数解析
          • parent表示 RecyclerView 的父视图。你可以用它来获取上下文创建视图的布局参数
      • onBindViewHolder(ViewHolder viewHolder, Object item):将数据绑定到视图,更新视图的内容显示正确的数据

        @Override
        public void onBindViewHolder(ViewHolder viewHolder, Object item) {
            // 将数据对象转换为具体的类型(假设是 Movie 类)
            Movie movie = (Movie) item;
        
            // 获取 ViewHolder 中的视图组件(假设是 ImageView)
            ImageView imageView = (ImageView) viewHolder.view;
        
            // 设置 ImageView 的图像资源为电影海报
            imageView.setImageResource(movie.getPosterResourceId());
        }
        
        • 参数解析
          • viewHolderonCreateViewHolder 方法返回的 ViewHolder 对象,包含视图组件
          • item要绑定到视图的数据对象。你需要将其转换为具体的数据类型
      • onUnbindViewHolder(ViewHolder viewHolder)清理视图,以便回收资源

        @Override
        public void onUnbindViewHolder(ViewHolder viewHolder) {
            // 清理视图资源,这里不需要做任何操作
            // 例如,如果是 ImageView,可以清除图像资源
            ImageView imageView = (ImageView) viewHolder.view;
            imageView.setImageDrawable(null); // 清除图像资源
        }
        
        • 参数解析
          • viewHolder包含视图组件的 ViewHolder 对象

代码示例

  • 通过 MoviePresenter 类与 BrowseFragment 类示例解释:假设需要显示一系列电影海报

    • 创建主布局文件res/layout/activity_main.xml

      <?xml version="1.0" encoding="utf-8"?>
      <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent">
      
          <!-- 容纳 BrowseFragment 的容器 -->
          <FrameLayout
              android:id="@+id/main_browse_fragment"
              android:layout_width="match_parent"
              android:layout_height="match_parent" />
      </FrameLayout>
      
    • 创建一个自定义 Movie 类方便调用方法

      //自定义数据模型类,用于封装电影信息
      public class Movie {
          private final int posterResourceId; // 海报资源的 ID
          private final String title; // 电影标题
      
          // 构造函数,用于创建 Movie 对象
          public Movie(int posterResourceId, String title) {
              this.posterResourceId = posterResourceId;
              this.title = title;
          }
      
          // 获取海报资源 ID
          public int getPosterResourceId() {
              return posterResourceId;
          }
      
          // 获取电影标题
          public String getTitle() {
              return title;
          }
      }
      
    • 创建一个 MoviePresenter 类来定义每个电影海报的显示方式

      import android.view.ViewGroup;
      import android.widget.ImageView;
      import android.widget.TextView;
      import androidx.leanback.widget.Presenter;
      
      //定义如何创建和绑定电影数据到视图
      public class MoviePresenter extends Presenter {
      
          @Override
          //用于创建视图组件。在这个例子中,我们创建了一个 ImageView 作为电影海报的视图
          //我们也可以创建一个包含多个视图(例如 ImageView 和 TextView)的复杂布局
          public ViewHolder onCreateViewHolder(ViewGroup parent) {
              // 创建一个包含 ImageView 和 TextView 的布局
              ImageView imageView = new ImageView(parent.getContext());
              TextView textView = new TextView(parent.getContext());
      
              // 设置布局参数和样式
              imageView.setLayoutParams(new ViewGroup.LayoutParams(
                      ViewGroup.LayoutParams.WRAP_CONTENT,
                      ViewGroup.LayoutParams.WRAP_CONTENT
              ));
              textView.setLayoutParams(new ViewGroup.LayoutParams(
                      ViewGroup.LayoutParams.WRAP_CONTENT,
                      ViewGroup.LayoutParams.WRAP_CONTENT
              ));
              
              // 这里仅创建 ImageView 的 ViewHolder
              return new ViewHolder(imageView);
          }
      
          @Override
          //方法用于将数据绑定到视图。在这个例子中,我们将电影的海报图像设置到 ImageView 中
          public void onBindViewHolder(ViewHolder viewHolder, Object item) {
              // 将电影海报数据绑定到 ImageView
              Movie movie = (Movie) item; // 假设 Movie 类包含电影信息
              // 获取 ViewHolder 中的 ImageView 视图
              ImageView imageView = (ImageView) viewHolder.view;
              //Movie 类假定包含电影的信息,如海报的资源 ID
              imageView.setImageResource(movie.getPosterResourceId()); // 设置电影海报图像
          }
      
          @Override
          //方法用于清理视图资源。通常在视图不再需要显示时调用,这里可以进行资源释放等操作。在这个例子中,我们没有需要特别清理的资源。
          public void onUnbindViewHolder(ViewHolder viewHolder) {
              // 清理视图资源,这里不需要做任何操作
          }
      }
      
    • 启动类中调用

      import android.os.Bundle;
      import androidx.fragment.app.FragmentActivity;
      import androidx.fragment.app.FragmentManager;
      import androidx.leanback.app.BrowseFragment;
      import androidx.leanback.widget.ArrayObjectAdapter;
      import androidx.leanback.widget.ListRow;
      import androidx.leanback.widget.ListRowPresenter;
      import androidx.leanback.widget.HeaderItem;
      
      //初始化 BrowseFragment 并设置电影数据行
      public class MainActivity extends FragmentActivity {
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              // 设置布局文件,将 activity_main.xml 作为内容视图
              setContentView(R.layout.activity_main);
      
              // 获取 FragmentManager,用于管理 Fragment
              FragmentManager fragmentManager = getSupportFragmentManager();
      
              // 创建一个 BrowseFragment 实例
              BrowseFragment browseFragment = new BrowseFragment();
      
              // 使用 FragmentManager 将 BrowseFragment 添加到容器(main_browse_fragment)中
              fragmentManager.beginTransaction()
                      .replace(R.id.main_browse_fragment, browseFragment)
                      .commit();
      
              // 配置 BrowseFragment 的基本属性和数据行
              browseFragment.setTitle("电影列表"); // 设置标题
              setupRows(browseFragment); // 设置数据行
          }
      
          // 配置 BrowseFragment 的数据行
          private void setupRows(BrowseFragment browseFragment) {
              // 创建一个 ArrayObjectAdapter,并使用 ListRowPresenter 作为呈现器
              ArrayObjectAdapter rowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
      
              // 创建一个 HeaderItem,代表行的标题
              HeaderItem headerItem = new HeaderItem(0, "热门电影");
      
              // 创建一个 ArrayObjectAdapter,用于 ListRow 的数据
              ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new MoviePresenter());
      
              // 添加电影数据到适配器
              listRowAdapter.add(new Movie(R.drawable.poster1, "电影 1"));
              listRowAdapter.add(new Movie(R.drawable.poster2, "电影 2"));
      
              // 将适配器添加到 ListRow,并添加到 rowsAdapter
              ListRow listRow = new ListRow(headerItem, listRowAdapter);
              rowsAdapter.add(listRow);
      
              // 设置适配器到 BrowseFragment
              browseFragment.setAdapter(rowsAdapter);
          }
      }
      
    • 最后创建AndroidManifest.xml声明应用程序和启动 Activity就大功告成了

posted @ 2024-08-03 14:12  阿俊学JAVA  阅读(4)  评论(0编辑  收藏  举报