How to display image from URL from Firestore - android

I could get it right with Realtime Database, but I went over to Cloud FireStore and now I'm running into some problems. I want to display an image that is in Firestore via a download URL from Firestore. I'm using the FirestoreRecyclerAdapter, I want to populate an imageView in a RecyclerView.
I tried to do it the same way it worked in Realtime Database, but I get an error, but this time I get an error telling me NumberFormatException: For input string:
#Override
protected void onBindViewHolder(#NonNull NoteHolder holder, int p,
#NonNull promo_one_data promo_one) {
holder.produk_product.setText(promo_one.getProduct());
holder.produk_discription.setText(promo_one.getDiscription());
holder.produk_discription_two.setText(promo_one.getDiscription_two());
holder.produk_size.setText(promo_one.getSize());
holder.produk_product_two.setText(promo_one.getProduct_two());
holder.produk_price.setText(promo_one.getPrice());
holder.produk_department.setText(promo_one.getDepartment());
if ("1".equals(holder.produk_department.getText().toString())) {
holder.itemView.setBackgroundColor(Color.parseColor("#FFCDD2"));
} else if ("2".equals(holder.produk_department.getText().toString())) {
holder.itemView.setBackgroundColor(Color.parseColor("#FFA6AF"));
} else {
holder.itemView.setBackgroundColor(Color.WHITE);
}
holder.produk_image.setImageResource(Integer.parseInt(promo_one.getImage()));
Picasso.get().load(promo_one.getImage()).into(holder.produk_image);
}
#NonNull
#Override
public NoteHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_promo, parent, false);
return new NoteHolder(v);
}
How can I display an image in a recyclerView from Cloud Firestore. It shows me "java.lang.NumberFormatException: For input string:...(the URL here), which I could gather means the string is to long to convert into a int to fill the imageView. How do I do this, or is there a way around? Or even how do I shorten the URL, or maybe is there a way to do it and not use Picasso?

Your problem is this line :
holder.produk_image.setImageResource(Integer.parseInt(promo_one.getImage()));
you should not be trying to parse the URL of the image to an integer here, the next line using Picasso:
Picasso.get().load(promo_one.getImage()).into(holder.produk_image);
should handle the image loading for you.

Related

Recyclerview dont show images

