Java (Android) File object too slow for AsyncTask - java

In an Android application I'm developing, I need to create a backup of a file and check on start up if it is identical to a remote file, if they are have different bytes then overwrite the backup with the remote file, afterwards check if they are the same, if they are identical return true. To do this I have the following process:
if(!backupFileExists(){
backupFile.createNewFile();
}
if(!checkBackupAndRemoteFilesAreIdentical()){ <----First Time
if(overwriteBackupFileWithRemoteFile()){
if(checkBackupAndRemoteFilesAreIdentical()){ <---- Second Time
return true;
}
}
}
return false;
The problem is when i run the code with AsyncTask, the second time i run checkBackupAndRemoteFilesAreIdentical() the value of the backupFile.length() hasn't updated, so it returns 0 which then returns false.
However if I add Thread.sleep(5000) the value of the backupFile.length() has time to update, it is successful and returns true.
Is there anyway to have this work without the Thread.sleep(5000) ?

This is normal, a network operation will take longer than loading your first activity.
If your 1st activity requires this file (or a portion of it) in order to work, then, you need to get it from the server (yes! in an async task) and update an object that your application will rely on. Decouple your application logic/design from source of data.
This problem is a generic one, what we do in general, we get as little data from the server for the first activity to work, then, when the user navigate to other screens, the data will be available at this stage.
I would suggest to think about your application data design. Which Server Data you need in every step and how this will be updated. If you are the owner of the server, and you are able to create new endpoints, try to design fast endpoints, less data, expose 'http head' operations to get only the content-length, ...
If you have more details on what you're trying to build, I will be more than happy to go through specifics.

Related

So am building an app and it has this feature that i dont know exactly how to go about it

I hope this makes a bit sense, basically, I have this feature in my app for tracking calories which consists of having this page that only appears the first time you use the feature and it asks you to add personal details (so it can make the right calculations), after that you get faced with a simple page that tracks your nutrition with a button for the user to insert the meals he has eaten, this page has to save the inserted data (via firebase) and then restart from 0 each and every day.
my first problem is I don't know how I make the page that only appears one time to save personal data(to be more precise I don't know how to make only appears the first time). and the second problem is how do I make the app automatically sends the given data at the end of each day?
interface in normal state, interface when adding the meals
hopefully, this 2 images will help you get a better grasp of what am trying to explain
don't worry am not looking for someone to straight up solve it all for me, I just need some orientation about what type of things/functions I need to do to solve these 2 problems
While #Narendra_Nath's answer might work, please note that is not a bulletproof solution. Why? Because a SharedPreferences doesn't persist across app uninstalls. This means that your user can install and uninstall the app and see the page as much as they want. So if you indeed want a user to see a screen only once, then you should consider storing that data in a database. Please note that SQLite isn't also a solution because when a user uninstalls the app, everything that is stored locally is wiped out. So what's the solution?
The best way to solve this would be to store the data in the cloud, either in Cloud Firestore or in the Realtime Database. So you can set a boolean variable and always check against it.
If you however intend to implement Firebase Authentication, then another solution would be to display the screen when your users are authenticated for the first time. So even if they will try to sign in on another device, install and uninstall the app, they won't be able to see the screen again.
Regarding the second problem, you should consider using Cloud Function for Firebase. It's the most elegant solution. If you want to somehow schedule an operation, then you should consider using Cloud Scheduler, as explained in my answer in the following post:
Is it not possible to have a code in the background who will be called every 24h?
Make the page that only appears one-time -> store a value in the shared preferences "isInfoShownToUser -> false" then do a check when the app starts to check if this value is false or true. If it is false show the "take the info" page .. then turn the value to false in the shared preferences.
How do I make the app automatically send data -> Use a Workmanager implementation to send data to the server (Firebase) at a particular time ..
Or use a implementation like the first one which uploads the data to the server just once everyday

Why are my Firebase In-app messages unreliable in production?

In-app messages work well in test mode, but seem to be very unreliable in production. I made campaigns with "Modals" as the message layout. The simplest possible messages, without any pictures. If I set countries as the targets, no messages seem to be shown in the target countries.
I have 2 campaigns without any country targets and those messages get shown, but still just sometimes. The first of these campaigns informs the user they have an opportunity to reach Level 1.
The message get shown about 50% of the times it should be shown (once per device). Sometimes the message get shown so quickly that it just flashes by, so it is impossible to read the text. It closes before the user closes it. The second of these campaigns inform the user when they have reached Level 1. It is the same result as described above here.
My calls to logEvent are from methods, which are directly called from the onresume method in the Main activity of the app. They are called according to certain conditions, not every time onresume is called. My calls look for instance like this:
FirebaseAnalytics.getInstance(this).logEvent("gyro_access", Bundle.EMPTY);
What can be done to make the In-app messages work in a reliable way in production?
I got this to work now. I used this method instead to trigger the messages:
FirebaseInAppMessaging.getInstance().triggerEvent()
I also updated Gradle, so the latest version of com.google.firebase:firebase-inappmessaging-display was used.
So the solution to my problem was either using the triggerEvent-method or updating Gradle.

Is there any way to guarantee that an ElasticSearch index has been deleted

