I'm doing an application where a list of things has to be displayed, so I created a LinearLayout and programmatically add CardViews to it, there is a function that connects to FireStore database to pull data from it and then the cards get created and added to the LinearLayout.
The data takes a bit to be loaded and that messes with the animation of the cards (The animation given by adding android:animateLayoutChanges="true" to the xml of the LinearLayout).
The final result with animations is clunky and stuttering, is there any way that I could make it smoother? Like maybe making the card wait for the data to be pulled before it gets added to the layout or making a custom animation of some sort that would wait a bit beofre starting.
Here's a video of the current state of the animations:
Example of current behavior of animations
I was asked for code so here it is:
Layout where the cards are added:
<LinearLayout
android:id="#+id/thisone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:orientation="vertical">
</LinearLayout>
Layout of the card:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
app:cardCornerRadius="20dp"
app:cardElevation="2dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/linearLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="15dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="#+id/workerImage"
android:layout_width="100dp"
android:layout_height="100dp"
android:contentDescription="#string/Desc_Photo_Card"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearanceOverlay="#style/roundedImageView"
app:srcCompat="#drawable/worker1" />
<TextView
android:id="#+id/nameWorker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:padding="10dp"
android:text="#string/Text1_Card"
android:textSize="14sp"
app:layout_constraintStart_toEndOf="#+id/workerImage"
app:layout_constraintTop_toTopOf="#+id/workerImage" />
<RatingBar
android:id="#+id/ratingBar"
style="#style/Widget.AppCompat.RatingBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleX="0.4"
android:scaleY="0.4"
app:layout_constraintBottom_toBottomOf="#+id/nameWorker"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/nameWorker"
app:layout_constraintTop_toTopOf="#+id/nameWorker" />
<com.google.android.material.button.MaterialButton
android:id="#+id/submitButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginTop="8dp"
android:padding="10dp"
android:text="#string/rating_button"
android:textColor="#fff"
android:textSize="10sp"
android:textStyle="bold"
app:cornerRadius="20dp"
app:layout_constraintEnd_toEndOf="#+id/nameWorker"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="#+id/nameWorker"
app:layout_constraintTop_toBottomOf="#+id/nameWorker"
tools:ignore="SmallSp" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="#string/available_at"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/workerImage" />
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="Currently not available"
app:layout_constraintBottom_toBottomOf="#+id/textView2"
app:layout_constraintStart_toEndOf="#+id/textView2"
app:layout_constraintTop_toTopOf="#+id/textView2"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
Function that fills the card with informations and adds it to the layout:
#SuppressLint("SetTextI18n")
private void addCard(int workerNum) {
View card = getLayoutInflater().inflate(R.layout.card_layout, layout, false);
TextView nameWorker = card.findViewById(R.id.nameWorker);
RatingBar RatingBar = card.findViewById(R.id.ratingBar);
Button submitButton = card.findViewById(R.id.submitButton);
ImageView workerImage = card.findViewById(R.id.workerImage);
TextView first_available_slot = card.findViewById(R.id.textView3);
String workerImgSrc = "worker"+ workerNum; // this is image file name
String PACKAGE_NAME = getApplicationContext().getPackageName();
int imgId = getResources().getIdentifier(PACKAGE_NAME+":drawable/"+workerImgSrc , null, null);
DocumentReference docRef = db.collection("workers").document(String.valueOf(workerNum));
docRef.get().addOnCompleteListener(task -> {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
// All the informations about the worker are filled out
name = (Objects.requireNonNull(document.toObject(Classes.Worker.class))).getName();
nameWorker.setText(name);
rating = (Objects.requireNonNull(document.toObject(Classes.Worker.class))).getRating();
RatingBar.setRating(rating);
workerImage.setImageBitmap(BitmapFactory.decodeResource(getResources(),imgId));
// Checks if the worker is available and changes the Textview accordingly.
// If there are no available appointments for that worker, the TextView will be
// left unchanged, which means that it till display "Currently not available"
db.collection("workers")
.document(String.valueOf(workerNum))
.collection("schedule")
.whereEqualTo("booked", "false")
.get()
.addOnCompleteListener(task1 -> {
if (task1.isSuccessful()) {
for (QueryDocumentSnapshot document1 : task1.getResult()) {
int day = Integer.parseInt(
Objects.requireNonNull(
document1.getString("day")
)
);
int hour = Integer.parseInt(
Objects.requireNonNull(
document1.getString("hour")
)
);
if(day > currentDay) {
first_available_slot.setText(
"Currently available. Click to see when")
;
}
if(day == currentDay) {
if(hour > currentHour) {
first_available_slot.setText(
"Currently available. Click to see when")
;
}
}
}
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
}
}
);
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
});
// This button allows the user to change the rating of the worker and correctly save the
// changes to the database
submitButton.setOnClickListener(v -> {
DocumentReference changerating = db.collection("workers").document(String.valueOf(workerNum));
changerating.update("rating", RatingBar.getRating()).addOnSuccessListener(aVoid ->
Log.d(TAG, "DocumentSnapshot successfully updated!"))
.addOnFailureListener(e -> Log.w(TAG, "Error updating document", e))
;
String rating1 = "On a scale of 5 Stars\n New rating = " + RatingBar.getRating();
Toast.makeText(getApplicationContext(),
rating1, Toast.LENGTH_LONG)
.show()
;
});
card.setOnClickListener(view -> openWorkerActivity(workerNum));
layout.addView(card);
}
Related
I'm trying to create a list of cards that will be generated dynamically because there is some stuff in the card that I need to pull from FireStore. I got it pretty much done but the card shows up sort of twice, the actual card shows up fine but then there is like the card layout in the back with the preset texts and stuff
Update: after some suggestions and help I changed the code, it still doesn't do what I want but I guess its a step in the right direction
here's the code I use to create the card (updated with full activity)
public class ScrollingActivity extends AppCompatActivity {
FirebaseFirestore db = FirebaseFirestore.getInstance();
FirebaseAuth fAuth = FirebaseAuth.getInstance();
LinearLayout layout;
String name;
float rating;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scrolling);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
CollapsingToolbarLayout toolBarLayout = findViewById(R.id.toolbar_layout);
toolBarLayout.setTitle(getTitle());
for (int i = 0; i<6; i++){
addCard(i);
}
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show());
}
private void addCard(int workerNum) {
layout = findViewById(R.id.thisone);
View card = getLayoutInflater().inflate(R.layout.sample_card_1, layout, false);
TextView nameWorker = findViewById(R.id.nameWorker);
RatingBar RatingBar = findViewById(R.id.ratingBar);
Button submitButton = findViewById(R.id.submitButton);
DocumentReference docRef = db.collection("workers").document(String.valueOf(workerNum));
docRef.get().addOnCompleteListener(task -> {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
Log.d(TAG, "DocumentSnapshot data: " + document.getData());
name = document.toObject(Classes.Worker.class).getName();
nameWorker.setText(name);
rating = document.toObject(Classes.Worker.class).getRating();
RatingBar.setRating(rating);
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
});
// perform click event on button
submitButton.setOnClickListener(v -> {
DocumentReference changerating = db.collection("workers").document(String.valueOf(workerNum));
changerating.update("rating", RatingBar.getRating()).addOnSuccessListener(aVoid ->
Log.d(TAG, "DocumentSnapshot successfully updated!"))
.addOnFailureListener(e -> Log.w(TAG, "Error updating document", e));
// get values and then displayed in a toast
String rating1 = "On a scale of 5 Stars\n New rating = " + RatingBar.getRating();
Toast.makeText(getApplicationContext(), rating1, Toast.LENGTH_LONG).show();
});
layout.addView(card);
}
Here's the xml of the layout where the cards are actually shown
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ScrollingActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="#dimen/app_bar_height"
android:fitsSystemWindows="true"
android:theme="#style/Theme.InternshipThesis.AppBarOverlay">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="#+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:toolbarId="#+id/toolbar">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="#style/Theme.InternshipThesis.PopupOverlay" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".ScrollingActivity"
tools:showIn="#layout/activity_scrolling">
<LinearLayout
android:id="#+id/thisone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<include layout="#layout/sample_card_1" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/fab_margin"
app:layout_anchor="#id/app_bar"
app:layout_anchorGravity="bottom|end"
app:srcCompat="#android:drawable/ic_menu_sort_by_size"
android:contentDescription="#string/main_fab_desc" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Here's the layout of the card
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/card"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="20dp"
app:cardElevation="2dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="15dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="#+id/imageView"
android:layout_width="100dp"
android:layout_height="100dp"
app:shapeAppearanceOverlay="#style/roundedImageView"
android:contentDescription="#string/Desc_Photo_Card1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/sample_worker_1" />
<TextView
android:id="#+id/nameWorker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/Text1_Card1"
android:textSize="20sp"
app:layout_constraintStart_toEndOf="#+id/imageView"
app:layout_constraintTop_toTopOf="#+id/imageView"
android:padding="10dp"/>
<RatingBar
android:id="#+id/ratingBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="#+id/imageView"
app:layout_constraintStart_toEndOf="#+id/imageView"
app:layout_constraintTop_toBottomOf="#+id/nameWorker" />
<com.google.android.material.button.MaterialButton
android:id="#+id/submitButton"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:padding="10dp"
android:text="#string/rating_button"
android:textColor="#fff"
android:textSize="20sp"
android:textStyle="bold"
app:cornerRadius="20dp"
app:layout_constraintEnd_toEndOf="#+id/ratingBar"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="#+id/ratingBar"
app:layout_constraintTop_toBottomOf="#+id/ratingBar" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
here's how it currently shows in the app
example 1
If I dont include the layout of the card in the xml of the activity, the app crashes because it cant find the objects inside the cards to fill in with data, but if I include it apparently it creates one card correctly filled and all the other ones are just filled with the preset data
The issue you're having is based in your AddCard function. You're inflating the card_view, but then instead of looking inside the new card_view (the variable card) for the views to fill with data, you're looking inside the root view (if you just call findViewById, it will look inside the root view of the fragment/activity by default).
To remedy this:
Remove this line from your main view: <include layout="#layout/sample_card_1" />, as it's not necessary (your code should dynamically add the cards)
Modify your AddCard function, and change these three lines as below:
TextView nameWorker = card.findViewById(R.id.nameWorker);
RatingBar RatingBar = card.findViewById(R.id.ratingBar);
Button submitButton = card.findViewById(R.id.submitButton);
By changing the findViewById calls to instead call on the card view you've inflated, you'll stop looking inside the root view (which will solve those crashes you referenced), and instead will fill out the new card with the details you want (which will solve the issue you're having of one card being filled out and the rest being default values).
I have a fragment where I'm processing data from xml source, and everything is working fine, but the thing is when I refresh my layout by detaching and then attaching my fragment, the ui keeps blinking until all data is processed, I checked my code many time but I feel lost and I couldn't find anything
This is how i'm processing my xml source data
fun getData(){
val url = URL("www.xmldatasource.com")
val factory = XmlPullParserFactory.newInstance()
factory.isNamespaceAware = false
val xpp = factory.newPullParser()
xpp.setInput(GetInputStream(url), "utf-8")
var insideItem = false
var eventType = xpp.eventType
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (xpp.name.equals("item", ignoreCase = true)) {
insideItem = true
} else if (xpp.name.equals("title", ignoreCase = true)) {
if (insideItem) {
title = xpp.nextText()
}
} else if (xpp.name.equals("pubDate", ignoreCase = true)) {
if (insideItem) {
val subbedDate = xpp.nextText()
publishDate = subbedDate.substring(0, 25)
}
} else if (xpp.name.equals("guid", ignoreCase = true)) {
if (insideItem) {
link = xpp.nextText()
}
} else if (xpp.name.equals("description", ignoreCase = true)) {
if (insideItem) {
val newsDescription = xpp.nextText()
if (newsDescription.contains("src") && newsDescription.contains("jpg")) {
imageUrl = newsDescription.substring(
newsDescription.indexOf("src=") + 5,
newsDescription.indexOf("jpg") + 3
)
}
if (newsDescription.contains("<BR>") && newsDescription.contains("</p>")) {
description =
newsDescription.substring(
newsDescription.indexOf("<BR>") + 4,
newsDescription.indexOf("</p>")
)
}
}
}
} else if (eventType == XmlPullParser.END_TAG && xpp.name.equals("item", ignoreCase =
true)) {
insideItem = false
imageUrl?.let {
//TODO : Getting Image Url And Convert it to Bitmap
val urlImg = URL(it)
val httpURLConnection = urlImg.openConnection() as HttpURLConnection
httpURLConnection.connect()
val inputStream = httpURLConnection.inputStream
val bitmap = BitmapFactory.decodeStream(inputStream)
CoroutineScope(Dispatchers.Main).launch{
xmlList?.clear()
val model = NewsModel(bitmap, title, description, publishDate!!, link!!)
xmlList?.add(model)
leagueViewModel.insertNews(model)
binding.newsrcycler.adapter = LeagueNewsAdapter(requireContext(), xmlList!!)
customType(requireActivity(), "left-to-right")
}
})
}
}
}
eventType = xpp.next()
}
}
Thsi is how i'm refreshing my fragment
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.refresh -> {
if(Constants.checkConnectivity(requireContext())){
requireActivity().supportFragmentManager.beginTransaction().detach(this).attach(this).commit()
} else {
requireContext().ShowToast(requireContext(),"Please Check Your Internet..")
}
}
}
return true
}
This is the layout containing all views of my adapter
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="listener"
type="taki.eddine.premier.league.pro.uilisteners.RssListener" />
<variable
name="newsModel"
type="taki.eddine.premier.league.pro.models.NewsModel" />
</data>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="16dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginTop="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="?attr/selectableItemBackground"
android:onClick="#{() -> listener.RssArticle(newsModel)}">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="match_parent"
android:layout_height="140dp"
android:layout_margin="8dp"
android:layout_marginTop="5dp"
app:layout_constraintBottom_toTopOf="#+id/guideline7"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:rssimg="#{newsModel.newsBanner}"/>
<TextView
android:id="#+id/newstitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:fontFamily="#font/andada"
android:maxLines="2"
android:text="#{newsModel.newsTitle}"
android:textColor="#android:color/black"
android:textSize="12sp"
app:layout_constraintBottom_toTopOf="#+id/guideline14"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/guideline7"
app:layout_constraintVertical_bias="0.0" />
<TextView
android:id="#+id/newsdescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:fontFamily="#font/adamina"
android:maxLines="3"
android:text="#{newsModel.newsDescription}"
android:textColor="#android:color/black"
android:textSize="12sp"
app:layout_constraintBottom_toTopOf="#+id/guideline15"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/guideline14"
app:layout_constraintVertical_bias="0.0" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="11dp"
android:layout_marginStart="8dp"
android:src="#drawable/ic_baseline_date_range_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/guideline22"
app:layout_constraintHorizontal_bias="0.842"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/guideline15" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginEnd="16dp"
android:fontFamily="#font/andada"
android:textStyle="bold"
android:textSize="11sp"
android:textColor="#android:color/holo_blue_dark"
android:layout_marginTop="15dp"
android:text="#{newsModel.newsDate}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="#+id/guideline22"
app:layout_constraintTop_toTopOf="#+id/guideline15" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
</layout>
This is my fragment layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/newsprogress"
android:visibility="visible"
android:layout_gravity="center"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/newsrcycler"
android:scrollbars="vertical"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
You seem to be setting the RecyclerView adapter multiple times in the while loop. This will keep refreshing the RecyclerView.
You shouldn't be replacing the entire adapter, as the data changes. The data should be kept inside the adapter, and it should be updated inside the adapter.
How I got to this conclusion:
getData() contains a while() loop.
In this while loop, in the last branch you call CoroutineScope(Dispatchers.Main).launch {}
In this launch {} you call binding.newsrcycler.adapter = LeagueNewsAdapter().
I used a working RecyclerView as a template for another, but I made some sort of mistake in its implementation and I can't find it. Here is the code that initializes the view:
mMessageThreadList = new ArrayList<>();
mRecyclerView = findViewById(R.id.chat_list_recycler_view);
private void initRecyclerView() {
Log.d(TAG, "initRecyclerView Called");
//Initializes and sets up adapter
mAdapter = new ChatListRecyclerViewAdapter(mThreadList);
mRecyclerView.setAdapter(mAdapter);
Query query = mThreadCollection;
query.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot queryDocumentSnapshots, #Nullable FirebaseFirestoreException e) {
for (DocumentChange documentChange : queryDocumentSnapshots.getDocumentChanges()) {
switch (documentChange.getType()) {
case ADDED:
Thread thread = documentChange.getDocument().toObject(Thread.class);
Log.d(TAG, "Last Message: " + thread.getLastMessage().getMessage());
mThreadList.add(thread);
mAdapter.notifyDataSetChanged();
}
}
}
});
}
Note that the print log statement in the SnapshotListener does contain a value when printed so the information is returning from Firebase, it's just not displaying. Which makes me think my problem is with my Adapter/Viewholder:
public class ChatListRecyclerViewAdapter extends RecyclerView.Adapter<ChatListRecyclerViewAdapter.ChatListViewHolder> {
private List<Thread> threadList;
ChatListRecyclerViewAdapter(List<Thread> threadList) {
this.threadList = threadList;
}
#NonNull
#Override
public ChatListViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_list_row, parent, false);
return new ChatListViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ChatListViewHolder holder, int position) {
// This method fills fields with data for each list item
Log.d(TAG, "onBindViewholder called");
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MMM hh:mm a");
final Thread thread = threadList.get(position);
char initial = thread.getPartnerName().charAt(0);
char uppercaseInitial = Character.toUpperCase(initial);
Log.d(TAG, thread.getLastMessage() + " " + thread.getPartnerID());
holder.partnerName.setText(thread.getPartnerName());
holder.authorInitial.setText(uppercaseInitial);
holder.lastMessageText.setText(thread.getLastMessage().getMessage());
holder.lastMessageTime.setText(simpleDateFormat.format(thread.getLastMessage().getTimestamp()));
}
#Override
public int getItemCount() {
return threadList.size();
}
//Viewholder stores the information about the layout and content of each list item, and serves as a template for each item of a RecyclerView
public class ChatListViewHolder extends RecyclerView.ViewHolder {
TextView partnerName;
TextView authorInitial;
TextView lastMessageText;
TextView lastMessageTime;
LinearLayout listTextHolder;
public ChatListViewHolder(View itemView) {
super(itemView);
partnerName = itemView.findViewById(R.id.partner_name);
authorInitial = itemView.findViewById(R.id.partner_initial);
lastMessageText = itemView.findViewById(R.id.last_message);
lastMessageTime = itemView.findViewById(R.id.last_message_time);
listTextHolder = itemView.findViewById(R.id.list_text_holder);
}
}
}
chat_list_row.xml file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/single_thread_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:background="#color/colorPrimaryDark">
<TextView
android:id="#+id/partner_initial"
android:background="#drawable/chat_list_circle"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_alignParentStart="true"
android:gravity="center"
android:text="A"
android:textSize="36sp"
tools:ignore="HardcodedText" />
<TextView
android:id="#+id/last_message_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:padding="5dp"
android:fontFamily="#font/nunito_extralight"
android:text="#string/sample_time"
android:textColor="#android:color/darker_gray"
android:textSize="12sp"
android:typeface="normal" />
<LinearLayout
android:id="#+id/list_text_holder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="#id/partner_initial"
android:layout_centerVertical="true"
android:orientation="vertical">
<TextView
android:id="#+id/partner_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_marginStart="5dp"
android:fontFamily="#font/nunito"
android:text="#string/sample_name"
android:textColor="#color/white"
android:textSize="14sp"
android:textStyle="bold"
android:typeface="sans" />
<TextView
android:id="#+id/last_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:fontFamily="#font/nunito_extralight"
android:gravity="start"
android:text="#string/sample_message"
android:textColor="#android:color/darker_gray"
android:textSize="12sp"
android:typeface="normal" />
</LinearLayout>
</RelativeLayout>
Edit: Layout of the Activity that RecyclerView appears in. I also edit above code to show where the variable is attached to the view:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/colorPrimaryDark"
android:paddingLeft="0dp"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingRight="0dp"
android:paddingBottom="0dp"
tools:context="org.andrewedgar.theo.ChatListActivity">
<include
android:id="#+id/chat_list_toolbar"
layout="#layout/toolbar" />
<android.support.v7.widget.RecyclerView
android:id="#+id/chat_list_recycler_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/chat_list_toolbar" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/new_check_in_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:src="#drawable/ic_person_pin_circle_black_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</android.support.constraint.ConstraintLayout>
Seems like you have missed to add layout manager of RecyclerView. Would you please add this and try again
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
Your recyclerview is not showing any data because the list in adapter is still empty. After fetching data from firebase you are adding to mThreadList, which is still with activity and not adapter. To update the list in adapter you can add a method in adapter class and pass the list to adapter and notifyDataseChanged there.
Activity:
//after firebase task...
mAdapter.updateData(mThreadList);
Adapter: add new method
void updateData(List<Thread> threadList){
this.threadList = threadList;
notifyDatasetChanged(); //notify adapter that new list is added
}
I've created some custom toast layout and have a problem with it !
My custom toast doesn't show my message and shows
It's my layout code :
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="24dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="#drawable/selector_custom_toast">
<TextView
android:id="#+id/tv_toast_message"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:gravity="center_vertical|center_horizontal"
android:lineSpacingExtra="4sp"
android:singleLine="false"
android:textAlignment="center"
android:textColor="#android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/iv_toast"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Test Toast Test Toast Test Toast Test Toast Test Toast Test Toast Test Toast Test Toast Test Toast Test Toast " />
<ImageView
android:id="#+id/iv_toast"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:adjustViewBounds="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ic_error_outline_red_24dp"
tools:ignore="ContentDescription" />
and it's my toaster function code :
public void toaster(String message, int length, int form) {
Toast toast = new Toast(context);
if (toastLayout == null) {
toastLayout = LayoutInflater.from(context).inflate(R.layout.custom_toast, null);
}
TextView toastMessage = toastLayout.findViewById(R.id.tv_toast_message);
toastMessage.setText(message);
toastMessage.setTypeface(MyApplication.getIranianSansFont(context));
ImageView toastImage = toastLayout.findViewById(R.id.iv_toast);
if (form == SUCCESS) {
toastImage.setImageResource(R.drawable.ic_check_circle_green_24dp);
toastMessage.setTextColor(context.getResources().getColor(R.color.greenSuccess));
} else if (form == ERROR) {
toastImage.setImageResource(R.drawable.ic_error_outline_red_24dp);
toastMessage.setTextColor(context.getResources().getColor(R.color.redError));
}
toast.setDuration(length);
toast.setView(toastLayout);
toast.show();
}
My text view height should be wrap content and width is match constraint but when I set both of them to wrap content the problem goes away and everything work just fine except the vision of the toast ! toast layout stick around the screen and it's margins get removed and message text get under the image view
can anyone help me fix my problem ?
I've Just Used Linear Layout instead of Constraint Layout , it was something wrong with Constraint Layout !
My Linear Layout Code :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="24dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="#drawable/selector_custom_toast">
<TextView
android:id="#+id/tv_toast_message"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_weight="1"
android:gravity="center_vertical|center_horizontal"
android:lineSpacingExtra="4sp"
android:singleLine="false"
android:textAlignment="center"
android:textColor="#android:color/black"
android:textDirection="rtl"
tools:text="Test Toast Test Toast Test Toast Test Toast Test Toast Test Toast Test Toast Test Toast Test Toast Test Toast " />
<ImageView
android:id="#+id/iv_toast"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="end|center_vertical"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:adjustViewBounds="true"
app:srcCompat="#drawable/ic_error_outline_red_24dp"
tools:ignore="ContentDescription" />
It will expand your view horizontally.
fun showCustomToast(context: Context, message: String) {
val inflater: LayoutInflater = LayoutInflater.from(context)
val layout: View = inflater.inflate(R.layout.layout_custom_toast, null, false)
val text = layout.findViewById<AppCompatTextView>(R.id.tvMessage) as AppCompatTextView
text.setText(message)
toast.setGravity(Gravity.TOP or Gravity.FILL_HORIZONTAL, 0, 0)
toast.setMargin(16f, 0f)
toast.duration = Toast.LENGTH_LONG
toast.setView(layout)
toast.show()
}
Hello my customlist view shows only one record. Everything is fine it shows multiple records in console but when ever i try to show the records in ListView it shows only last record its overriding first record, currently there are two records which are showing in my console but in ListView it shows only last record, I am searching for solution since yesterday , I have spend more then 6 hours to solve this problem.
Cart_Adapter.java
public class Cart_Adapter extends BaseAdapter {
Activity activity;
ArrayList<ProductBean> list;
String abc;
public Cart_Adapter(Activity activity, ArrayList<ProductBean> list) {
this.activity = activity;
this.list = list;
}
#Override
public int getCount() {
return list.size();
}
#Override
public Object getItem(int i) {
return list.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
View v=view;
if(v==null){
LayoutInflater layoutInflater= (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v=layoutInflater.inflate(R.layout.cartxml,null);
}
TextView title=(TextView) v.findViewById(R.id.title);
TextView size=(TextView) v.findViewById(R.id.size);
TextView color=(TextView) v.findViewById(R.id.color);
Button remove=(Button) v.findViewById(R.id.remove);
ImageView imageView=(ImageView) v.findViewById(R.id.imageView);
title.setText(list.get(i).getTitle());
size.setText(list.get(i).getSize());
color.setText(list.get(i).getColor());
ArrayList<ImagesBean> aa =list.get(i).getImagesList();
if(aa!=null){
for(i=0; i<aa.size(); i++) {
abc = String.valueOf(aa.get(i).getImgone());
System.out.println("--testing" + abc);
}
}
System.out.println("===="+abc);
if(abc !=null ) {
imageView.setImageBitmap(getBitmapFromString(abc));
// imageView.setImageBitmap(getBitmapFromString(list.get(i).getImagesList()));
}else{}
return v;
}
private Bitmap getBitmapFromString(String encode){
byte[] b = Base64.decode(encode,Base64.DEFAULT);
return BitmapFactory.decodeByteArray(b,0,b.length);
}
}
class from where I am getting database record
ArrayList<String> arrayList=mydatabase.getpid(userid);
System.out.println("--outside"+arrayList);
for(int i =0; i<arrayList.size(); i++) {
String l = arrayList.get(i);
final String ll = l.toString().replace("[", "").replace("]", "").replace(" ", "");
System.out.println("--before loop" + ll);
for (String s : ll.split(",")) {
int pid = Integer.parseInt(s);
myadapter = new Cart_Adapter(Cart.this, mydatabase.getproduct_details(pid));
lv.setAdapter(myadapter);
}
}
Activity_cart.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.bhm.ishopping.Cart">
<android.support.constraint.ConstraintLayout
android:id="#+id/customlayout"
android:layout_width="410dp"
android:layout_height="63dp"
android:layout_marginStart="8dp"
android:background="#39a423"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.617"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="#+id/textView15"
android:layout_width="86dp"
android:layout_height="29dp"
android:layout_marginStart="320dp"
android:textColor="#android:color/holo_blue_bright"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="16dp" />
</android.support.constraint.ConstraintLayout>
<TextView
android:id="#+id/textView19"
android:layout_width="171dp"
android:layout_height="34dp"
android:layout_marginEnd="120dp"
android:layout_marginTop="76dp"
android:text="Your Cart Detail"
android:textColor="#android:color/black"
android:textSize="22sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ListView
android:id="#+id/lv"
android:layout_width="373dp"
android:layout_height="411dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.4"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/customlayout" />
<Button
android:id="#+id/submit"
android:layout_width="230dp"
android:layout_height="wrap_content"
android:layout_marginStart="76dp"
android:layout_marginTop="40dp"
android:text="Submit Your Order"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/lv" />
</android.support.constraint.ConstraintLayout>
Cart.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/imageView"
android:layout_width="99dp"
android:layout_height="87dp"
android:layout_alignParentStart="true"
android:layout_alignTop="#+id/remove"
android:layout_marginStart="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ic_launcher_background" />
<TextView
android:id="#+id/textView16"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="#+id/imageView"
android:layout_marginStart="15dp"
android:layout_toEndOf="#+id/imageView"
android:text="Ttile"
android:textColor="#android:color/background_dark"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.456"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView17"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:layout_alignParentTop="true"
android:layout_alignStart="#+id/textView16"
android:layout_marginTop="102dp"
android:text="Color"
android:textColor="#android:color/black"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView16" />
<TextView
android:id="#+id/textView18"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignEnd="#+id/textView17"
android:layout_below="#+id/textView17"
android:text="Size"
android:textColor="#android:color/black"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView17" />
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="#+id/size"
android:layout_alignTop="#+id/remove"
android:text="TextView"
android:textColor="#android:color/black"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/color"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/imageView"
android:layout_alignStart="#+id/size"
android:text="TextView"
android:textColor="#android:color/black"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/title" />
<TextView
android:id="#+id/size"
android:layout_width="wrap_content"
android:layout_height="21dp"
android:layout_above="#+id/textView18"
android:layout_marginEnd="26dp"
android:layout_toStartOf="#+id/remove"
android:text="TextView"
android:textColor="#android:color/black"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/color" />
<Button
android:id="#+id/remove"
android:layout_width="46dp"
android:layout_height="67dp"
android:layout_alignBottom="#+id/size"
android:layout_alignParentEnd="true"
android:layout_marginEnd="13dp"
android:background="#5d8f37"
android:text="X"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</RelativeLayout>
console output show two records
enter code here System.out: ===pids1 System.out: ==database record[ProductBean{id='', title='ddd', color='dff', size='Select Size', type='Shart', cost='ddf', imagesList=null System.out: ===pids2 System.out: ==database record[ProductBean{id='', title='aa', color='aa', size='Select Size', type='Select Type', cost='aa', imagesList=null}]
You need to make your cartxml hight to android:layout_height="wrap_content"
like below code
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
EDIT
ArrayList<ProductBean> list= new ArrayList();
ArrayList<String> arrayList=mydatabase.getpid(userid);
System.out.println("--outside"+arrayList);
myadapter = new Cart_Adapter(Cart.this, list);
lv.setAdapter(myadapter);
for(int i =0; i<arrayList.size(); i++) {
String l = arrayList.get(i);
final String ll = l.toString().replace("[", "").replace("]", "").replace(" ", "");
System.out.println("--before loop" + ll);
for (String s : ll.split(",")) {
int pid = Integer.parseInt(s);
list.addAll(mydatabase.getproduct_details(pid));
}
}
myadapter.notifyDataSetChanged().
for (String s : ll.split(",")) {
int pid = Integer.parseInt(s);
myadapter = new Cart_Adapter(Cart.this, mydatabase.getproduct_details(pid));
lv.setAdapter(myadapter);
}
You are setting adapter inside loop .Which is totally wrong . Put this code outside Loop .
And one more thing Its time to upgrade to RecyclerView . Its easy and better implementation of ViewHolder Pattern .
ArrayList<String> arrayList=mydatabase.getpid(userid);
ArrayList<String> dataList=new ArrayList();;
for(int i =0; i<arrayList.size(); i++) {
String l = arrayList.get(i);
final String ll = l.toString().replace("[", "").replace("]", "").replace(" ", "");
System.out.println("--before loop" + ll);
for (String s : ll.split(",")) {
// Do your stuff add data to list here
dataList.add(stringToAdd);
}
}
myadapter = new Cart_Adapter(Cart.this, dataList);
lv.setAdapter(myadapter);
Do this way and if your dataset is not building properly then i thing you are using wrong dataset for your list . Or probably you need an ExpandableListView . Figure out the dataSet first currently which is 'ArrayList'.
Print your list size in getCount(), to be sure if list is being sent inside. Check your item's layout_height, it should be wrap_content.
Because you are setting adapter each items in loop.
for (String s : ll.split(",")) {
int pid = Integer.parseInt(s);
myadapter = new Cart_Adapter(Cart.this, mydatabase.getproduct_details(pid));
lv.setAdapter(myadapter);
}
}
so it will take last pid from the iteration and will fetch product details which you are setting in card adapter.
Wrong part is: you are calling setAdapter() with each iteration in the loop
Solution:
Collect the list of records in loop, you can keep adding product details in the array list and then set the final list outside loop in the adapter.
Check your cartxml layout file. The root RelativeLayout height will be wrap_content otherwise it will take all the available space for a single item. Use android:layout_width="wrap_content" for RelativeLayoutin in your cartxml