i have been trying to display images in my recyclerview, i had seen a lot of tutorials, but i can't.
this is my onBindViewholder in my adapter class
#Override
public void onBindViewHolder(#NonNull final cowviewHolder holder, int position) {
final Cow vacaslist = vacas.get(position);
holder.textViewinterno.setText(vacaslist.interno);
holder.textViewsiniiga.setText(vacaslist.siniiga);
Picasso.get().load(vacaslist.ulr)
.resize(80,80).centerCrop().error(R.drawable.ic_imageinf).into(holder.imageviewrec);
This is my database in firebase, im taking the images from storage
Thanks.. If need more info let me know
I think the problem is your ulr variable name because on firebase it is url so, if you are instantiating your Cow object using following syntax:
ref.child("Vacas").child("$id").getValue(Cow.class);
Then ulr will be null.

Android Firestore "whereEqualTo" and "whereArrayContains" alongwith orderBy clause not working [duplicate]

I have a RecyclerView that utilizes the FireaseUI and orders all objects from the "Polls" node by the "timestamp" field (sequentially).
New Fragment - .onViewCreated()
Query queryStore = FirebaseFirestore.getInstance()
.collection(POLLS_LABEL)
.orderBy("timestamp", Query.Direction.ASCENDING);
//Cloud Firestore does not have any ordering; must implement a timestampe to order sequentially
FirestoreRecyclerOptions<Poll> storeOptions = new FirestoreRecyclerOptions.Builder<Poll>()
.setQuery(queryStore, Poll.class)
.build();
mFirestoreAdaper = new FirestoreRecyclerAdapter<Poll, PollHolder>(storeOptions) {
#Override
protected void onBindViewHolder(#NonNull final PollHolder holder, final int position, #NonNull Poll model) {
holder.mPollQuestion.setText(model.getQuestion());
String voteCount = String.valueOf(model.getVote_count());
//TODO: Investigate formatting of vote count for thousands
holder.mVoteCount.setText(voteCount);
Picasso.get()
.load(model.getImage_URL())
.fit()
.into(holder.mPollImage);
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent toClickedPoll = new Intent(getActivity(), PollHostActivity.class);
String recyclerPosition = getSnapshots().getSnapshot(position).getId();
Log.v("Firestore ID", recyclerPosition);
toClickedPoll.putExtra("POLL_ID", recyclerPosition);
startActivity(toClickedPoll);
}
});
}
I have another layout in my app that subscribes to this same node, but instead queries by "followers" and then by "timestamp.:
Following Fragment - .onViewCreated()
Query queryStore = FirebaseFirestore.getInstance()
.collection(POLLS_LABEL)
.whereArrayContains("followers", mUserId)
.orderBy("timestamp", Query.Direction.ASCENDING);
FirestoreRecyclerOptions<Poll> storeOptions = new FirestoreRecyclerOptions.Builder<Poll>()
.setQuery(queryStore, Poll.class)
.build();
mFirestoreAdaper = new FirestoreRecyclerAdapter<Poll, PollHolder>(storeOptions) {
#Override
protected void onBindViewHolder(#NonNull final PollHolder holder, final int position, #NonNull Poll model) {
holder.mPollQuestion.setText(model.getQuestion());
String voteCount = String.valueOf(model.getVote_count());
//TODO: Investigate formatting of vote count for thousands
holder.mVoteCount.setText(voteCount);
Picasso.get()
.load(model.getImage_URL())
.fit()
.into(holder.mPollImage);
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent toClickedPoll = new Intent(getActivity(), PollHostActivity.class);
String recyclerPosition = getSnapshots().getSnapshot(position).getId();
Log.v("Firestore ID", recyclerPosition);
toClickedPoll.putExtra("POLL_ID", recyclerPosition);
startActivity(toClickedPoll);
}
});
}
In the first scenario, UI items populate, in real-time, into my RecyclerView as they are added to Firebase. However, when I query by ".whereArrayContains," I do not get this same behavior, and I was curious as to why. The items only reappear when I restart the application:
Edit:
I commented out the below line:
// .whereArrayContains("followers", mUserId)
and the behavior performed as expected, therefore I can isolate the issue to the .whereArrayContains() query. It is the only difference between each Fragment.
This is happening because when you are using whereArrayContains() and orderBy() methods in the same query, an index is required. To use one, go to your Firebase Console and create it manually or if you are using Android Studio, you'll find in your logcat a message that sounds like this:
W/Firestore: (0.6.6-dev) [Firestore]: Listen for Query(products where array array_contains YourItem order by timestamp) failed: Status{code=FAILED_PRECONDITION, description=The query requires an index. You can create it here: ...
You can simply click on that link or copy and paste the url into a web broswer and you index will be created automatically.
Why is this index needed?
As you probably noticed, queries in Cloud Firestore are very fast and this is because Firestore automatically creates an indexes for any fields you have in your document. When you need to order your items, a particular index is required that should be created as explained above. However, if you intend to create the index manually, please also select from the dropdown the corresponding Array contains option, as in the below image:

Retrieve posts from firebase database using a field within the child

project tree image in this link
I am developing a social media app
In the Firebase database,
There will be Users node,posts node,likes node and request type nodes
Users nodes contains fields which represents users details and it has a uid which is like a key
Under the posts node, there will be a postskey within it there will be the details of the posts like uid,profileimage,postimage, description,date,time,fullname
The uid in the posts node is the uid in the Users node
I successfully uploaded images into the firebase storage and its url would be in the postimage field within the child node
To retrieve the particular users posts and display it in the particular users profile I tried this code which I enclosed in the images
But the posts of the user doesn't shows and white blank activity only shows up
Can u guide me to achieve my expected result
I am not good in English
Sorry,if you cannot understand my question because of my poor English
within OnCreate ,
mAuth=FirebaseAuth.getInstance();
currentUserID=mAuth.getCurrentUser().getUid();
PostsRef=FirebaseDatabase.getInstance().getReference().child("Posts");
myPostsList=(RecyclerView)findViewById(R.id.my_all_posts_list);
myPostsList.setHasFixedSize(true);
LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);
linearLayoutManager.setReverseLayout(true);
linearLayoutManager.setStackFromEnd(true);
myPostsList.setLayoutManager(linearLayoutManager);
DisplayMyAllPosts();
within Displaymyallposts method
private void DisplayMyAllPosts() {
Query myPostsQuery=PostsRef.orderByChild("uid").startAt(currentUserID).endAt(currentUserID+"\uf8ff");
FirebaseRecyclerOptions<Posts> options=new FirebaseRecyclerOptions.Builder<Posts>().setQuery(myPostsQuery,Posts.class).build();
FirebaseRecyclerAdapter<Posts,MyPostsViewHolder> firebaseRecyclerAdapter=new FirebaseRecyclerAdapter<Posts, MyPostsViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull MyPostsViewHolder holder, int position, #NonNull Posts model) {
holder.fullname.setText(model.getFullname());
holder.date.setText(model.getDate());
holder.time.setText(model.getTime());
holder.description.setText(model.getDescription());
Picasso.get().load(model.getProfileimage()).into(holder.profileimage);
Picasso.get().load(model.getPostimage()).into(holder.postImage);
}
#NonNull
#Override
public MyPostsViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view=LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.all_posts_layout,viewGroup,false);
MyPostsViewHolder viewHolder=new MyPostsViewHolder(view);
return viewHolder;
}
};
myPostsList.setAdapter(firebaseRecyclerAdapter);
}
public static class MyPostsViewHolder extends RecyclerView.ViewHolder{
TextView fullname,date,time,description;
CircleImageView profileimage;
ImageView postImage;
public MyPostsViewHolder(#NonNull View itemView) {
super(itemView);
fullname=itemView.findViewById(R.id.post_user_name);
date=itemView.findViewById(R.id.post_date);
time=itemView.findViewById(R.id.post_time);
description=itemView.findViewById(R.id.post_description);
profileimage=itemView.findViewById(R.id.post_profile_image);
postImage=itemView.findViewById(R.id.post_image);
}
}
The post is retrieved
it's because of my silly mistakes
I forgot to give startlistening
That's the reason for not been able to retrieve the post
But there is an another problem
Except the image all other fields are displaying
But not the image
The image is still blank

