如何在LibGDX中实现Sugar ORM

时间:2017-12-18 20:09:42

标签: java android libgdx sugarorm

我们是一群法国学生。我们正在开发一种需要数据库的游戏。为简化代码,我们使用LibGdx。 但是,似乎Sugar ORM不受应用程序的约束。我们无法扩展SugarRecord。

我放了AndroidManifest.xml和build.gradle(Module:Android)的代码。我们如何解决这个问题呢?

编辑:我们在Android文件夹中创建我们的类。 Sugar Orm没有在核心中定义。

<application
    android:name="com.orm.SugarApp"
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/GdxTheme">
    <meta-data
        android:name="DATABASE"
        android:value="AppName.db" />
    <meta-data
        android:name="VERSION"
        android:value="1" />
    <meta-data
        android:name="QUERY_LOG"
        android:value="true" />
    <meta-data
        android:name="DOMAIN_PACKAGE_NAME"
        android:value="com.AppName" />

build.gradle(模块:Android):

dependencies {
    compile 'com.github.satyan:sugar:1.3'
    //other dependencies
}

谢谢!

1 个答案:

答案 0 :(得分:0)

的Bonjour!我将做出一些假设(如果他们错了,请纠正我,我们将在下面提炼答案):

  1. 问题是您正在尝试扩展SugarRecord<T>,而您的编译器/ IDE无法看到该类。
  2. 您尝试扩展SugarRecord<T>的课程位于core/src/...,而不是android/src/...
  3. 有什么问题?

    当您编写软件时(如果它的游戏无关紧要),您需要注意如何将软件划分为多个部分以及这些部分如何交互。特别是,您希望能够知道对一个部件的更改何时会破坏另一个部件。

    libGDX将其代码分为基于平台的部分(这就是为什么你有核心项目和桌面项目和 android 项目)。 核心应该具有与平台无关的所有代码(即,无论您是在PC还是移动设备上,这些内容都是相同的),而您的其他项目则负责平台特定的东西。

    Sugar ORM是一个特定于Android的东西,所以你(正确地)将它放入你的 android gradle项目依赖项中。但是,这意味着只有android/src文件夹下的代码才能了解Sugar ORM并且可以使用它。我非常确定导致您出现问题的原因。问题是,您要保存的类几乎肯定在core/src下,并且属于,那么我们如何解决?

    简易修复方法

    如果您只打算让您的程序在Android上运行(并且您的项目有一个紧迫的截止日期:wink :),您可以将依赖项从Android gradle项目移动到Core gradle项目。这将允许您在任何地方使用这些类,但是当您尝试构建Desktop / iOS / HTML项目时,这将意味着麻烦。

    正确的修复方法

    如果你想以正确的方式修复它(并且可能会给你的教授留下令人难以置信的编码能力),你需要使用一种叫做依赖注入的东西。依赖注入是指我们采用代码所需的东西,并在运行时将它提供给代码。这意味着我们可以动态决定是否通过 android 数据库或 iOS 数据库。就像@ Arctic45在评论中所说的那样,libGDX Wiki对这种技术有一个简要的概述,但我们会详细介绍一下。

    对于这个例子,我将假设一个Monster类的简单游戏,看起来像这样:

    // Lives in core
    public class Monster {
        public String name;     // prénom
        public int hitpoints;   // points de dommage
    
        public Monster() {
            this.name = "Tim the Unnamed";
            this.hitpoints = 1;
        }
        public Monster(String name, int hitpoints) {
            this.name = name;
            this.hitpoints = hitpoints;
        }
        @Override
        public String toString() {
            return String.format("{name: '%s', hitpoints: %n}", this.name, this.hitpoints);
        }
    
        public void attack(Monster other) {
            // Game specific logic...
        }
    }
    

    现在我们希望能够将其保存到数据库中,但我们不知道它是Android数据库还是iOS数据库,甚至可能是数据库的数据库在某个地方(如Firebase)。我们如何处理?

    我们所做的是为核心提供DatabaseWrapper界面。这个界面提供了我们需要的方法,但没有包括它们如何实现 - 它就像一个承诺。 核心可以计划使用这些方法,然后一旦我们知道我们所处的平台,我们就会提供它们。以下是一个示例应用程序,它说明了这种技术:

    // Lives in core
    // Replace with your application
    public class LibGDXTestbed extends ApplicationAdapter {
        DatabaseWrapper database;
    
        public LibGDXTestbed() { } // For platforms that don't have databases to inject.
    
        public LibGDXTestbed(DatabaseWrapper database) {
            this.database = database;
        }
    
        /**
         * For demo purposes, add a new randomized monster to the database, then log a list of all the
         * monsters created to date.
         */
        @Override
        public void create () {
            if(database != null) {
                createMonster();
                printMonsters();
            } else {
                Gdx.app.error("WARNING", "No database provided. Load/Save Functionality Disabled.");
            }
        }
    
        // Helper method
        private void createMonster() {
            // Create a set of names we can use for new monsters.
            String[] names = {"Fred", "Mary", "Jean", "Tim"};
    
            String randomName = new Array<String>(names).random();
            int randomHP = MathUtils.random(100);
            database.saveMonster(new Monster(randomName, randomHP));
        }
    
        // Helper method
        private void printMonsters() {
            for(Monster monster : database.getMonsters()) {
                Gdx.app.log("DEBUG", monster.toString());
            }
        }
    }
    

    请注意,上述内容并不了解有关Sugar ORM的任何信息,也无法对数据库的工作方式做出任何假设。

    包装器本身看起来像这样:

    // Located in core
    public interface DatabaseWrapper {
        public void saveMonster(Monster monster);
        public List<Monster> getMonsters();
    }
    

    现在这有点人为(并且可以重构为更通用),但它说明了这一点。

    接下来,我们创建实现此数据库所需的特定于android的代码。首先,我们将创建一个SugarMonster类,其扩展为SugarRecord(因为我们不希望使用我们的核心Monster类本身):

    // Lives in android/src
    public class SugarMonster extends SugarRecord<SugarMonster> {
        public String name;     // prénom
        public int hitpoints;   // points de dommage
    
        public SugarMonster() {
        }
    
        public SugarMonster(Monster monster) {
            this.name = monster.name;
            this.hitpoints = monster.hitpoints;
        }
    }
    

    我们还需要一个SugarWrapper类,它在幕后使用Sugar ORM实现我们的DatabaseWrapper类:

    // Lives in android/src
    public class SugarWrapper implements DatabaseWrapper {
        @Override
        public void saveMonster(Monster monster) {
            SugarMonster data = new SugarMonster(monster);
            data.save();
        }
    
        @Override
        public List<Monster> getMonsters() {
            List<SugarMonster> records = SugarMonster.listAll(SugarMonster.class);
            ArrayList<Monster> monsters = new ArrayList<>();
            for(SugarMonster record : records) {
                monsters.add(new Monster(record.name, record.hitpoints));
            }
            return monsters;
        }
    }
    

    最后,我们需要更新我们的AndroidLauncher类以注入我们的数据库包装器:

    // Lives in android/src
    public class AndroidLauncher extends AndroidApplication {
        @Override
        protected void onCreate (Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
            initialize(new LibGDXTestbed(new SugarWrapper()), config);
        }
    }
    

    加成

    另一个很酷的事情是,如果你实施这个&#34;对&#34;方式,它为测试提供了一些很酷的可能性。如果要针对代码编写单元测试,可以创建TestWrapper来实现DatabaseWrapper并使用静态数据模拟数据库功能:

    public class TestWrapper implements DatabaseWrapper {
        List<Monster> monsters;
        public TestWrapper() {
            this.monsters = new ArrayList<>();
            this.monsters.add(new Monster("Tim the Tester", 123));
        }
        @Override
        public void saveMonster(Monster monster) {
            this.monsters.add(monster);
        }
    
        @Override
        public List<Monster> getMonsters() {
            return this.monsters;
        }
    }