我有一个应用程序,我想使用ISBN搜索一本书并将其显示在屏幕上。 Book
对象存储在以ISBN为主键的Realm数据库中。如果它们未存储在数据库中,则从服务器异步检索它们(ASyncTask),然后将其存储在数据库中。
现在,我不熟悉Realm以及如何使用它。
在下面的代码中,ViewBookActivity
和MainController
会在同一个线程上运行,因此使用相同的数据库实例吗?从“静态类”返回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
}
答案 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
函数调用AsyncTask
和AsyncTask
在单独的线程上运行,因此当您致电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/