how to update recyclerview after pulling data from server?

If i had to send a request to get data within onBindViewHolder(), how can i update view after data comes back from server?
what I have now is that I cache the data along with row position, so that next time when user scrolls to that row, I can display info right away.
but there are 2 other issues I don't know how to solve.
I scroll the list to view item at position 10, 11 and 12. I decided to wait for data to come back. do i call notifyDataSetChanged() after? because onBindViewHolder already been called by the time data comes back and view would just remained empty, but I also don't think by calling notifyDataSetChanged() after each request would be a good idea.
I start to view the list at position 0 and keep scrolling to position 10. app sends out request to pull data for position 0 to 10. since the request at 0 is sent out first, more likely it would get back first or at least sooner than position 10, but by that time I'm already viewing the item at position 10. my view would start changing if all requests are back in order, so it would show data for position 0 then keep updating all the way to 10.
is it a bad practice to load data from server as recyclerview scrolls? but by doing this would save me a lot of time, and I guess for user too? because instead of sending all the requests ahead of time, user get to see partial data while other data are being loaded in the background.
Thanks!!!
EDITED
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.ViewHolder> {
private Context ctx;
private ArrayList<Photo> alPhotos = new ArrayList<>();
private HashMap<String, Drawable> hmImages = new HashMap<>();
public TestAdapter(Context ctx, ArrayList<Photo> alPhotos) {
this.ctx = ctx;
this.alPhotos = alPhotos;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_photo_brief, parent, false));
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Photo photo = alPhotos.get(position);
loadRemoteImage(photo.IMG, holder.ivThumb, true);
holder.tvEmail.setText(photo.EMAIL);
}
#Override
public int getItemCount() {
return alPhotos.size();
}
private void loadRemoteImage(final String imgUrl, final ImageView view, final boolean cache) {
if (hmImages.containsKey(imgUrl)) {
view.setImageDrawable(hmImages.get(imgUrl));
} else {
final WeakReference<ImageView> weakView = new WeakReference<>(view);
RequestManager.getManager().add(new Request<>(imgUrl, new DrawableParser(), new RequestCallback<Drawable>() {
#Override
public void onFinished(Request<Drawable> request, Response<Drawable> response) {
if (cache) hmImages.put(imgUrl, response.result);
ImageView view = weakView.get();
if (view != null) {
view.setImageDrawable(response.result);
}
}
#Override
public void onError(Request<Drawable> request, Response<Drawable> response) {
}
#Override
public void onTimeout(Request<Drawable> request, Response<Drawable> response) {
}
})
);
}
}
public class ViewHolder extends RecyclerView.ViewHolder {
private ImageView ivThumb;
private TextView tvEmail;
public ViewHolder(View itemView) {
super(itemView);
findViews();
}
private void findViews() {
ivThumb = (ImageView) itemView.findViewById(R.id.ivThumb);
tvEmail = (TextView) itemView.findViewById(R.id.tvEmail);
}
}
}
It's a good idea to load data while scrolling, a lot of popular apps do that. I personally use WeakReference in this case. I store a weak reference to the view holder in my model when I start loading data. If the reference is still valid by the time I get the response then it makes sense to update the view. If there is no view holder in memory then it's already been recycled and I don't have to update anything anymore.
When onViewRecycled is called you can clear the weak reference and also consider cancelling the network request (depends on your needs).
Caching works perfect with this model, you just insert this logic before making a network request. Again, this depends on your needs, maybe you don't need caching at all, or maybe your data is rarely updated then it makes sense to always use cache until some event.
In my app I also use EventBus, it helps me with event handling, but it is absolutely fine to just use Android SDK and support library.
You can also add a ScrollListener if you need to differentiate the item behavior depending on whether user scrolls the list right now. E.g. in my app I animate the data if list loaded and user wasn't scrolling it (improves interaction with the user). When user scrolls I load data as is, because it will be too much motion on the screen if I animate data.

