I'm trying to use AsyncTransaction for inserting some object, but for the moment it is a failed...
I tried to debug, but without success either ...
See my code :
realm.executeTransactionAsync(
new Realm.Transaction() {
#Override
public void execute(#NonNull Realm realm) {
Log.i("Insert", "Insert start");
realm.insert(character);
}
}, new Realm.Transaction.OnSuccess() {
#Override
public void onSuccess() {
Log.i("Insert", "Insert complete");
finish();
}
}, new Realm.Transaction.OnError() {
#Override
public void onError(Throwable error) {
Log.i("Insert","Error " + error.getMessage());
}
});
When i debug, i see that I didn't go on any callback of the async-transaction, there is no log, there is nothing that can help me.
Thank in advance,
EDIT :
public RealmAsyncTask executeTransactionAsync(final Transaction transaction,
#Nullable final Realm.Transaction.OnSuccess onSuccess,
#Nullable final Realm.Transaction.OnError onError) {
checkIfValid();
//noinspection ConstantConditions
if (transaction == null) {
throw new IllegalArgumentException("Transaction should not be null");
}
// Avoid to call canDeliverNotification() in bg thread.
final boolean canDeliverNotification = sharedRealm.capabilities.canDeliverNotification();
// If the user provided a Callback then we have to make sure the current Realm has an events looper to deliver
// the results.
if ((onSuccess != null || onError != null)) {
sharedRealm.capabilities.checkCanDeliverNotification("Callback cannot be delivered on current thread.");
}
// We need to use the same configuration to open a background SharedRealm (i.e Realm)
// to perform the transaction
final RealmConfiguration realmConfiguration = getConfiguration();
// We need to deliver the callback even if the Realm is closed. So acquire a reference to the notifier here.
final RealmNotifier realmNotifier = sharedRealm.realmNotifier;
final Future<?> pendingTransaction = asyncTaskExecutor.submitTransaction(new Runnable() {
#Override
public void run() {
if (Thread.currentThread().isInterrupted()) {
return;
}
SharedRealm.VersionID versionID = null;
Throwable exception = null;
final Realm bgRealm = Realm.getInstance(realmConfiguration);
bgRealm.beginTransaction();
// NOTHING IS DONE AFTER IS POINT .....
try {
transaction.execute(bgRealm);
if (Thread.currentThread().isInterrupted()) {
return;
}
bgRealm.commitTransaction();
// The bgRealm needs to be closed before post event to caller's handler to avoid concurrency
// problem. This is currently guaranteed by posting callbacks later below.
versionID = bgRealm.sharedRealm.getVersionID();
} catch (final Throwable e) {
exception = e;
} finally {
try {
if (bgRealm.isInTransaction()) {
bgRealm.cancelTransaction();
}
} finally {
bgRealm.close();
}
}
final Throwable backgroundException = exception;
final SharedRealm.VersionID backgroundVersionID = versionID;
// Cannot be interrupted anymore.
if (canDeliverNotification) {
if (backgroundVersionID != null && onSuccess != null) {
realmNotifier.post(new Runnable() {
#Override
public void run() {
if (isClosed()) {
// The caller Realm is closed. Just call the onSuccess. Since the new created Realm
// cannot be behind the background one.
onSuccess.onSuccess();
return;
}
if (sharedRealm.getVersionID().compareTo(backgroundVersionID) < 0) {
sharedRealm.realmNotifier.addTransactionCallback(new Runnable() {
#Override
public void run() {
onSuccess.onSuccess();
}
});
} else {
onSuccess.onSuccess();
}
}
});
} else if (backgroundException != null) {
realmNotifier.post(new Runnable() {
#Override
public void run() {
if (onError != null) {
onError.onError(backgroundException);
} else {
throw new RealmException("Async transaction failed", backgroundException);
}
}
});
}
} else {
if (backgroundException != null) {
// FIXME: ThreadPoolExecutor will never throw the exception in the background.
// We need a redesign of the async transaction API.
// Throw in the worker thread since the caller thread cannot get notifications.
throw new RealmException("Async transaction failed", backgroundException);
}
}
}
});
return new RealmAsyncTaskImpl(pendingTransaction, asyncTaskExecutor);
}
I found the trick.
In my constructor, i add some RealmObject to a another, that create a error
(Can't not write on a non write transaction)
The second point, was i used beginTransaction() on the parent, but it block on the other part for asynctransaction
I change my code for using the RealmRecyclerView on the firstPart and i didn't have the problem anymore
Thanks
Related
Use case: We use hazelcast’s DurableExecutorService for distributed task execution. Before submitting a task, we wrap it into a custom future task. That we do to set context, get timestamps and for rollback on cancellation of task. Please find sample template below:
public class CustomFuture<V> extends FutureTask<V> {
private SomeCallableCommand<V> command;
private Context conext;
private Timestamp scheduledTimestamp, startTimestamp, finishTimestamp;
public CustomFuture(SomeCallableCommand<V> command) {
super(command);
this.command = command;
this.conext = conextHolder.getContext().copy();
scheduledTimestamp = new Timestamp(System.currentTimeMillis());
}
#Override
public void run() {
try {
startTimestamp = new Timestamp(System.currentTimeMillis());
setContext();
super.run();
} finally {
removeContext();
}
}
#Override
protected void done() {
super.done();
finishTimestamp = new Timestamp(System.currentTimeMillis());
}
#Override
public oolean cancel(oolean mayInterruptIfRunning) {
oolean cancelled = super.cancel(mayInterruptIfRunning);
if (cancelled) {
try {
command.rollback();
} catch (Exception e) {
_logger.error(“Unable to rollback command”, e); //$NON-NLS-1$
}
finishTimestamp = new Timestamp(System.currentTimeMillis());
}
return cancelled;
}
public String getExecutionStatus() {
if (finishTimestamp != null) {
if (isCancelled()) {
return “cancelled”; //$NON-NLS-1$
} else {
return “finished”; //$NON-NLS-1$
}
} else if (startTimestamp != null) {
return “executing”; //$NON-NLS-1$
}
return “scheduled”; //$NON-NLS-1$
}
public oolean isExecuting() {
return (startTimestamp != null && finishTimestamp == null);
}
public String getDescription() {
return getCommand().getDescription();
}
/**
* Duration, in milliseconds, between the time the task is scheduled and the time it starts.
* If there are no available threads in the pool, this is roughly the time a task spends in the executor queue.
* #return
*/
public long getIdleTimeMillis() {
if (scheduledTimestamp == null) {
return -1;
}
// Take difference from current time if task never executed
startTimestamp = (startTimestamp == null) ? new Timestamp(System.currentTimeMillis()) : startTimestamp;
return startTimestamp.getTime() – scheduledTimestamp.getTime();
}
}
Submitting to executor service:
// Wrapping up callable into CustomFuture and submitting it to durable executor service.
CustomFuture task = new CustomFuture(callableCommand);
executor.execute(task);
Problem: Executor service throws serialization exception, as FutureTask(extended by CustomTask) is not serializable.
Please let us know if there’s any alternative DistributedTask or some other FutureTask implementation to solve this problem.
The fact is that I need to simultaneously pull in data from the local database, from the server, while checking the connection to the Internet.
Without checking the internet is easy. But when I turn off mobile data, crashes.
I do not understand how to combine and decided to do this:
private void getCategories() {
composite.add(getDataFromLocal(context)
.observeOn(AndroidSchedulers.mainThread()).flatMap(new Function<PromoFilterResponse, ObservableSource<List<FilterCategory>>>() {
#Override
public ObservableSource<List<FilterCategory>> apply(PromoFilterResponse promoFilterResponse) throws Exception {
if (promoFilterResponse != null) {
PreferencesHelper.putObject(context, PreferencesKey.FILTER_CATEGORIES_KEY, promoFilterResponse);
return combineDuplicatedCategories(promoFilterResponse);
} else {
return Observable.empty();
}
}
})
.subscribe(new Consumer<List<FilterCategory>>() {
#Override
public void accept(List<FilterCategory> categories) throws Exception {
if (mView != null) {
mView.hideConnectingProgress();
if (categories != null && categories.size() > 0) {
mView.onCategoriesReceived(categories);
}
}
}
}));
composite.add(InternetUtil.isConnectionAvailable().subscribe(isOnline -> {
if (isOnline) {
composite.add(
getDataFromServer(context)
.flatMap(new Function<PromoFilterResponse, ObservableSource<List<FilterCategory>>>() {
#Override
public ObservableSource<List<FilterCategory>> apply(PromoFilterResponse promoFilterResponse) throws Exception {
if (promoFilterResponse != null) {
PreferencesHelper.putObject(context, PreferencesKey.FILTER_CATEGORIES_KEY, promoFilterResponse);
return combineDuplicatedCategories(promoFilterResponse);
} else {
return Observable.empty();
}
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(categories -> {
if (mView != null) {
mView.hideConnectingProgress();
if (categories != null && categories.size() > 0) {
mView.onCategoriesReceived(categories);
} else {
mView.onCategoriesReceivingFailure(errorMessage[0]);
}
}
}, throwable -> {
if (mView != null) {
if (throwable instanceof HttpException) {
ResponseBody body = ((HttpException) throwable).response().errorBody();
if (body != null) {
errorMessage[0] = body.string();
}
}
mView.hideConnectingProgress();
mView.onCategoriesReceivingFailure(errorMessage[0]);
}
}));
} else {
mView.hideConnectingProgress();
mView.showOfflineMessage();
}
}));
}
private Single<Boolean> checkNetwork(Context context) {
return InternetUtil.isConnectionAvailable()
.subscribeOn(Schedulers.io())
.doOnSuccess(new Consumer<Boolean>() {
#Override
public void accept(Boolean aBoolean) throws Exception {
getDataFromServer(context);
}
});
}
private Observable<PromoFilterResponse> getDataFromServer(Context context) {
return RetrofitHelper.getApiService()
.getFilterCategories(Constants.PROMO_FILTER_CATEGORIES_URL)
.subscribeOn(Schedulers.io())
.retryWhen(BaseDataManager.isAuthException())
.publish(networkResponse -> Observable.merge(networkResponse, getDataFromLocal(context).takeUntil(networkResponse)))
.doOnNext(new Consumer<PromoFilterResponse>() {
#Override
public void accept(PromoFilterResponse promoFilterResponse) throws Exception {
PreferencesHelper.putObject(context, PreferencesKey.FILTER_CATEGORIES_KEY, promoFilterResponse);
}
})
.doOnError(new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
LogUtil.e("ERROR", throwable.getMessage());
}
});
}
private Observable<PromoFilterResponse> getDataFromLocal(Context context) {
PromoFilterResponse response = PreferencesHelper.getObject(context, PreferencesKey.FILTER_CATEGORIES_KEY, PromoFilterResponse.class);
if (response != null) {
return Observable.just(response)
.subscribeOn(Schedulers.io());
} else {
return Observable.empty();
}
}
As you can see, connect the local database separately, simultaneously check the Internet and upload data from the server.
But it seems to me not quite right. Moreover, the subscriber is duplicated and so on.
I saw a lot of tutorials, where the combination of the local database with the API is described, but I did not see it at the same time processing the connection error with the Internet.
I think many people faced such a problem and how did you solve it?
Suppose You have two Obsevable: one from server and another from database
You can merge them into one stream like below:
public Observable<Joke> getAllJokes() {
Observable<Joke> remote = mRepository.getAllJokes()
.subscribeOn(Schedulers.io());
Observable<Joke> local = mRepository.getAllJokes().subscribeOn(Schedulers.io());
return Observable.mergeDelayError(local, remote).filter(joke -> joke != null);
}
Im' not android developer, but in my mind methods return types should be something like this:
//just for demonstration
static boolean isOnline = false;
static class NoInternet extends RuntimeException {
}
private static Completable ensureOnline() {
if (isOnline)
return Completable.complete();
else
return Completable.error(new NoInternet());
}
private static Single<String> getDataFromServer() {
return Single.just("From server");
}
private static Maybe<String> getDataFromLocal() {
return Maybe.just("From local");//or Maybe.never()
}
We can run all in parallel with Observable.merge. But what if error NoIternet happens? Merged observable will fail. We can use materialisation - transform all emission and errors to onNext value.
private static void loadData() {
Observable<Notification<String>> fromServer = ensureOnline().andThen(getDataFromServer()).toObservable().materialize();
Observable<Notification<String>> fromLocaldb = getDataFromLocal().toObservable().materialize();
Observable.merge(fromLocaldb, fromServer)
.subscribe(notification -> {
if (notification.isOnNext()) {
//calls one or two times(db+server || db || server)
//show data in ui
} else if (notification.isOnError()) {
if (notification.getError() instanceof NoInternet) {
//show no internet
} else {
//show another error
}
} else if (notification.isOnComplete()){
//hide progress bar
}
});
}
I'm writing an Android messaging application, and 1 class is calling another class, and I wish for the calling class to wait for the callee class to complete before carrying on.
Caller Class (MessageManagement) code snippet is as follows:
private static Messenger myMessenger;
try {
Message msg = Message.obtain();
msg.arg1 = constructedMessage.length();
msg.arg2 = -1;
msg.obj = constructedMessage;
Log.d(TAG, "Calling myMessenger.send()");
myMessenger.send(msg);
Log.d(TAG, "Sent");
} catch (Exception e) {
e.printStackTrace();
}
// Wait here until myMessenger completes its task
doOtherStuff();
Right now, doOtherStuff() starts and finishes before myMessenger starts. I need myMessenger to complete before doOtherStuff() starts.
I've read about wait() and notify() but I'm not sure how to implement it here, or whether it's the right choice.
Some background about the flow of the program. It's basically a messaging app that I inherited, so I'm not exactly sure of its framework. From what I can tell tracing the flow of the code:
When an SMS message is received, the SMS receiver BroadcastReceiver(SmsReceiver) handles it, getting the sender address and message body, then calling a SMS handler service(HandleSmsService), which then calls the caller class in a runnable with the following code:
HandleSmsService
public class HandleSmsService extends Service {
private String message;
private MessageManagement messageManager;
private Handler timeoutHandler = new Handler();
#Override
public void onStart(Intent intent, intent startid) {
message = intent.getExtras().getString("message");
messageManager = new MessageManagement(this);
timeoutHandler.postDelayed(runnable, 10);
}
private Runnable runnable = new Runnable() {
#Override
public void run() {
try {
messageManager.handleMessage(message);
stopSelf();
} catch (Exception e) {
e.printStackTrace();
}
}
};
MessageManagement is my caller class, and MessageManagement.handleMessage() is the top most code snippet presented earlier.
The MessageManagement.handleMessage() apparently calls another Handler in the callee class when it calls myMessenger.send(msg). This Handler code is as follows:
private Handler smsHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// do some stuff
}
};
I'm assuming the posted code is running on the MainThread and the reason why you are using a handler is that something asynchronous is done on another thread when receiving that message.
In that case, you can't use wait on the thread, as it will lock up the UI and probably cause an application not responding error.
Without changing too much of your code, one way to do it is to nest a listener in your constructedMessage for e.g.
public class DoStuffRequest {
private OnFinishListener mOnFinishListener;
private boolean isCanceled;
private String mMessage;
public interface OnFinishListener {
public void onFinish();
}
public DoStuffRequest(String message) {
mMessage = message;
}
public OnFinishListener getOnFinishListener() {
return mOnFinishListener;
}
public void setOnFinishListener(OnFinishListener onFinishListener) {
mOnFinishListener = onFinishListener;
}
public void cancel() {
isCanceled = true;
}
public void notifyFinish() {
if (!isCanceled && mOnFinishListener != null) {
mOnFinishListener.onFinish();
}
}
public String getMessage() {
return mMessage;
}
}
then use some along the line of this to get the ball rolling:
private static Messenger myMessenger;
private DoStuffRequest mRequest;
...
private void send(String message) {
mRequest = new DoStuffRequest(message);
mRequest.setOnFinishListener(new ConstructedMessage.OnFinishListener() {
#Override
public void onFinish() {
doOtherStuff();
}
});
try {
Message msg = Message.obtain();
msg.arg1 = constructedMessage.length();
msg.arg2 = -1;
msg.obj = constructedMessage;
Log.d(TAG, "Calling myMessenger.send()");
myMessenger.send(msg);
Log.d(TAG, "Sent");
} catch (Exception e) {
e.printStackTrace();
}
}
private void doThisIfYouWantToCancel() {
if (mRequest != null) {
mRequest.cancel();
}
}
your Handler/Service code can now call constructedMessage.finish() when the async stuff is done. Depending on what doOtherStuff() does (e.g. when manipulating the UI), you might want to do this on the MainThread (the code i've written above is NOT thread safe and i assume you are calling the listener on the MainThread).
Also remember to call constructedMessage.cancel() in case you do not want to get notified any more (e.g. you are leaving the activity/fragment).
this is just one way to do it, depending on your needs, some other methods might be a better choice.
I guess it should look something like this:
try {
Message msg = Message.obtain(handler, new Runnable() {
#Override
public void run() {
doOtherStuff();
}
});
msg.arg1 = constructedMessage.length();
msg.arg2 = -1;
msg.obj = constructedMessage;
Log.d(TAG, "Calling myMessenger.send()");
msg.sendToTarget();
Log.d(TAG, "Sent");
} catch (Exception e) {
e.printStackTrace();
}
The other way to do this using native means:
private static Messenger myMessenger = new Messenger(new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
// do something what you need
if (msg.getTarget() != null) {
msg.sendToTarget();
}
return false;
}
}));
try {
final Message msg = Message.obtain();
msg.setTarget(new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
doOtherStuff();
return false;
}
}));
msg.arg1 = constructedMessage.length();
msg.arg2 = -1;
msg.obj = constructedMessage;
Log.d(TAG, "Calling myMessenger.send()");
myMessenger.send(msg);
Log.d(TAG, "Sent");
} catch (final Exception e) {
e.printStackTrace();
}
I'm doing the multiple transaction in thread using spring transaction template, as per the spring transaction template it's thread-safe, however it's not releasing the connection for the long time. I'm using c3p0 connection pool configured by tomcat jndi context.
Here is the code snippet:
for (SearchProcessorType[] processorTypes : getProcessorChainTypes()) {
if (processorTypes.length > 1) {
ExecutorService doerService = Executors.newFixedThreadPool(processorTypes.length);
for (final SearchProcessorType processorType : processorTypes) {
if(searchData.getException() != null) {
if(searchData.getException() instanceof SearchException) {
throw (SearchException)searchData.getException();
}
throw new RuntimeException(searchData.getException().getMessage());
}
doerService.submit(new Runnable() {
#Override
public void run() {
try {
if (!searchData.isSkipType(processorType)) {
final SearchProcessor processsor = SearchProcessor.get(processorType);
if (authentication != null) {
SecurityContextHolder.getContext().setAuthentication(authentication);
}
if (processsor.isTransactional()) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
processsor.process(searchData, (SearchResponse<Object>) response);
}
});
} else {
processsor.process(searchData, (SearchResponse<Object>) response);
}
}
} catch (Exception ex) {
searchData.setException(ex);
}
}
});
}
doerService.shutdown();
while (!doerService.isTerminated()) {
// Wait for processors to get completed
}
if(searchData.getException() != null) {
if (searchData.getException() instanceof SearchException) {
throw (SearchException) searchData.getException();
} else {
throw new RuntimeException(searchData.getException());
}
}
} else if (!searchData.isSkipType(processorTypes[0])) {
SearchProcessor.get(processorTypes[0]).process(searchData, (SearchResponse<Object>) response);
}
}
I need to run two SwingWorkers. One of them can only run after the other is done. Can I run them like this?
class TestWorker {
private FirstWorker worker1;
private SecondWorker worker2;
public TestWorker() {
worker1 = new FirstWorker() {
#Override
protected void done() {
try {
result1 = get();
} catch (Exception) {
// exception handling
}
worker2 = new SecondWorker() {
#Override
protected void done() {
try {
result2 = get();
} catch (Exception) {
// exception handling
}
}
}
worker2.execute();
}
}
worker1.execute();
}
}
And how should I cancel them? Like this?
private cancel() {
if (worker2 != null) work2.cancel();
if (worker1 != null) work1.cancel();
}
Thanks a lot!
You can do it that way and it will work. However, unless there are other operations in your outer done that you're not showing, you would probably be better off with something that did both operations in doInBackground and returned an array of the results.