Libgdx仿安卓R文件通过Id访问资源

简介: 博客已迁移:更多精彩内容尽在AyoCrazy.com 在Libgdx开发过程中,对资源的引用是直接通过一个资源路径的字符串来获取的,这给我们开发过程中造成了很大的不便。例如我们修改了某个资源文件的路径后,编译器并不会报错,但是运行的时候却提示找不到这个文件,因为编译器无法判断这个资源路径是否为有效路径,这个时候我们需要手动去修改这个路径字符串,如果是一


博客已迁移:更多精彩内容尽在AyoCrazy.com



在Libgdx开发过程中,对资源的引用是直接通过一个资源路径的字符串来获取的,这给我们开发过程中造成了很大的不便。例如我们修改了某个资源文件的路径后,编译器并不会报错,但是运行的时候却提示找不到这个文件,因为编译器无法判断这个资源路径是否为有效路径,这个时候我们需要手动去修改这个路径字符串,如果是一个两个倒还好,但如果是批量修改呢,又怎么保证路径不会输错。要解决这个问题,我们可以通过将资源路径与变量对应起来,因为编译器可以判断一个变量是否存在。于是,我们很容易想到Android中的R文件,每个资源对应一个整型id,通过id去访问资源。那么在Libgdx中我们同样可以采取类似的方式,手动生成一个R文件,通过访问R文件中的变量去访问资源。这也是很多libgdx开发者通用的做法。

原理

通过遍历资源目录(android工程下的assets文件夹),获取每个资源的路径,然后将这些资源路径储存为Java的一个String类型常量,那么用的时候就可以直接使用R文件中的这个常量就行了,如果资源发生变动,只需要重新生成一下R文件就行了,十分方便。

好处

  • 有效防止路径拼写错误
  • 资源变动后,编译器会给予错误提示
  • 遍历文件夹为耗时操作,若遍历R文件则方便快速得多

步骤

1.在core工程下创建一个R文件的包和一个生成R文件的类

如下图的包和AutoR类
创建包和类

2.在AutoR类中写入生成R文件的代码

package com.mytian.mypet.R;

import java.io.File;
import java.io.FileOutputStream;
import java.util.Locale;

import com.badlogic.gdx.utils.Array;

/**
 * 自动生成R文件,在电脑上运行本程序,将会对assetPath路径下的所有文件进行遍历,生成R文件
 * 
 * @author AyoCrazy
 *
 */
public class AutoR {
    //这个路径是你android工程的assets文件夹路径
    private String assetPath = "E:\\workspace\\MyPet\\mypet\\android\\assets";

    public static void main(String[] args) {
        new AutoR().start();
    }

    public void start() {
        Group root = new Group("R");
        getFiles(root, new File(assetPath));
        writeFiles(root);
    }