Android How to save msg into local storage?

I'm pretty new to the Android developer. I'm currently making an simple message app. so i want to store all the text message I received from node server. I don't really now how should i do this.
the msg I received from node server is JSONObject like:
{"name":"XX", "id":"XX","message":"xxxxxxxx"}
and I'm using a Custom ArrayAdepter to display the text:
public class ChatArrayAdapter extends ArrayAdapter<Text> {
private TextView text,avatar;
private List<Text> msgcontx = new ArrayList<Text>();
private LinearLayout wrapper;
#Override
public void add(Textobject){
msgcontx.add(object);
super.add(object);
}
public ChatArrayAdapter(Context context,int textViewResourceId) {
super(context, textViewResourceId);
}
public int getCount(){
return this.msgcontx.size();
}
public Text getItem(int index){
return this.msgcontx.get(index);
}
public View getView(int position,View convertView,ViewGroup parent){
View row = convertView;
if(row == null){
LayoutInflater inflater = (LayoutInflater)this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.chat_listview, parent,false);
}
wrapper = (LinearLayout)row.findViewById(R.id.wrapper);
Text comment = getItem(position);
avatar = (TextView)row.findViewById(R.id.avatar);
avatar.setText(comment.userID);
avatar.setVisibility(comment.left? View.VISIBLE: View.GONE);
text = (TextView)row.findViewById(R.id.comment);
text.setText(comment.comment);
// chat background to be changed
text.setBackgroundResource(comment.left ? R.drawable.bg_chat_recipient : R.drawable.bg_chat_sender );
wrapper.setGravity(comment.left? Gravity.START : Gravity.END);
return row;
}
public Bitmap decodeToBitmap(byte[] decodedByte){
return BitmapFactory.decodeByteArray(decodedByte, 0,decodedByte.length );
}
}
now I don't know how should I store those msg I received from node server at local storage, and when i open the app, I want to also display the msg history.
should I use SQL? but how should I store the msg? put them in different rows?
I know it might be a dumb question, But I really don't know how to store the msg to local storage and read them again.
Anyone can give a brief introduction? Thanks a lot!
You should use some kind of database.I recommend an sql db with an orm - it lets you create a database based on classes and eliminates the need in ton of sql.
I like active android, but also take a look at sugar orm.
You should have a messages table, and each row in the table will be a message.In an orm you define the message using a class. example code (using ActiveAndroid orm):
#Table(name="Messages")
class Message extends Model {
String name;
String id;
String message;
//the empty consructor is required by active android
public Message(){
super();
}
}
to actually enter the messages into the databse you will need to parse the json and create Messages objects from them, then save them.To parse the json into the Message object you can use Gson or logan square.

Categories

Resources