Android APP 基于RecyclerView框架工程(知识体系积累)

news2024/12/24 2:22:41

说明这个简单的基于RecyclerView的框架作用在于自己可以将平时积累的一些有效demo整合起来(比如音视频编解码的、opengles的以及其他也去方向的、随着项目增多,工程量的增加,后期想高效的分析和查找并不容易),不用搞太多的工程,不像多个工程过于分散也占空间。


1 基于RecyclerView框架工程实现原理说明

该工程通过config.xml配置文件获取每一个网格中的基本信息,并将其存储到itemlist中。应用启动后,点击网格中的按键,每个按键可以按需启动一个应用。适用于长期积累自己的知识体系。

接下来直接上干货,粘过去可以直接用的那种~。平台是基于Android12的。

框架工程代码完整解读(android Q)

2.1 layout布局文件解读

res/layout 主界面 activity_main.xml内容如下:

<androidx.constraintlayout.widget.ConstraintLayout 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"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    tools:ignore="ExtraText">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="500dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textviewMainMenu"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:text="@string/title"
        android:background="@color/white"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/recyclerview" />
</androidx.constraintlayout.widget.ConstraintLayout>

RecycleView中需要使用的配置文件item参考实现如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="4dp"
        android:layout_marginTop="18dp"
        android:text="@string/title"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="@string/h264_decode_demo"
        app:layout_constraintStart_toStartOf="@+id/textView"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>

2.2 配置文件体系构建

使用res/xml 配置文件 config.xml内容如下:

<?xml version="1.0" encoding="utf-8"?>
<items>
    <item>
        <description>H264解码一个download目录下的out.h264码流</description>
        <buttonName>H264解码</buttonName>
        <activityName>com.wds.videoexample.Activity1</activityName>
    </item>
    <item>
        <description>通过mediaprojection获取投屏数据,使用H264编码一个sdcard/路径下的codec.h264码流</description>
        <buttonName>H264编码</buttonName>
        <activityName>com.example.app.Activity2</activityName>
    </item>
    <item>
        <description>通过camerax获取投屏数据,使用H264编码一个sdcard/路径下的codec.h264码流</description>
        <buttonName>Button03</buttonName>
        <activityName>com.example.app.Activity3</activityName>
    </item>
    。。。
<items>

关于元素的个数和tag,大家可以自己按照自己的需求自定义。接下来有了配置文件,还要有配套的解析器,这里命名为ParseConfig,代码实现如下:

public class ParserConfig {
    private final static String TAG = "ParserConfig";
    private static List<Item> itemList;
    public static List<Item> getItemList() {
        return itemList;
    }
   private static String fullDescription = "";
    @SuppressLint("DefaultLocale")
    public static void initItemList(Context context) {
        itemList = new ArrayList<>();
        XmlResourceParser parser = context.getResources().getXml(R.xml.config);
        Log.d(TAG,"initItemLis");
        String description = null;
        String buttonName = null;
        String activityName = null;
        String tagName = null;
        //String fullDescription = "";
        int index= 0;

        try {
            int eventType = parser.getEventType();
            while (eventType != XmlPullParser.END_DOCUMENT) {
                if (eventType == XmlPullParser.START_TAG) {
                    tagName = parser.getName();
                    if ("item".equals(tagName)) {
                        index++;
                        while (parser.next() != XmlPullParser.END_TAG) {
                            if (parser.getEventType() == XmlPullParser.TEXT) {
                                description = parser.getText();
                                fullDescription += "\ndemo"+String.format("%03d",index)+":"+description+"\n";
                            }
                        }
                        while (parser.next() != XmlPullParser.END_TAG) {
                            if (parser.getEventType() == XmlPullParser.TEXT) {
                                buttonName = parser.getText();
                            }
                        }
                        while (parser.next() != XmlPullParser.END_TAG) {
                            if (parser.getEventType() == XmlPullParser.TEXT) {
                                activityName = parser.getText();
                            }
                        }
                        if (buttonName != null && activityName != null) {
                            itemList.add(new Item(description,buttonName, activityName));
                        }
                    }
                }
                eventType = parser.next();
            }

        } catch (XmlPullParserException | IOException e) {
            e.printStackTrace();
        }
    }
    public static String getFullDescription(){
        return fullDescription;
    }
}

这里涉及的itemlist中的元素item定义如下:

public class Item {
    public String buttonName; //点击按键内容
    private String activityName;
    private String description;

