I'm migrating an app to Realm and I have an AsyncTask like this (simplified for brevity) that I used to search through a list of objects and filter it based on a search query:
private class SearchTask extends AsyncTask<String, Void> {
Realm realm;
#Override
protected List<SearchResults> doInBackground(String... params) {
String searchString = params[0];
realm = Realm.getDefaultInstance();
ArrayList<SearchResults> myFoos = FooHelper.getAllFoo(realm);
ArrayList<Foo> matches = new ArrayList<>();
for (Foo aFoo : myFoos){
if(!aFoo.getProperty().isEmpty()){
matches.add(aFoo);
}
}
realm.close();
return matches;
}
#Override
protected void onPostExecute(List<SearchResults> results) {
super.onPostExecute(results);
synchronized (SearchActivity.this){
//use search results
}
}
}
The problem is that when the results are returned they can't be accessed since they were created on another thread. The only solution I can think of is to return an array of primary keys from the async task then re-query for those again.
There has to be a better way of basically doing SEARCH on a realm. Any suggestions?
Until fairly recently realm did not support asynchronous queries at all.
You'll be happy to know this has changed but you don't do it via async task. Heres the documentation on how to do it:
https://realm.io/docs/java/latest/#asynchronous-queries
Related
I am experimenting with the integration of MongoDB on Android using Java as the language.
I followed the guide provided by MongoDB to configure the Atlas account and the Realm to communicate with.
After that I tried implementing CRUD methods, for insertions I did not encounter any problems, while for queries I did.
In particular to get all the objects of a certain class in a certain collection.
I used this method, as suggested by the wiki (https://www.mongodb.com/docs/realm/sdk/java/quick-start-local/)
RealmResults<Contact> contacts = backgroundThreadRealm.where(Contact.class).findAll();
inserted in a class made to handle background tasks:
public class BackgroundTasks implements Runnable {
#Override
public void run() {
String realmName = "MyApp";
RealmConfiguration config = new RealmConfiguration.Builder().name(realmName).build();
Realm backgroundThreadRealm = Realm.getInstance(config);
// all Tasks in the realm
RealmResults<Contact> contacts = backgroundThreadRealm.where(Contact.class).findAll();
Log.v("Contacts", String.valueOf(contacts.size()));
backgroundThreadRealm.close();
}
}
While in the MainActivity I inserted this (looks like a battlefield, maybe I inserted stuff I won't even need, but I was experimenting):
// initialize mongodb realm
realm.init(this);
// open realm
String realmName = "MyApp";
RealmConfiguration config = new RealmConfiguration.Builder().name(realmName).build();
backgroundThreadRealm = Realm.getInstance(config);
app = new App(new AppConfiguration.Builder(appId).build());
User user = app.currentUser();
mongoClient = user.getMongoClient("mongodb-atlas");
mongoDatabase = mongoClient.getDatabase("MyApp");
MongoCollection<Document> mongoCollection = mongoDatabase.getCollection("Contacts");
FutureTask<String> task = new FutureTask(new BackgroundTasks(), "test");
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.execute(task);
#Override
protected void onDestroy() {
super.onDestroy();
// the ui thread realm uses asynchronous transactions, so we can only safely close the realm
// when the activity ends and we can safely assume that those transactions have completed
backgroundThreadRealm.close();
}
I get no exceptions but the Log:
Log.v("Contacts", String.valueOf(contacts.size()));
results in 0.
Yet I have these contacts in the DB (they have different IDs):
And the related model in java:
#RealmClass
public class Contact extends RealmObject implements Serializable {
#PrimaryKey
private String nameSurname;
private int age;
// Drawable resource ID
private int imageResourceId;
public Contact() {
}
public Contact(String name, String surname, int age, int imageResourceId) {
this.nameSurname = name+" "+surname;
this.age = age;
this.imageResourceId = imageResourceId;
}
// In addition all the getters and setters
Can you help me?
It would also help to understand when it's appropriate to make synchronous and asynchronous calls, because I guess I've confused the implementations in general.
I'd like to use synchronous calls to get all the objects in the DB and then display them on the app, but it seems ill-advised online so I tried asynchronous, although I'm sure I did something wrong..
Thanks
I'm preety new in java/android.
I'm writing android app, which takes data from online api.
The problem is, I'm not sure if my concept is correct.
So my app send first request, but I need some of respond data to start next request.
Here is some example more or less how it looks right now:
public class MainActivity extends AppCompatActivity{
private int key = 0;
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new DownloadTask().execute("url of 1st request");
}
private class DownloadTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
try {
return downloadContent(params[0]);
} catch (IOException e) {
return "Unable to retrieve data. URL may be invalid.";
}
}
#Override
protected void onPostExecute(String result) {
if(key == 0){
// I know it's 1st request because my key == 0
JSONObject json = new JSONObject(result);
String id = json.getString("id");
key++;
new DownloadTask().execute( "url of 2nd request/" + id );
}else{
// I know it's 2st request because my key != 0
//here I'm getting data i need
// and I'm going to rest of my app
end(result);
}
}
}
private void end(String result){
//rest of my app
}
}
Code is working fine, but I wanted to know if it's proper way to do it.
Maybe you know another way to do that, I'm not asking for completly new code, but maybe some topic I should find and read.
If you want to do it asynchronously, i will recommend you using CompletableFuture's. It is very simple and look like that:
CompletableFuture
.supplyAsync(() -> yourFirstrequest())
.thenApplyAsync(yourInstance::getResponse)
.thenAcceptAsync(nextRequestClass::sendNextrequest);
or you can separate them by Future's like:
CompletableFuture firstRequest = CompletableFuture.supplyAsync(() -> yourFirstrequest());
CompletableFuture getResponse = firstRequest.thenApply(response -> someActionWithResponse(response));
it is very powerful and convenient framework.
Take a look at the java docs or android specific docs
I had to create an account to ask this question because I couldn't find the right way to do this. The only thing that comes close is this question here, but it doesn't go all the way and I'm still stuck. Here we go...
I'm trying to build an app following as much of the Architecture Components principles.
I'm currently trying to add a row in one of my database table, and get the ID of this row in return, to then insert a row in another table, with a reference to the first one.
I've created my database object:
#Entity(indices = {#Index("id")})
public class Search {
#PrimaryKey(autoGenerate = true) private int id;
...
And the corresponding DAO:
#Dao
public interface SearchDao {
#Insert
long insert(Search search);
...
As you can see, my DAO returns a long with the created ID. This is the behavior which was pointed out in the question I linked before, and documented here.
Since I'm following Android Architecture Components principles, I'm using a Repository class to do all my database related work. In this Repository, I've created a public method to insert a new object, which is creating and executing an AsyncTask to do the work:
public class Repository {
public void insertSearch(Search search) {
new insertSearchAsyncTask(this.mSearchDao).execute(search);
}
...
private static class insertSearchAsyncTask extends AsyncTask<Search, Void, Long> {
private SearchDao mAsyncTaskDao;
insertSearchAsyncTask(SearchDao dao) {
this.mAsyncTaskDao = dao;
}
#Override
protected Long doInBackground(final Search... params) {
long id = this.mAsyncTaskDao.insert(params[0]);
return id;
}
}
I know I can use the onPostExecute(long id) method to do stuff with the result of the doInBackground method, but this onPostExecute method cannot return anything to the insertSearch method, where I created the AsyncTask and executed it.
I know need to change the return type of my insertSearch method to long. However if I want to have something to return, I need to get the result of the execution of the AsyncTask. How can I do that?
I've tried this (according to the validated answer):
public class Repository {
private long result_id = 0;
public long insertSearch(Search search) {
new insertSearchAsyncTask(this.mSearchDao).execute(search);
return result_id;
}
private class insertSearchAsyncTask extends AsyncTask<Search, Void, Long> {
private SearchDao mAsyncTaskDao;
insertSearchAsyncTask(SearchDao dao) {
this.mAsyncTaskDao = dao;
}
#Override
protected Long doInBackground(final Search... params) {
long id = this.mAsyncTaskDao.insert(params[0]);
return id;
}
#Override
protected void onPostExecute(Long search_id) {
result_id = search_id;
}
}
}
But this feels very very wrong. I had to make the insertSearchAsyncTask class not-static, and I have to store the result of the insert in an attribute of my Repository.
I'm hoping there is a better/correct way of doing this.
I've also looked at other suggested answers on the link above, especially one about Delegates, but this doesn't suit my need as I need the method insertSearch to return the result, not another one called by the AsyncTask when it finishes.
I hope I've explained my problem clearly enough.
Any idea anyone?
Thanks a lot!!
I'm developing an Android app which has a lot of different requests for web services.
Every request is done in a subclass of AsyncTask in this manner:
(new AsyncTask<String, Void, Object1>() {
#Override
protected Object1 doInBackground(String... params) {
// network request and parsing to Object1
Object1 obj = new Object1();
obj1 = Parser.parseObject1(httpClient.execute(...));
return obj1;
}
#Override
protected Object1 onPostExecute(Object1... ret) {
return ret[0];
}
}).execute();
Object1 is a placeholder for different objects (Car, Bicycle, Truck...), each one in a different AsyncTask.
What are my alternatives other than returning the output of httpClient in a String and parsing in the Main Thread (UI Thread)? Avoid parsing in the UI Thread sounds reasonable if it's going to parse a lot of data, am I right?
-= UPDATE =-
Let me rephrase the question: I'm asking for a more intelligent way to develop my application avoiding being repetitive (AsyncTask has a lot of boilerplate code). The way I did was by creating 20+ subclasses of AsyncTask, which clearly is not DRY (do not repeat yourself).
In iOS we have lambda expressions so callbacks done in web requests are very easy and succinct.
You can create classes that contain most of your boilerplate code. E.g.
public class SpecialAsyncTask<T> extends AsyncTask<String, Void, T> {
public interface ResultProvider<T> {
T generateResultInBackground(String... params);
}
public interface ResultConsumer<T> {
void handleResultInForeground(T result);
}
private final ResultProvider<T> mProvider;
private final ResultConsumer<T> mConsumer;
private SpecialAsyncTask(ResultProvider<T> provider, ResultConsumer<T> consumer) {
mProvider = provider;
mConsumer = consumer;
}
#Override
protected T doInBackground(String... params) {
return mProvider.generateResultInBackground(params);
}
#Override
protected void onPostExecute(T result) {
mConsumer.handleResultInForeground(result);
}
public static <T> void execute(ResultProvider<T> provider, ResultConsumer<T> consumer, String... params) {
new SpecialAsyncTask<T>(provider, consumer).execute(params);
}
}
is an example how you could keep Object1 as a generic parameter while being able to specify an object that only needs to implement an interface to handle code that would otherwise have to be inside a new AsyncTask instance.
With a schema like that you could for example define some common code as static content:
class Providers {
public static final ResultProvider<String> HTTP_GETTER = new ResultProvider<String>() {
#Override
public String generateResultInBackground(String... params) {
return MagicHttpLibrary.getContentAsString(params[0]);
}
};
}
And you can just use Providers.HTTP_GETTER as parameter instead of implementing doInBackground. Or create a new class hierarchy of that implement one of those interfaces with different methods to access them (like factories for example)
Use of above example would look for example like below
class User extends Activity implements ResultConsumer<String> {
#Override
protected void onCreate(Bundle savedInstanceState) {
SpecialAsyncTask.execute(Providers.HTTP_GETTER, this , "http://google.com");
SpecialAsyncTask.execute(Providers.HTTP_GETTER, this , "http://yahoo.com");
}
#Override
public void handleResultInForeground(String result) {
Toast.makeText(this, result, Toast.LENGTH_LONG).show();
}
}
and there is more or less no repeated code besides the different method calls. It depends on how you want to use a class and what actually changes in the code to know how to design something like that. Identify the parts that need to be parametrized and move code that repeats into a re-used place (inheritance / composition).
Google's Volley HTTP request library does the request and parsing both in the same worker thread. So, that's a pretty good example to code by.
I'm trying to organize my app code separating AsyncTask classes from Activity or Fragments.
Surfing this forum I've learned about the "interface and listener" solution:
Interface.java
public interface TaskCompleteListener<T> {
public void onTaskComplete(T result);
}
AsyncTask.java
[...]
#Override
protected void onPostExecute(String JSONResponse) {
// using Gson library I convert JSONResponse string to POJO objects...
listener.onTaskComplete(result);
}
Activity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// start AsyncTask...
}
// Inner class implementing interface
public class LoadTaskCompleteListener implements TaskCompleteListener<Object> {
#Override
public void onTaskComplete(Object result) {
updateUI(result);
}
}
public void updateUI(Object result) {
// here you can manage UI updating, using result object
}
}
UPDATE
DataHelper.java
public class DataHelper {
private AsyncTaskCompleteListener<Object> listener;
public DataHelper(AsyncTaskCompleteListener<Obejct> listener) {
this.listener = listener;
}
// Multiple AsyncTask are defined here...
}
Well, I like this pattern so much, but: what if inside activity (or fragment)
I have multiple requests, with different type of results (single object, array, list)
and different business logic for managing them?
I can't handle that using a single callback. Any ideas? Should I add multiple
callbacks inside the interface? I'm really stuck with this.
I've a single file called DataHelper with multiple AsyncTask inside (something like web getters).
Naturally I can give up with this approach if you suggest any other alternative.
Why not return an array of Objects as a result? Then if you have more than one object inside that array you'll know the order in which you put them so you can use more than one set of results at a time.
public interface TaskCompleteListener<T> {
public void onTaskComplete(T... results);
}
Note that a 'handler' can be used instead of an async task and that each handler may return its message to the message looper with the msg wrapping different data. Easy to handle many data types because its just a message component.
Sample here
See 'process_entity() ' where the messages containing result component are sent by sample code.
Note that the definition of onTaskComplete() accepts as argument a generic type, type T:
onTaskComplete(T result);
this means that you can pass in any object type, single object, array, list, etc.
Regarding on how to handle different results using a single callback, you can use a Bundle to put the result in, associated with a key, and then in updateUI() check for that key and take appropriate actions.
Something like this (pseudocode, not sure if it will compile):
#Override
protected void onPostExecute(String JSONResponse) {
Bundle bundle = new Bundle();
bundle.putString("key_json_response", result); //put the response in a Bundle
listener.onTaskComplete(bundle);
}
// .....
public void updateUI(Object result) {
Bundle bundle = (Bundle)result;
if(bundle.containsKey("key_json_response")){
String json = bundle.getString("key_json_response");
// process json
} else if(bundle.containsKey("key_another_response")){
// process another response
}
}