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

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


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

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

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

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

2.1 layout布局文件解读

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

html 复制代码
<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参考实现如下:

html 复制代码
<?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内容如下:

html 复制代码
<?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,代码实现如下:

java 复制代码
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定义如下:

java 复制代码
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 专门的类来做运行时权限的处理,代码实现如下:

java 复制代码
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);
    }
}

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

java 复制代码
Permission.checkPermissions(this);
Permission.requestManageExternalStoragePermission(getApplicationContext(), this);

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

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

java 复制代码
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实现效果

实际运行效果展示如下:

相关推荐
fatiaozhang952729 分钟前
中兴云电脑W102D_晶晨S905X2_2+16G_mt7661无线_安卓9.0_线刷固件包
android·adb·电视盒子·魔百盒刷机·魔百盒固件
CYRUS_STUDIO2 小时前
Android APP 热修复原理
android·app·hotfix
鸿蒙布道师2 小时前
鸿蒙NEXT开发通知工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
鸿蒙布道师2 小时前
鸿蒙NEXT开发网络相关工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
大耳猫2 小时前
【解决】Android Gradle Sync 报错 Could not read workspace metadata
android·gradle·android studio
ta叫我小白2 小时前
实现 Android 图片信息获取和 EXIF 坐标解析
android·exif·经纬度
dpxiaolong4 小时前
RK3588平台用v4l工具调试USB摄像头实践(亮度,饱和度,对比度,色相等)
android·windows
tangweiguo030519875 小时前
Android 混合开发实战:统一 View 与 Compose 的浅色/深色主题方案
android
老狼孩111225 小时前
2025新版懒人精灵零基础及各板块核心系统视频教程-全分辨率免ROOT自动化开发
android·机器人·自动化·lua·脚本开发·懒人精灵·免root开发
打死不学Java代码5 小时前
PaginationInnerInterceptor使用(Mybatis-plus分页)
android·java·mybatis