    public Item(String description, String buttonName, String activityName) {
        this.buttonName = buttonName;
        this.activityName = activityName;
        this.description = description;
    }

    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getButtonName() {
        return buttonName;
    }
    public void setButtonName(String buttonName) {
        this.buttonName = buttonName;
    }
    public String getActivityName() {
        return activityName;
    }
    public void setActivityName(String activityName) {
        this.activityName = activityName;
    }
}

2.3 权限的处理

关于权限,使用了一个Permission 专门的类来做运行时权限的处理,代码实现如下:

public class Permission {
    public static final int REQUEST_MANAGE_EXTERNAL_STORAGE = 1;
    //需要申请权限的数组
    private static final String[] permissions = {
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.CAMERA
    };
    //保存真正需要去申请的权限
    private static final List<String> permissionList = new ArrayList<>();

    public static int RequestCode = 100;

    public static void requestManageExternalStoragePermission(Context context, Activity activity) {
        if (!Environment.isExternalStorageManager()) {
            showManageExternalStorageDialog(activity);
        }
    }

    private static void showManageExternalStorageDialog(Activity activity) {
        AlertDialog dialog = new AlertDialog.Builder(activity)
                .setTitle("权限请求")
                .setMessage("请开启文件访问权限,否则应用将无法正常使用。")
                .setNegativeButton("取消", null)
                .setPositiveButton("确定", (dialogInterface, i) -> {
                    Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
                    activity.startActivityForResult(intent, REQUEST_MANAGE_EXTERNAL_STORAGE);
                })
                .create();
        dialog.show();
    }

    public static void checkPermissions(Activity activity) {
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
                permissionList.add(permission);
            }
        }

        if (!permissionList.isEmpty()) {
            requestPermission(activity);
        }
    }

    public static void requestPermission(Activity activity) {
        ActivityCompat.requestPermissions(activity,permissionList.toArray(new String[0]),RequestCode);
    }
}

这样,如果后面又更多的权限,都可以使用该方法来处理,处理方式为:

Permission.checkPermissions(this);
Permission.requestManageExternalStoragePermission(getApplicationContext(), this);

2.4 基于RecyclerView的框架工程 | 主流程代码参考实现

这里给出框架工程的代码的实现。具体如下:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private RecyclerView mRecyclerView;
    MyAdapter mMyAdapter ;
    private List<Item> itemList;
    private TextView mTextViewMainmenu;
    @SuppressLint("DefaultLocale")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
        mTextViewMainmenu = findViewById(R.id.textviewMainMenu);
        mTextViewMainmenu.setMovementMethod(ScrollingMovementMethod.getInstance());
        mRecyclerView = findViewById(R.id.recyclerview);
        ParserConfig.initItemList(this);
        mTextViewMainmenu.setText(ParserConfig.getFullDescription());
        itemList = ParserConfig.getItemList();
        mMyAdapter = new MyAdapter();
        mRecyclerView.setAdapter(mMyAdapter);
        GridLayoutManager layoutManager = new GridLayoutManager(MainActivity.this,3);
        mRecyclerView.setLayoutManager(layoutManager);

        DividerItemDecoration mDivider = new
                DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
        mRecyclerView.addItemDecoration(mDivider);
        DividerItemDecoration mDivider2 = new
                DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL);
        mRecyclerView.addItemDecoration(mDivider2);
    }

    class MyAdapter extends RecyclerView.Adapter<MyViewHoder> {

        @NonNull
        @Override
        public MyViewHoder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = View.inflate(MainActivity.this, R.layout.item_list, null);
            return new MyViewHoder(view);
        }

        @Override
        public void onBindViewHolder(@NonNull MyViewHoder holder, int position) {
            Item item = itemList.get(position);
            @SuppressLint("DefaultLocale") String title_text = getString(R.string.wbs_demo) + String.format("%03d", position+1);
            holder.mTitleTv.setText(title_text);
            holder.mButton.setText(item.buttonName);
            holder.mButton.setTag(position);

            holder.mButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    int position = (int)view.getTag();
                    mTextViewMainmenu.setText(itemList.get(position).getDescription());
                    Handler handler = new Handler();
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (position == 0) {
                                Intent intent = new Intent(MainActivity.this, H264decoderActivity.class);
                                startActivity(intent);
                            } else if (position == 1) {
                                Intent intent = new Intent(MainActivity.this, H264encoderMediaProjActivity.class);
                                startActivity(intent);
                            } else if (position == 2) {
                                Intent intent = new Intent(MainActivity.this, H264encoderCameraXActivity.class);
                                startActivity(intent);
                            }
                        }
                    }, 3000); //

                    Log.d(TAG,"onclick"+view.getTag());
                }
            });
        }

        @Override
        public int getItemCount() {
            return itemList.size();
        }
    }

    static class MyViewHoder extends RecyclerView.ViewHolder {
        TextView mTitleTv;
        Button mButton;

        public MyViewHoder(@NonNull View itemView) {
            super(itemView);
            mTitleTv = itemView.findViewById(R.id.textView);
            mButton = itemView.findViewById(R.id.button);
        }

    }
}

