领域数据库 - 如何构建我的Android应用程序

时间:2015-09-20 23:39:34

标签: android design-patterns realm

我有一个应用程序,我想使用ISBN搜索一本书并将其显示在屏幕上。 Book对象存储在以ISBN为主键的Realm数据库中。如果它们未存储在数据库中,则从服务器异步检索它们(ASyncTask),然后将其存储在数据库中。

现在,我不熟悉Realm以及如何使用它。

在下面的代码中,ViewBookActivityMainController会在同一个线程上运行,因此使用相同的数据库实例吗?从“静态类”返回Realm对象会有问题吗?

如何保证调用MainController.getBook()始终返回一本书?它现在的工作方式是,当调用getBook并且书不在数据库中时,它返回null。

每个Activity中的changelisteners是否只使用MainController?我希望尽可能避免在活动中使用/引用Realm,并让它们通过MainController获取对象。

public class RealmActivity extends Activity {
    private Realm realm;

    @Override
     protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(this).build();
        Realm.deleteRealm(realmConfiguration); // Clean slate
        Realm.setDefaultConfiguration(realmConfiguration); // Make this Realm the default
    }

    @Override
     protected void onDestroy() {
        super.onDestroy();
    }
}

public class ViewBookActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = getIntent();
        ISBN = intent.getStringExtra("ISBN");
        setContentView(R.layout.activity_scan_result);
        setBook(ISBN);
    }

    public void setBook(String ISBN) {
        Book b = MainController.getBook(ISBN);
        // Display book on screen
    }
}

public class MainController {
    static Realm realm = Realm.getDefaultInstance();

    public static Book getBook(String isbn) {
        Book book = realm.where(Book.class)
                .equalTo("isbn", isbn)
                .findFirst();
        if (book == null) {
            NetworkController.getBook(isbn);
        } else {
            return book;
        }
        return null;
    }
}

public class NetworkController {
    private static BookHandler bookHandler = new BookHandler();
    public static void getBook(String isbn) {
        NetworkHelper.sendRequest(HTTPRequestMethod.GET,
                "/books/" + isbn, bookHandler);
    }
}


public class NetworkHelper {
    private static String host = "http://crowdshelf-dev.herokuapp.com";
    public static void sendRequest(final HTTPRequestMethod requestMethod, final String route, final ResponseHandler responseHandler) {
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected void doInBackground(Void... params) {
                try {
                    URL url = new URL(host + "/api" + route);
                    Log.d("NETDBTEST", "NetworkHelper request: " + requestMethod.toString() + " URL: " + url.toString());
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.connect();

                    BufferedReader bReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                    StringBuilder builder = new StringBuilder();
                    String line = null;
                    while ((line = bReader.readLine()) != null) {
                        builder.append(line).append("\n");
                    }
                    String jsonString = builder.toString();
                    responseHandler.handleJsonResponse(jsonString);
                return null;
                }
            }
        }.execute();
    }
}

public class BookHandler implements ResponseHandler {
    @Override
    public void handleJsonResponse(String jsonString) {
        Realm realm = Realm.getDefaultInstance();
        realm.beginTransaction();
        realm.createOrUpdateObjectFromJson(Book.class, jsonString);
        realm.commitTransaction();
        realm.close();
    }
}

public class Book extends RealmObject{
    @PrimaryKey
    private String isbn;
    // Other fields, getters and setters
}

1 个答案:

答案 0 :(得分:0)

1)首先,我不知道您为清理数据库而创建RealmActivity的原因。活动用于显示UI。如果它没有任何用途,那么将代码移动到其他类。就像你可以创建一个新的类RealmHandler并在那里保留这种代码。

2)你真的不需要创建一个静态函数来获取Realm对象。你可以拥有这样的MainController函数:

    public class MainController {


    public Book getBook(String isbn, Context context) {
        Realm realm = Realm.getDefaultInstance(context);

        Book book = realm.where(Book.class)
                .equalTo("isbn", isbn)
                .findFirst();
        if (book == null) {
            NetworkController.getBook(isbn);
        } else {
            return book;
        }
        return null;
    }
}

3)

  

我如何保证始终调用MainController.getBook()   还书?

您无法保证始终获得图书,例如在服务器上找不到图书,或者没有互联网连接。你必须手动处理这种情况。

sendBook函数调用AsyncTaskAsyncTask在单独的线程上运行,因此当您致电NetworkController.getBook(isbn)时,您无法返回服务器结果。获得结果的唯一方法是BookHandler. handleJsonResponse

顺便说一下,您不需要实现Handler来获取AsyncTask的结果。您可以覆盖onPostExecution函数来控制结果并在主线程上执行UI。

解决方案: 您可以根据自己的喜好以不同的方式处理此问题,其中一种方法是:

i)致电MainController.getBook()获取一本书。如果找不到Book,则运行NetworkController.getBook(isbn); - 这将在不同的线程上运行,当前线程将向您的Activity发回null。如果为null,则只需忽略它或相应地执行操作。

ii)在AsyncTask中,您可以首先显示ProgressBar,以便在从服务器获取数据时告诉用户正在处理的内容。您可以在onPreExecution的{​​{1}}函数中执行此操作。

iii)获得AsyncTask onPostExecution函数的结果。现在你回到主线程上了。如果您在同一个活动中,则可以直接更新您的UI,但在您的情况下则不是。您无法像在函数或更新UI中那样直接返回数据。

iv)您可以向MainActivity发送一个信号,表明网络呼叫已完成,新数据在数据库中,因此更新视图。您可以使用事件总线来实现此目的。我个人使用Otto by Square:http://square.github.io/otto/