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实现效果

实际运行效果展示如下:

相关推荐
m0_548514772 小时前
2024.12.10——攻防世界Web_php_include
android·前端·php
凤邪摩羯3 小时前
Android-性能优化-03-启动优化-启动耗时
android
凤邪摩羯3 小时前
Android-性能优化-02-内存优化-LeakCanary原理解析
android
喀什酱豆腐3 小时前
Handle
android
m0_748232925 小时前
Android Https和WebView
android·网络协议·https
m0_748251725 小时前
Android webview 打开本地H5项目(Cocos游戏以及Unity游戏)
android·游戏·unity
m0_748254667 小时前
go官方日志库带色彩格式化
android·开发语言·golang
zhangphil7 小时前
Android使用PorterDuffXfermode模式PorterDuff.Mode.SRC_OUT橡皮擦实现“刮刮乐”效果,Kotlin(2)
android·kotlin
爱学测试的李木子7 小时前
从0到1搭建 Android 自动化 python+appium 环境
android·软件测试·python·测试工具·自动化
咸芝麻鱼7 小时前
Android Studio | 连接手机设备后,启动App时出现:Waiting For DebuggerApplication (App名)...
android·adb·智能手机·android studio