2.5 主框架 demo实现效果

实际运行效果展示如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1939493.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vscode 环境

这张截图显示的是在VS Code&#xff08;Visual Studio Code&#xff09;中选择Python解释器的界面。不同的Python解释器及其虚拟环境列出了可选项&#xff0c;用户可以根据需要选择合适的解释器来运行Python代码。以下是对截图中信息的详细解释&#xff1a; 解释器选择界面 当…

Java小技能:多级组织机构排序并返回树结构(包含每个层级的子节点和业务数据集合)

文章目录 引言I 实体定义1.1 部门1.2 用户组织机构中间表1.3 树状DTOII 抽取组织机构排序方法2.1 树状排序方法2.2 案例III 查询条件构建3.1 根据部门进行权限控制3.2 注入风险引言 需求: 根据组织机构进行数据授权控制,例如控制船舶、船舶设备、摄像头、港区查看权限。 一…

05_解封装和解码

1. 基本概念 容器就是一种文件格式&#xff0c;比如flv、mkv、mp4等。包含下面5种流以及文件头信息。 流是一种视频数据信息的传输方式&#xff0c;5种流&#xff1a;音频&#xff0c;视频&#xff0c;字幕&#xff0c;附件&#xff0c;数据。 包在ffmpeg中代表已经编码好的一…

【LINUX】pr_info函数开发摸索

1、打印开关可随时控制&#xff0c;开机如果要修改是否打印日志的话&#xff0c;需要修改代码重新编译内核才行&#xff0c;其实如果真要搞&#xff0c;应该有其他方法&#xff1b; 2、打印次数&#xff0c;当前代码里边写的是1000次&#xff0c;其实可以根据传参动态修改打印…

CUDA编程00 - 配置CUDA开发环境

第一步&#xff1a; 在一台装有Nvidia显卡和驱动的机器上&#xff0c;用nvidia-smi命令查看显卡所支持cuda版本 第二步&#xff1a; 到Nvidia官网下载CUDA Toolkit并安装&#xff0c;CUDA Toolkit Archive | NVIDIA Developer 安装时按提示下一步即可&#xff0c;安装完成用 …

Django cursor()增删改查和shell环境执行脚本

在Django中&#xff0c;cursor()方法是DatabaseWrapper对象&#xff08;由django.db.connectio提供&#xff09;的一个方法&#xff0c;用于创建一个游标对象。这个游标对象可以用来执行SQL命令&#xff0c;从而实现对数据库的增删改查操作。 查询&#xff08;Select&#xff0…

C++初学者指南-5.标准库(第一部分)--标准库查询存在算法

C初学者指南-5.标准库(第一部分)–标准库查询存在算法 文章目录 C初学者指南-5.标准库(第一部分)--标准库查询存在算法any_of / all_of / none_ofcountcount_if相关内容 不熟悉 C 的标准库算法&#xff1f; ⇒ 简介 any_of / all_of / none_of 如果在输入范围(所有元素…

2024最新教程,在docker中安装kali,并配置ssh连接

docker的基本使用&#xff1a;搭建高效攻防靶场vulfocus与Docker仓库管理实战&#xff1a;从听说到入门 拉取kali官方镜像 docker pull kalilinux/kali-rolling 启动一个kali镜像&#xff0c;将容器中的22端口映射到主机100端口&#xff0c;方便ssh直接连接 docker run -it…

Unity UGUI 之 Toggle

​本文仅作学习笔记与交流&#xff0c;不作任何商业用途本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正​ 1.什么是Toggle&#xff1f; Unity - Manual: Toggle 带复选框的开关&#xff0c;可…

linux-二元信号量和计数信号量-生产者消费者模型以及用二元信号量实现-死锁(2)-侠义消息队列(fifo)-proc文件系统