In some automated tests, I am trying to delete and immediately recreate an index at the start of every test, using ElasticSearch's high-level rest client (version 6.4), as follows:
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);
deleteIndexRequest.indicesOptions(IndicesOptions.lenientExpandOpen());
client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
request.mapping("_doc", "{...}", XContentType.JSON);
client.indices().create(request, RequestOptions.DEFAULT);
The problem I have is that, intermittently, my tests fail at the point of creating the index, with an error:
{"error": {"root_cause":[{"type":"resource_already_exists_exception","reason":"index [(index-name)/(UUID)] already exists, ...,}] "status":400}
The more tests I run, the more likely I am to see the error, which seems to be a strong indicator that it's a race condition - presumably when I try to recreate the index, the previous delete operation hasn't always completed.
This is backed-up with the fact that if I put a breakpoint immediately after the delete operation, and manually run a curl request to look at the index that I tried to delete, I find that it's still there some of the time; on those occasions the error above appears if I continue the test.
I've tried asserting the isAcknowledged() method of the response to the delete operation, but that always returns true, even in cases when the error occurs.
I've also tried doing an exists() check before the create operation. Interestingly in that case if I run the tests without breakpoints, the exists() check always returns false (i.e. that the index doesn't exist) even in cases where the error will then occur, but if I put a breakpoint in before the create operation, then the exists() check returns true in cases where the error will happen.
I'm at a bit of a loss. As far as I understand, my requests should be synchronous, and from a comment on this question, this should mean that the delete() operation only returns when the index has definitely been deleted.
I suspect a key part of the problem might be that these tests are running on a cluster of 3 nodes. In setting up the client, I'm only addressing one of the nodes:
client = new RestHighLevelClient(RestClient.builder(new HttpHost("example.com", 9200, "https")));
but I can see that each operation is being replicated to the other two nodes.
When I stop a breakpoint before the create operation, in cases where the index is not deleted, I can see that it's not being deleted on any of the nodes, and it seems not to matter how long I wait, it never gets deleted.
Is there some way I can reliably determine whether the index has been deleted before I create it? Or perhaps something I need to do before I attempt the delete operation, to guarantee that it will succeed?
Hey I think there are quite a few things to think about. For one I'd test everything with curl or some kind of rest client till I start doing anything in code. Might just help you conceptually, but that's just my opinion.
This is one thing you should consider:
"If an external versioning variant is used, the delete operation automatically creates an index if it has not been created before (check out the create index API for manually creating an index)."
https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete.html
Which kind of would explain why exists() would return false. So if external versioning variant is used then the delete option would actually create an index with the same name prior to deleting it.
You mentioned about the fact that you are working with a three node cluster. Something you can try is:
"When making delete requests, you can set the wait_for_active_shards parameter to require a minimum number of shard copies to be active before starting to process the delete request." Here is a super detailed explanation which is certainly worth reading: https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html#index-wait-for-active-shards
I suggest you try:
curl -X DELETE 127.0.0.1:9200/fooindex?wait_for_active_shards=3
You said you have 3 nodes in your cluster,so this means that:"...indexing operation will require 3 active shard copies before proceeding, a requirement which should be met because there are 3 active nodes in the cluster, each one holding a copy of the shard."
This check is probably not 100% water tight since according to the docs here:https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html#index-wait-for-active-shards
"It is important to note that this setting greatly reduces the chances of the write operation not writing to the requisite number of shard copies, but it does not completely eliminate the possibility, because this check occurs before the write operation commences. Once the write operation is underway, it is still possible for replication to fail on any number of shard copies but still succeed on the primary. The _shards section of the write operation’s response reveals the number of shard copies on which replication succeeded/failed." so perhaps use this parameter, but have your code check the response to see if any operations failed.
Something you can also try is:
(I can't seem to find good documentation to back this info up)
This should be able to tell you if the cluster isn't ready to accept deletes.
curl -X DELETE 127.0.0.1:9200/index?wait_for_completion=true

Android Variables in Background

I'd like to know how I can set a variable that will stay the same after I have closed the app. In this case I don't want to make it with a SharedPreference or a DataBase.
Thanks in advance.
If the app gets closed any variable will be long gone on the next start.
The only way to keep data is to use persistence of some sort, and the most commonly used one is SharedPreferences.
You can alternatively write to a file, send your data to a server (and load it again on the next start), or use a database.
You can also make use of a Service which you keep running in the background, that keeps your values. But you will have no guarantee about when / how the system might stop it, and they would be lost—again—like before.
If you want to keep some value, you need to persist it.
Variables endure for the life cycle of an app. When user closes an app and that app is not running a service in the background everything is deleted. In some occurences(but this has a slight chance) static variables from previous session can be read incidentally if app is restarted again, but this is not a correct behaviour.
There are 3 ways to keep your data.
Write to file: You can create files in txt, json or in any other format you wish, and read from these files on runtime to get values from previous session. I don't prefer writing to file to keep data very much. If you don't know how to use database and want mess with it, you can use this.
Shared Preferences: This is generally for saving settings file with name and value pairs.
Writing to a database: You write your data to database. SQLite and Realm databases are the most popular ones.

Optimizing RMI Service Response

I am writing a server client application, best performance is a must; I am using RMI for server-client communication, the server uses mySQL database.
Now in the client side I have a method called
getLinks()
which invokes the same method on the server, the problem is that this method returns about 700Mb of data, which takes some time to get, and some more time to analyse.
And then I'm setting some values for each Link:
for (Link l : myService.getLinks()) l.setSelected(false);
What I have in mind right now is just getting the Link Ids first (since this would be a smaller data) and then using Asynchronous method to get each Link by Id (each link need one service call); and then setting the Link values.
Is this the best approach, is there another way of getting RMI data one by one (one method call and more than one return)?
Is there something like (yield return) in C#?
you can also make a pagination method, which receive the initial id (or position if the id's are not a consecutive) and the length, in this way you will not send all the id's twice
Are the Link objects remote objects? If not I don't really see the point of the code, as it only sets something locally in the client object which is immediately thrown away.
Assuming they are remote objects, it would be better to ship the entire update to the server and tell it to update the whole collection, something like setLinksSelected(boolean), where the server does the iteration.
But I would also be wary of updating, or even transporting, 700Mb of data via RMI whichever way you do it. That's a lot of data.

Categories

Resources