I'm currently loading an undefinite number of online images in a TableLayout. To do so I use a loadimage() function that fetch the image url and then load it like so (not actual code):
for(i=0;i<numberofimagetoload;i++)
{
loadimage(i);
}
public void loadimage(int imagenumber)
{
String url = serverimage.getURL(imagenumber)
ImageView.loadImageFromURL(url)
}
But images are loading in complete disorder, mainly because of the fetching time.
My question is: "How can I wait for the loadimage function to complete before moving on?"
Try Linked hash set. It prevents duplicate values and maintains the insertion order.
ArrayList can also help.
For network call use retrofit. It returns an object in response.
Related
I'm trying to add pagination in images data that I'm retrieving from firebase using Firebase Storage. I have 10 images there and I want to display 2 at a time in RecyclerView and when the user scrolls down to end vertically, it loads the next 2 until all the images are displayed, I have also read some documentation of Firebase where it was mentioned to use storage.list(int max results) method but with that, it only shows the number of results that I pass in the method for instance if I pass 2 it shows 2 images only, and I can't load anymore. I've found one method too on the official documentation i.e below: https://firebase.google.com/docs/storage/android/list-files
public void listAllPaginated(#Nullable String pageToken) {
FirebaseStorage storage = FirebaseStorage.getInstance();
StorageReference listRef = storage.getReference().child("files/uid");
// Fetch the next page of results, using the pageToken if we have one.
Task<ListResult> listPageTask = pageToken != null
? listRef.list(100, pageToken)
: listRef.list(100);
listPageTask
.addOnSuccessListener(new OnSuccessListener<ListResult>() {
#Override
public void onSuccess(ListResult listResult) {
List<StorageReference> prefixes = listResult.getPrefixes();
List<StorageReference> items = listResult.getItems();
// Process page of results
// ...
// Recurse onto next page
if (listResult.getPageToken() != null) {
listAllPaginated(listResult.getPageToken());
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
// Uh-oh, an error occurred.
}
});
}
I'm confused about how to use it, I don't know where I can get a page token from in order to provide a reference to open the next page
The thing is I have 200 images in my Firebase Storage and I directly want to apply pagination to the URLs that I'm retrieving from Firebase Storage.
To achieve that, you have two options. The first one would be to use StorageReference#listAll() method which:
List all items (files) and prefixes (folders) under this StorageReference.
And according to the official documentation regarding how to list files with Cloud Storage on Android, please note that:
Cloud Storage for Firebase allows you to list the contents of your Cloud Storage bucket. The SDKs return both the items and the prefixes of objects under the current Cloud Storage reference:
So you have to explicitly differentiate that (items vs. prefixes) in your application code and provide your own pagination algorithm.
The second option that you have, and the simplest one, in my opinion, would be to store the image URLs in the Firestore and implement the pagination as explained here:
Paginate data with query cursors
The question may sound weird. I have the following custom Object that I named ItemUser:
private UserInfo user_info;
private List<UserAchievement> user_achievements;
Both fields have getters and setters. My Firestore's database looks like this:
I would like to get the List size instead of re-calling the database and getting the size of the collection from a separated call that would consume much resources and take a lot of time (3-4s).
Firstly I'm getting the data using this:
mDB.collection("COLLECTION_NAME").document("USER_ID").get()
Inside the onCompletedListener I'm getting the custom object as the following:
ItemUser mUser = task.getResult().toObject(ItemUser.class);
Now, when I'm trying to get the size of the user_achievements, a NullPointerException popups saying I can't get the size of a null reference.
Therefore the user_achievements is null. I think the way I'm defining user_achievements in my custom Object is the reason for this exception.
The question is: How could this be possible done without recalling the database to count only the size?
I have the main custom Object ItemUser and its children are 'healthy' except user_achievements because of the way it's defined - List<UserAchievement>.
So, any suggestions to overpass this issue?
How could this be possible done without recalling the database to count only the size?
No, because Cloud Firestore is a real-time database and items can be added or deleted, so to get the size of a list you need to query the database and use a get() call.
If you want to count the number of documents beneath a collection (which can be added to a list), please see my answer from this post in which I have explained that task.getResult().size() can help you solve the problem.
Edit:
mDB.collection("COLLECTION_NAME").document("USER_ID").get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
int size = task.getResult().size();
Log.d(TAG, String.valueOf(size));
}
}
});
Ok, I am building an app in client and it needs to take data from DB. The app won't take all data from DB all at once but based on the pagination.
It has a simple textbox for user to enter text and a Button to search data.
Requirements:
-If the system already downloaded the data from a certain pageNo, then it won't call to server again.
-Each time it successfully called to server it needs to remember the pageNo, so that next time when user searching for that exact term it
will search for pageNo=pageNo+1 cos we searched for pageNo
already.
So here is what i did:
private HashMap<String, Integer> wordPageNoHashMap=new HashMap<String, Integer>();
button.addClickHandler(new ClickHandler(){
#Override
public void onClick(ClickEvent event) {
int pageNo=0;
if(wordPageNoHashMap.containsKey(word)){
pageNo=wordPageNoHashMap.get(word); //note: page no only increase if found result
}
else{
pageNo=1;
wordPageNoHashMap.put(word, pageNo);
}
callToDB(word,pageNo);
}
});
public void resultFromDB(ServerResult result){
int pageNo=result.getPageNo();
String word=result.getWord();
List<String> textResult=result.getResult();
if(textResult!=null && textResult.size()>0){
pageNo++;
wordPageNoHashMap.put(word, pageNo);
//show data here
}
else{
//show err here
}
}
I putting pageNo++ at the result not at the time we call.
Am i designning it ok?
or
Can u do a better design?
Assuming my understanding is correct, for a search query I will retrieve a reasonable number of records from the DB (say 500) and store it in something like a PagedListHolder and set the per page data to whatever number you want(say 20).
Now I have two options, when the user clicks next I will simply call the nextPage() and retrieve the data set. (This might be applicable for infinite loading)
Or if the user is clicks on a particular page number (conventional pagination), I will pass on the page number to the setPage() method and retrieve the elements from that page.
I have used the PagedlistHolder example to make it easy for you to understand. You may use any similiar Class if available, or you can write one.
I think this achieves your objective of not hitting the DB for the same set of data.
Let me know if it helped.
My Android app has an IntentService where it requests a list of MessageThreads objects from Facebook, parses the JSON response to build an ArrayList of the objects:
ArrayList<MessageThread> mMessageThreads = new ArrayList<MessageThread>();
Then it calls FB again in the same service, get the names for the MessageThread ids and matches them with the MessageThread objects. At this point I have an ArrayList with complete MessageThread objects and I insert them into an SQLite db.
// save to db and broadcast
for (MessageThread message : mMessageThreads) {
((FBClientApplication)getApplication()).getMessagesData().insertOrIgnore(message.toContentValues();
}
where:
public void insertOrIgnore(ContentValues values) {
SQLiteDatabase db = this.dbHelper.getWritableDatabase();
db.insertWithOnConflict(TABLE, null, values, SQLiteDatabase.CONFLICT_IGNORE);
}
Via ACRA reports I see that intermittently the line
for (MessageThread message : mMessageThreads)
throws an ConcurrentModificationException and the app forcloses. I haven't been able to isolate under what conditions. I read about this Exception and as I understand it it happens when we remove items from an ArrayList while iterating over it, but I'm not removing items from the list. Any pointers to help with this problem are greatly appreciated.
It also happens when you add items to an ArrayList while iterating over it, which it looks like you might do in this code.
In general, it's any "structural modification" that occurs to the ArrayList that can cause a CME while iterating.
What you can try to do is when you iterates your Collection instead of using the original you can make a copy right there, so you will have something like:
for (MessageThread message : new List<MessageThread>(mMessageThreads))
That will help you to avoid CuncurrentModificationException.
Now if you really want to get fancy you can protect your code using synchronized blocks such as:
synchronized(mMessageThreads){
for (MessageThread message : new List<MessageThread>(mMessageThreads)){
...
}
With this last pice of code you will restrict the access to mMessageThreads, if somebody it's using it it will get locked, so if somebody else wants to use it needs to wait until the first one is done.
I am making a web application, I want to store images in cache. Next time I don't want to get images from network. How can I implement using java, using WeakHashmap or Hashmap.
Let's say you have class NetworkImageService which fetches image remotely:
class NetworkImageService {
public Image getImage(name) { ... }
}
Then you can subclass it to have CachedNetworkImageService, like this:
class CachedNetworkImageService extends NetworkImageService {
Cache cache = new Cache();
public Image getImage(name) { ...
Image img = cache.get(name);
if( img == null ) {
img = super.getImage(name);
cache.put( name, img );
}
return img.
}
}
That's the basic idea of how I do usually (but it's pseudo-code). You can of course improve it and use for instance cache.contains() instead to check against null.
In the most basic case, you can substitute Cache with Hashmap. Otherwise you can improve this and implement various strategies in the cache. You can have an eviction policy that remove image after some time, or following a LIFO scheme.
The code above does not support concurrent access, so you would also need to consider that. The most basic way to make it thread-safe is to synchronize the method getImage().