二元信号量和计数信号量的区别&#xff1a; 二元信号量和计数信号量在嵌入式系统和多任务环境中都是重要的同步机制&#xff0c;用于控制对共享资源的访问。它们之间的主要区别体现在以下几个方面&#xff1a; 1. 状态表示 二元信号量&#xff08;Binary Semaphore&#xff09;…

[计算机基础]一、计算机组成原理

计算机组成原理的考察目标为&#xff1a; 1. 掌握单处理器计算机系统中主要部件的工作原理、组成结构以及相互连接方式。 2. 掌握指令集体系结构的基本知识和基本实现方法&#xff0c;对计算机硬件相关问题进行分析&#xff0c;并能够对相关部件进行设计。 3. 理解计算机系统的…

HTML5-canvas1

1、canvas&#xff1a;创建画布 <canvas id"canvas"></canvas>2、画一条直线 var canvasdocument.getElementById(cancas&#xff09;; canvas.width800; canvas.height800; var contextcanvas.getContext(2d); //获得2d绘图上下文环境 //画一条直线 c…

算法 - 图论Dijkstra(原理、思路代码实现、以东南大学真题为例讲解手算方法)

Dijkstra 算法原理&#xff1a; Dijkstra算法是一种经典的用于计算单源最短路径的算法。它可以在带权重的图中找到从源节点到所有其他节点的最短路径。Dijkstra算法通过贪心策略&#xff0c;不断选择当前已知最短路径最小的节点&#xff0c;更新其邻接节点的路径长度&#xff…

Linux之旅:常用的指令,热键和权限管理

目录 前言 1. Linux指令 &#xff08;1&#xff09; ls &#xff08;2&#xff09; pwd 和 cd &#xff08;3&#xff09;touch 和 mkdir &#xff08;4&#xff09; rmdir 和 rm &#xff08;5&#xff09;cp &#xff08;6&#xff09;mv &#xff08;7&#xff09;…

Qt窗口介绍

Qt窗口 一、Qt窗口二、菜单栏创建菜单栏在菜单栏中添加菜单创建菜单项在菜单项之间添加分割线综合练习 三、工具栏创建工具栏设置停靠位置设置浮动属性设置移动属性综合练习 四、状态栏状态栏的创建在状态栏中显示实时消息在状态栏显示永久的消息 五、浮动窗口浮动窗口的创建设…

达梦数据库系列—29. DTS迁移ORACLE到DM

目录 1.ORACLE源端信息 2.DM目的端信息 3.DTS 迁移评估 4.数据库迁移 4.1 Oracle 源端数据库准备 4.2 目的端达梦数据库准备 初始化参数设置 兼容性参数设置 表空间规划 用户规划 创建迁移用户和表空间 4.3迁移步骤 创建迁移 配置数据源 配置迁移对象及策略 开…

Vue3 --- 路由

路由就是一组key-value的对应关系&#xff1b;多个路由&#xff0c;需要经过路由器的管理。 1. 基本切换效果 安装路由器 npm i vue-router /router/index.ts // import { createRouter, createWebHistory } from vue-router import Home from /components/Home.vue import…

[Armbian] 部署Docker版Home Assistent,安装HACS并连接米家设备

title: [Armbian] 部署Docker版Home Assistent&#xff0c;安装HACS并连接米家设备 date: 2024-07-21T10:51:23Z lastmod: 2024-07-21T11:40:39Z [Armbian] 部署Docker版Home Assistent&#xff0c;安装HACS并连接米家设备 官网&#xff1a;Home Assistant (home-assistant.i…

算法——滑动窗口(day6)

1004.最大连续1的个数 ||| 1004. 最大连续1的个数 III - 力扣&#xff08;LeetCode&#xff09; 题目解析&#xff1a; 这道题如果能转化为滑动窗口的话就会很简单&#xff0c;因为我们如果尝试去把0翻转为1再计数的话等到第2轮又得重新翻转回来&#xff0c;费时费力~ 那么我…

gihub导入gitee仓库实现仓库同步

昨天在GitHub里导入了gitee仓库&#xff0c;但是在仓库同步这里卡了很久&#xff0c;因为网上大多数都是从github导入gitee&#xff0c;然后github生成token放入实现同步&#xff0c;但是我找到一种更为方便的&#xff01; 1.首先找到项目文件下的.git文件里的config文件 2.在…