    // 写代码到R文件
    private void writeFiles(Group group) {
        // 包名
        String packName = getClass().getPackage().getName();
        // R文件的路径
        String RFilePath = assetPath.replace("\\android\\assets",
                "\\core\\src\\" + packName.replace(".", "\\") + "\\R.java");
        // 生成包名代码
        String head = "package " + packName + ";\n";
        // 生成注释
        String info = "\n/** 此文件为自动生成,请勿随意手动修改 */";
        // 生成代码主体
        String body = head + info + group.toString();
        try {
            FileOutputStream os = new FileOutputStream(new File(RFilePath));
            os.write(body.getBytes(), 0, body.getBytes().length);
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 递归遍历文件
    private void getFiles(Group group, File parent) {
        File[] fs = parent.listFiles();
        for (File f : fs) {
            String fileName = f.getName();
            if (f.isDirectory()) {
                // 如果是目录,则创建一个Group并将其加入到父Group中
                Group g = new Group(fileName);
                group.addGroup(g);
                // 此处递归
                getFiles(g, f);
            } else {
                // 如果是文件,直接将文件名加入到父Group中
                group.addFile(fileName);
            }
        }
    }

    private int index;

    /** 一个Group对应一个文件目录*/
    private class Group {
        private String name;// 名字,一般为目录名,顶层为"R",此名字将用作R文件中的类名或内部类名
        private Array<Group> groups = new Array<AutoR.Group>();// 子Group,对应子目录
        private Array<String> fileNames = new Array<String>();// 文件名,只有名字,不包含后缀
        private Group parent;// 父Group,对应其父目录
        private String space = "";// 空格,用于格式化生成的java代码

        public Group(String dirName) {
            name = dirName;
        }

        @Override
        public String toString() {
            String fileString = "";
            for (String fileName : fileNames) {
                // 获取文件的输出路径
                String outPath = (outPath() + "/" + fileName).substring(1);// 去除最前面的斜杠
                // 生成单个变量的java代码
                fileString += space + " public static final String "
                        + fileName.toUpperCase(Locale.ENGLISH).replace(".", "_").replace("-", "_") + " = \"" + outPath
                        + "\";\n";
                System.out.println(">> " + (++index) + " <<------- " + outPath);
            }
            String groupString = "";
            // 生成子Group的代码
            for (Group g : groups) {
                groupString += g.toString();
            }
            // 返回Group对应的类和变量的java代码
            return "\n" + space + "public class " + name + " {\n" + fileString + groupString + space + "}\n";
        }

        // 添加一个子Group
        private void addGroup(Group g) {
            groups.add(g);
            g.parent = this;
            g.space = space + " ";
        }

        // 添加一个文件
        private void addFile(String fileName) {
            fileNames.add(fileName);
        }

        // 生成输出路径
        private String outPath() {
            if (parent == null) {
                return "";
            } else {
                return parent.outPath() + "/" + name;
            }
        }
    }
}

记得将变量assetPath的值该为你的android工程下的assets文件夹路径(绝对路径)。

3.运行AutoR文件,并刷新第一步中创建的包

点右键运行AutoR文件并刷新后,将会看到包下多了一个R文件。这个文件中就是自动生成的资源ID文件。
生成的文件如下格式:

    package com.mytian.mypet.R;

/** 此文件为自动生成,请勿随意手动修改 */
public class R {
    public static final String BG_PNG = "bg.png";
    public static final String GOBLINS_ATLAS = "goblins.atlas";
    public static final String GOBLINS_JSON = "goblins.json";
    public static final String GOBLINS_PNG = "goblins.png";
    public static final String SKIN1_SKIN = "skin1.skin";
    public static final String SKIN2_SKIN = "skin2.skin";

    public class fonts {
        public static final String MINI_TTF = "fonts/mini.ttf";
    }
}

R文件会自动为每个目录创建一个内部类,保持层级关系同资源目录中的一致。

4.引用R文件中的资源ID来访问资源

例如:

// R文件中的访问方式
FileHandle fh1 = Gdx.files.internal(R.fonts.MINI_TTF);
// 原始访问方式
FileHandle fh2 = Gdx.files.internal("fonts/mini.ttf");

5.最后记得每次改动资源之后,都要重新运行运行AutoR文件,并刷新R文件

结语

目录
相关文章
|
2月前
|
Java Android开发 C++
Android Studio JNI 使用模板:c/cpp源文件的集成编译,快速上手
本文提供了一个Android Studio中JNI使用的模板,包括创建C/C++源文件、编辑CMakeLists.txt、编写JNI接口代码、配置build.gradle以及编译生成.so库的详细步骤,以帮助开发者快速上手Android平台的JNI开发和编译过程。
93 1
|
4月前
|
存储 数据库 Android开发
安卓Jetpack Compose+Kotlin,支持从本地添加音频文件到播放列表,支持删除,使用ExoPlayer播放音乐
为了在UI界面添加用于添加和删除本地音乐文件的按钮,以及相关的播放功能,你需要实现以下几个步骤: 1. **集成用户选择本地音乐**:允许用户从设备中选择音乐文件。 2. **创建UI按钮**:在界面中创建添加和删除按钮。 3. **数据库功能**:使用Room数据库来存储音频文件信息。 4. **更新ViewModel**:处理添加、删除和播放音频文件的逻辑。 5. **UI实现**:在UI层支持添加、删除音乐以及播放功能。
|
5月前
|
Android开发
Android网络访问超时
Android网络访问超时
43 2
|
2月前
|
开发工具 git 索引
repo sync 更新源码 android-12.0.0_r34, fatal: 不能重置索引文件至版本 ‘v2.27^0‘。
本文描述了在更新AOSP 12源码时遇到的repo同步错误,并提供了通过手动git pull更新repo工具来解决这一问题的方法。
61 1
|
2月前
|
XML 安全 Android开发
Flutter配置Android和IOS允许http访问
Flutter配置Android和IOS允许http访问
56 3
|
2月前
|
存储 监控 数据库
Android经典实战之OkDownload的文件分段下载及合成原理
本文介绍了 OkDownload,一个高效的 Android 下载引擎,支持多线程下载、断点续传等功能。文章详细描述了文件分段下载及合成原理,包括任务创建、断点续传、并行下载等步骤,并展示了如何通过多种机制保证下载的稳定性和完整性。
38 0
|
2月前
|
Java 开发工具 Android开发
Android Studio利用Build.gradle导入Git commit ID、Git Branch、User等版本信息
本文介绍了在Android Studio项目中通过修改`build.gradle`脚本来自动获取并添加Git的commit ID、branch名称和用户信息到BuildConfig类中,从而实现在编译时将这些版本信息加入到APK中的方法。
45 0
|
2月前
|
监控 Java 开发工具
### 绝招揭秘!Android平台GB28181设备接入端如何实现资源占用和性能消耗的极限瘦身?
【8月更文挑战第14天】本文介绍在Android平台优化GB28181标准下设备接入的性能方法,涵盖环境搭建、SDK集成与初始化。重点讲解内存管理技巧如软引用、按需加载资源,以及通过硬件加速解码视频数据和图像缩放来减轻CPU与GPU负担。同时采用线程池异步处理视频流,确保UI流畅性。这些策略有助于提高应用效率和用户体验。
33 0
|
4月前
|
Android开发
Android studio 出现Plugin [id: ‘com.android.application‘, version: ‘8.1.0‘, apply: false] 问题解决办法
Android studio 出现Plugin [id: ‘com.android.application‘, version: ‘8.1.0‘, apply: false] 问题解决办法
707 1
|
4月前
|
缓存 Android开发 Kotlin
【安卓app开发】kotlin Jetpack Compose框架 | 先用OKhttp下载远程音频文件再使用ExoPlayer播放
使用 Kotlin 的 Jetpack Compose 开发安卓应用时,可以结合 OkHttp 下载远程音频文件和 ExoPlayer 进行播放。在 `build.gradle` 添加相关依赖后,示例代码展示了如何下载音频并用 ExoPlayer 播放。代码包括添加依赖、下载文件、播放文件及简单的 Compose UI。注意,示例未包含完整错误处理和资源释放,实际应用需补充这些内容。