如何在LibGDX中实现Sugar ORM

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在LibGDX中实现Sugar ORM相关的知识,希望对你有一定的参考价值。

我们是一群法国学生。我们正在开发一种需要数据库的游戏。为简化代码,我们使用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. 问题是你正在尝试扩展SugarRecord<T>,你的编译器/ IDE无法看到该类。
  2. 你试图扩展SugarRecord<T>的班级位于core/src/...,而不是android/src/...

What is the problem?

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

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

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

The Easy Way to Fix

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

The Right Way to Fix

如果你想以正确的方式解决它(并且可能会用你疯狂的编码能力给你的教授留下深刻的印象),你需要使用一种叫做依赖注入的东西。依赖注入是指我们采用代码所需的东西,并在运行时将它提供给代码。这意味着我们可以动态决定是否通过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);
    }
}

Bonus

另一个很酷的事情是,如果你以“正确”的方式实现这一点,它可以为测试提供一些很酷的可能性。如果要根据代码编写单元测试,可以创建一个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;
    }
}

以上是关于如何在LibGDX中实现Sugar ORM的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中实现 ORM

如何在 ORM 中实现一致的事务?

如何建立两个实体之间的关系 - Sugar ORM

从片段中获取意图值后,我如何在 recyclerview 项目中实现单击

如何在sqlite django ORM中实现have子句

如何使用对象列表在片段中实现newinstace模式[重复]