I create one recyclerview with address. When this recyclerview is empty, want one spesicif LinearLayout appear and when recyclerView has one or more items this LinearLayout disapear.But it is not working. I use funtions setVisibility(). Please help!!!
My code for xml is:
<?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="match_parent"
android:background="#color/user_location_bg_color"
android:orientation="vertical"
tools:context=".UserLocationActivity">
<ImageButton
android:id="#+id/user_location_back_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="50dp"
android:background="#color/my_account_bg_color"
android:contentDescription="#null"
android:src="#drawable/ic_back" />
<TextView
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="40dp"
android:text="#string/user_location_text"
android:textColor="#color/black"
android:textSize="20sp"
android:textStyle="bold" />
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="20dp"
android:background="#color/black" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/coffee_recycler_bg_color" />
<LinearLayout
android:id="#+id/empty_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="invisible">
<pl.droidsonroids.gif.GifImageView
android:id="#+id/location_giffy"
android:layout_width="wrap_content"
android:layout_height="300dp"
android:src="#drawable/location_gif" />
<TextView
android:id="#+id/user_location_blank_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="60dp"
android:layout_marginTop="50dp"
android:layout_marginEnd="60dp"
android:gravity="center"
android:text="#string/user_address_blank_text"
android:textColor="#color/black"
android:textSize="15sp" />
</LinearLayout>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center|bottom"
android:orientation="vertical">
<Button
android:id="#+id/add_new_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="50dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="10dp"
android:backgroundTint="#color/btn_add_new_address"
android:text="#string/btn_add_new_address_text"
android:textAllCaps="false"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
My code for Activity is:
public class UserLocationActivity extends AppCompatActivity implements AddressAdapter.OnAddressListener {
//Init Variables
RecyclerView recyclerAddress;
private FirebaseDatabase db = FirebaseDatabase.getInstance();
private DatabaseReference ref = db.getReference().child("UserAddress");
private AddressAdapter adapter;
private ArrayList<UserLocation> list;
public LinearLayout empty_address;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_location);
recyclerAddress = findViewById(R.id.recycler_address);
recyclerAddress.setHasFixedSize(true);
recyclerAddress.setLayoutManager(new LinearLayoutManager(this));
list = new ArrayList<>();
adapter = new AddressAdapter(this, list, this);
recyclerAddress.setAdapter(adapter);
empty_address = findViewById(R.id.empty_address);
if (adapter.getItemCount() == 0) {
//making it semi-transparent
empty_address.setVisibility(LinearLayout.VISIBLE);
}
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
UserLocation userLocation = dataSnapshot.getValue(UserLocation.class);
list.add(userLocation);
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
#Override
public void onAddressItemDelete(int position) {
}
}
My adapter code is:
public class AddressAdapter extends RecyclerView.Adapter<AddressAdapter.AddressViewHolder> {
private List<UserLocation> listData = new ArrayList<>();
UserLocationActivity userLocationActivity;
private OnAddressListener mOnAddressListener;
public AddressAdapter(UserLocationActivity userLocationActivity, List<UserLocation> listData, OnAddressListener onAddressListener){
this.listData = listData;
this.userLocationActivity = userLocationActivity;
this.mOnAddressListener = onAddressListener;
}
#NonNull
#Override
public AddressViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(userLocationActivity).inflate(R.layout.address_item , parent, false);
return new AddressViewHolder(v,mOnAddressListener);
}
#Override
public void onBindViewHolder(#NonNull AddressViewHolder holder, int position) {
UserLocation userLocation = listData.get(position);
holder.addressItem.setText(userLocation.getUserLocation());
}
#Override
public int getItemCount() {
if (listData.size() == 0){
userLocationActivity.empty_address.setVisibility(LinearLayout.VISIBLE);
}
return listData.size();
}
public static class AddressViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView addressItem;
public ImageView btnAddressItemDelete;
OnAddressListener onAddressListener;
public AddressViewHolder(View itemView, OnAddressListener onAddressListener){
super(itemView);
addressItem = itemView.findViewById(R.id.address_item);
btnAddressItemDelete = itemView.findViewById(R.id.btn_address_item_delete);
this.onAddressListener = onAddressListener;
}
#Override
public void onClick(View v) {
onAddressListener.onAddressItemDelete(getAdapterPosition());
}
}
public interface OnAddressListener{
void onAddressItemDelete(int position);
}
}
It seems there's a bug in your code, I have fixed it.
The bug is you're checking recyclerView is empty first then adding the data into recyclerView
public class UserLocationActivity extends AppCompatActivity implements AddressAdapter.OnAddressListener {
//Init Variables
RecyclerView recyclerAddress;
private FirebaseDatabase db = FirebaseDatabase.getInstance();
private DatabaseReference ref = db.getReference().child("UserAddress");
private AddressAdapter adapter;
private ArrayList<UserLocation> list;
public LinearLayout empty_address;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_location);
recyclerAddress = findViewById(R.id.recycler_address);
recyclerAddress.setHasFixedSize(true);
recyclerAddress.setLayoutManager(new LinearLayoutManager(this));
list = new ArrayList<>();
adapter = new AddressAdapter(this, list, this);
recyclerAddress.setAdapter(adapter);
empty_address = findViewById(R.id.empty_address);
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
UserLocation userLocation =
dataSnapshot.getValue(UserLocation.class);
list.add(userLocation);
}
adapter.notifyDataSetChanged();
if (list.size() == 0) {
empty_address.setVisibility(View.VISIBLE);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
#Override
public void onAddressItemDelete(int position) {
}
}
Related
Here are my codes for MyAdapter, ActivityMain, MinActivity, and User
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
Context context;
ArrayList<User> list;
public MyAdapter(Context context, ArrayList<User> list) {
this.context = context;
this.list = list;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.item, parent, false);
return new MyViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
// here is the problem that I don't know how to fix][1]
// I'm tryin to pass data from firebase to Recyclerview
// error I'm getting here is:
// [Cannot resolve method 'getFirstName' in 'User'
// Cannot resolve method 'getLastName' in 'User'
// Cannot resolve method 'getAge' in 'User']
User user = list.get(position);
holder.FirstName.setText(user.getFirstName());
holder.LastName.setText(user.getLastName());
holder.Age.setText(user.getAge());
}
#Override
public int getItemCount() {
return list.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder{
TextView FirstName, LastName, Age;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
FirstName = itemView.findViewById(R.id.tvFirstName);
LastName = itemView.findViewById(R.id.tvLastName);
Age = itemView.findViewById(R.id.tvAge);
}
}
}
This is MainActivity code
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
DatabaseReference database;
MyAdapter myAdapter;
ArrayList<User> list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_Main);
recyclerView = findViewById(R.id.userList);
database = FirebaseDatabase.getInstance().getReference("User");
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
list = new ArrayList<>();
myAdapter = new MyAdapter(this,list);
recyclerView.setAdapter(myAdapter);
database.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot : snapshot.getChildren()){
User user = dataSnapshot.getValue(User.class);
list.add(user);
}
myAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
}
This is User codes which I generated with getter
public class User {
String FirstName, LastName, Age;
public String getFirstName() {
return FirstName;
}
public String getLastName() {
return LastName;
}
public String getAge() {
return Age;
}
{
}
}
This is my layout file
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:cardElevation="8dp"
app:cardCornerRadius="8dp"
android:layout_margin="16dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="First Name :"
android:textColor="#color/black"
android:textSize="26sp"
android:textStyle="bold"/>
<TextView
android:id="#+id/tvFirstName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="Arya"
android:textColor="#color/black"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/last_name"
android:textColor="#color/black"
android:textSize="26sp"
android:textStyle="bold"/>
<TextView
android:id="#+id/tvLastName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="#string/stark"
android:textColor="#color/black"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/age"
android:textColor="#color/black"
android:textSize="26sp"
android:textStyle="bold"/>
<TextView
android:id="#+id/tvAge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="18"
android:textColor="#color/black"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
When I hit RUN it gives me this error:
I'm new to coding.
you can change your code like this
holder.FirstName.setText(list.getFirstName().get(position));
holder.LastName.setText(list.getLastName().get(position));
holder.Age.setText(list.getAge().get(position);
and you should change this code position
myAdapter = new MyAdapter(this,list);
recyclerView.setAdapter(myAdapter);
into under this code
database.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot : snapshot.getChildren()){
User user = dataSnapshot.getValue(User.class);
list.add(user);
}
myAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
hope it can solve your problem :)
I want to integrate my chatbot(created by dialogflow) to my apps and I have create the xml files but I didn't find a way how to match between them.
I have already database using room library persistance .And, I'm coding with Java.
How can I itegrate my agent into my apps?And how to add a recylerViewAdapter for my chatmessages.
Thank you
msg_list.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/leftText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_alignParentStart="true"
android:text="Hello this is me!!"
android:padding="8dp"
android:textColor="#212121"
android:background="#drawable/left_background"
android:elevation="2dp"
android:layout_alignParentLeft="true" />
<TextView
android:id="#+id/rightText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_alignParentEnd="true"
android:text="Hi!! How are you!!"
android:background="#drawable/right_background"
android:textColor="#fff"
android:padding="8dp"
android:elevation="2dp"
android:layout_alignParentRight="true" />
</RelativeLayout>
Chatbot.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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Chatbot">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="10dp"
android:paddingBottom="50dp"
android:clipToPadding="false"
android:background="#f4f6f7"
tools:listitem="#layout/msglist"
/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="5dp"
android:layout_marginBottom="10dp"
android:elevation="2dp"
android:layout_toStartOf="#+id/addBtn"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="5dp"
android:layout_toLeftOf="#+id/addBtn">
<EditText
android:id="#+id/message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:background="#fff"
android:hint="Type a Message"
android:minHeight="50dp"
android:textSize="18sp" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/addBtn"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentEnd="true"
android:background="#drawable/back_fab"
android:layout_marginBottom="10dp"
android:layout_marginEnd="5dp"
android:elevation="4dp"
android:layout_centerInParent="true"
android:layout_alignParentRight="true"
android:layout_marginRight="5dp">
<ImageView
android:id="#+id/fab_img"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_centerInParent="true"
android:src="#drawable/ic_send_white_24dp"
android:tint="#fff"/>
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
ChatbotActivity
public class Chatbot extends AppCompatActivity implements AIListener {
RecyclerView recyclerView;
EditText message;
RelativeLayout addBtn;
ChatbotAdapter adapter;
Boolean flagFab = true;
private AIService aiService;
private AIServiceContext customAIServiceContext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chatbot);
recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
message = (EditText)findViewById(R.id.message);
addBtn = (RelativeLayout)findViewById(R.id.addBtn);
recyclerView.setHasFixedSize(true);
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(linearLayoutManager);
addBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String msg = message.getText().toString().trim();
if (!message.equals("")) {
ChatMessage chatMessage = new ChatMessage(msg, "user");
}
message.setText("");
}
});
adapter = new ChatbotAdapter();
recyclerView.setAdapter(adapter);
final AIConfiguration config = new AIConfiguration("Acces",
AIConfiguration.SupportedLanguages.French,
AIConfiguration.RecognitionEngine.System);
aiService = AIService.getService(this, config);
customAIServiceContext = AIServiceContextBuilder.buildFromSessionId("ID");
aiService.setListener(this);
final AIDataService aiDataService = new AIDataService(config);
final AIRequest aiRequest = new AIRequest();
addBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String msg = message.getText().toString().trim();
if (!msg.equals("")) {
aiRequest.setQuery(msg);
new AsyncTask<AIRequest,Void, AIResponse>(){
#Override
protected AIResponse doInBackground(AIRequest... aiRequests) {
final AIRequest request = aiRequests[0];
try {
final AIResponse response =
aiDataService.request(aiRequest);
return response;
} catch (AIServiceException e) {
}
return null;
}
#Override
protected void onPostExecute(AIResponse response) {
if (response != null) {
Result result = response.getResult();
String reply = result.getFulfillment().getSpeech();
}
}
}.execute(aiRequest);
}
else {
aiService.startListening();
}
message.setText("");
}
});
}
#Override
public void onResult(AIResponse response) {
}
#Override
public void onError(AIError error) {
}
#Override
public void onAudioLevel(float level) {
}
#Override
public void onListeningStarted() {
}
#Override
public void onListeningCanceled() {
}
#Override
public void onListeningFinished() {
}
}
Chatmessage
public class ChatMessage {
private String msgText;
private String msgUser;
public ChatMessage(String msgText, String msgUser){
this.msgText = msgText;
this.msgUser = msgUser;
}
public ChatMessage(){
}
//+getter & setter
}
ChatbotAdapter
//I don't know how to code this class
public class ChatbotAdapter extends RecyclerView.Adapter<ChatbotAdapter.ChatHolder>
{
#NonNull
#Override
public ChatHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.msglist, viewGroup, false);
return new ChatHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull ChatHolder chatHolder, int i) {
}
#Override
public int getItemCount() {
return 0;
}
public class ChatHolder extends RecyclerView.ViewHolder {
TextView leftText, rightText;
public ChatHolder(View itemView) {
super(itemView);
leftText = (TextView) itemView.findViewById(R.id.leftText);
rightText = (TextView) itemView.findViewById(R.id.rightText);
}
}
}
Your question is not that clear. Please add some more details like what is you want, what you have implemented and what issue is coming.
You may also try my implementation. I am not using Recycler view in my implementation, but you could follow the following article I wrote for integrating Dialogflow with Android. Try an follow the V2 version as V1 will phase out by October this year.
Also, Do not use fragment for Chatbot as it somehow does not work. Try and make a simple chatbot using my implementation and then you can work towards your own implementation.
Hope it works.
I tried the solutions on the other similar posts that I found here but they did not help me. I hope someone can help.
I get data from Unsplash's API and the ArrayList contains 10 items once I get a response, that's why I think It has to be something with the way the view is inflated.
This is code:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "unsplash";
private final String CLIENT_ID = "...myclientID...";
// testing keyword used on the API to search for pictures
private final String KEYWORD = "stackOverflow";
private final String urlBase = "https://api.unsplash.com/";
private Retrofit retrofit;
private RecyclerView recyclerView;
private RecyclerViewAdapter recyclerViewAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
retrofit = new Retrofit.Builder()
.baseUrl(urlBase)
.addConverterFactory(GsonConverterFactory.create())
.build();
recyclerView = findViewById(R.id.recyclerview);
recyclerView.setHasFixedSize(true);
GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
recyclerView.setLayoutManager(layoutManager);
recyclerViewAdapter = new RecyclerViewAdapter();
recyclerView.setAdapter(recyclerViewAdapter);
getData();
}
private void getData() {
PictureService service = retrofit.create(PictureService.class);
Call<PictureResponse> pictureResponseCall = service.getPictureList(KEYWORD, CLIENT_ID);
pictureResponseCall.enqueue(new Callback<PictureResponse>() {
#Override
public void onResponse(Call<PictureResponse> call, Response<PictureResponse> response) {
if (response.isSuccessful()){
PictureResponse pictureResponse = response.body();
ArrayList<UnsplashPic> pictureList = pictureResponse.getResults();
recyclerViewAdapter.addPictures(pictureList);
}else{
Log.e (TAG, " onResponse " + response.errorBody());
}
}
#Override
public void onFailure(Call<PictureResponse> call, Throwable t) {
Log.e (TAG, " onFailure " + t.getMessage());
}
});
}
}
My adapter class:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private ArrayList<UnsplashPic> pictureList;
public RecyclerViewAdapter (){
pictureList = new ArrayList<>();
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.item_view_holder, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int i) {
UnsplashPic pic = pictureList.get(i);
viewHolder.artistName.setText(pic.user.getUsername());
viewHolder.unsplash.setText("Unsplash");
}
#Override
public int getItemCount() {
return pictureList.size();
}
public void addPictures(ArrayList<UnsplashPic> pictureList) {
pictureList.addAll(pictureList);
notifyDataSetChanged();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private ImageView imageView;
private TextView artistName;
private TextView unsplash;
public ViewHolder (View itemView){
super(itemView);
imageView = itemView.findViewById(R.id.imageview);
artistName = itemView.findViewById(R.id.artist_name);
unsplash = itemView.findViewById(R.id.unsplash_name);
}
}
}
item_view_holder.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="#+id/imageview"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:background="#ababab"
android:contentDescription="unsplash picture" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Photo by "/>
<TextView
android:id="#+id/artist_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="on "/>
<TextView
android:id="#+id/unsplash_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true" />
</LinearLayout>
activity_main.xml
<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="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Search for pictures"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Search"/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/recyclerview">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
Here:
public void addPictures(ArrayList<UnsplashPic> pictureList) {
pictureList.addAll(pictureList);
notifyDataSetChanged();
}
you are actually adding the content of the pictureList you send as parameter of the function to that same list, your list from adapter is not updated.
You should do like this instead:
public void addPictures(ArrayList<UnsplashPic> pictureList) {
this.pictureList.addAll(pictureList);
notifyDataSetChanged();
}
I'm trying to fetch the data from my Firebase database but from some reason it doesn't work, so I'll try to provide as much info as posible ..
This is the database snapshot:
This is a POJO class:
public class Result2 implements Serializable {
private int score;
private String userName;
public Result2(int score, String userName) {
this.score = score;
this.userName = userName;
}
public int getScore() {
return score;
}
public String getUserName() {
return userName;
}
}
This is my activitys layout called activity_results.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:weightSum="2"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="50dp">
<TextView
android:textColor="#000"
android:textSize="16sp"
android:gravity="center"
android:text="USERNAME"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<TextView
android:textColor="#000"
android:textSize="16sp"
android:text="SCORE"
android:gravity="center"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
<View
android:background="#000"
android:layout_width="match_parent"
android:layout_height="1dp"
/>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="10dp"
android:clipToPadding="false"
android:scrollbars="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
As you can see, I want to have 2 TextViews that will act like tabs and a RecyclerView underneath that will show the data
Here is my Adapters ViewHolder layout called score_view_holder.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:weightSum="2">
<TextView
android:id="#+id/username"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:textSize="14sp" />
<TextView
android:id="#+id/score"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:textSize="14sp" />
</LinearLayout>
<View
android:background="#4545"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"/>
So it will contain two horizontal TextViews and a View as a line below..
Here is my Adapter:
public class ScoreAdapter extends RecyclerView.Adapter<ScoreAdapter.ScoreViewHolder> {
private List<Result2> results = new ArrayList<>();
public void setResults(List<Result2> results) {
this.results.clear();
this.results.addAll(results);
notifyDataSetChanged();
}
#Override
public ScoreAdapter.ScoreViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.score_view_holder, parent, false);
return new ScoreAdapter.ScoreViewHolder(view);
}
#Override
public void onBindViewHolder(ScoreAdapter.ScoreViewHolder holder, int position) {
Result2 result = getResult(position);
if (result != null) {
holder.setUsername(result.getUserName() != null ? result.getUserName() : "-");
holder.setScore(String.valueOf(result.getScore()));
}
}
private Result2 getResult(int position) {
return !results.isEmpty() ? results.get(position) : null;
}
#Override
public int getItemCount() {
return results.size();
}
public class ScoreViewHolder extends RecyclerView.ViewHolder {
private TextView username;
private TextView score;
public ScoreViewHolder(View itemView) {
super(itemView);
username = itemView.findViewById(R.id.username);
score = itemView.findViewById(R.id.score);
}
public void setUsername(String username) {
this.username.setText(username);
}
public void setScore(String score) {
this.score.setText(score);
}
}
}
It should get List of Result2 objects and just set text in those two TextViews (username and score)
And finally my Activity where all the magic doesn't happen :)
public class Results extends AppCompatActivity {
private DatabaseReference mDatabase;
private ScoreAdapter scoreAdapter;
private RecyclerView recyclerView;
private List<Result2> results = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_results);
recyclerView = findViewById(R.id.recycler_view);
scoreAdapter = new ScoreAdapter();
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(scoreAdapter);
mDatabase = FirebaseDatabase.getInstance().getReference();
loadResults();
}
private void loadResults() {
mDatabase.child("Users").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot childSnapshot : dataSnapshot.getChildren()) {
Result2 result = childSnapshot.getValue(Result2.class);
if(result != null) {
results.add(result);
}
}
Toast.makeText(Results.this, String.valueOf(results.size()), Toast.LENGTH_SHORT).show();
scoreAdapter.setResults(results);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
}
);
}
}
Funniest thing, Toast shows correct number of Results, but when scoreAdapter.setResults(results); is called, screen blinks and goes back to first screen... Does it have something to do with a POJO class, or onDataChange method or main thread?
I tried with debugging and also funny thing here.. This is what is caught on breakpoint inside ScoreAdapter setResult method:
I tried setting breakpoints inside onBindViewHolder and getResults() but none of them gets called :o
if(result != null) {
results.add(result);
}
See here you are checking result != null. But result is a reference variable of type Results. So it will not be null, it will contains some value.
So, try removing that if statement and do only -
results.add(result);
public class ExerciseList extends ArrayAdapter<Exercise> {
private Activity context;
List<Exercise> exercises;
public ExerciseList(Activity context, List<Exercise> exercises) {
super(context, R.layout.layout_exercise_list, exercises);
this.context = context;
this.exercises = exercises;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View listViewItem = inflater.inflate(R.layout.layout_exercise_list, null, true);
TextView nameTextView = listViewItem.findViewById(R.id.nameTextView);
TextView setsTextView = listViewItem.findViewById(R.id.setsTextView);
TextView repsTextView = listViewItem.findViewById(R.id.repsTextView);
TextView restTextView = listViewItem.findViewById(R.id.restTextView);
Exercise exercise = exercises.get(position);
nameTextView.setText(exercise.getName());
setsTextView.setText(String.valueOf(exercise.getSets()));
repsTextView.setText(String.valueOf(exercise.getReps()));
restTextView.setText(String.valueOf(exercise.getRestTime()));
return listViewItem;
}
}
public class WorkoutActivity extends AppCompatActivity {
EditText exerciseNameET;
EditText setsET;
EditText repsET;
EditText restTimeET;
Button addButton;
ArrayList<Exercise> exercises;
ListView exerciseList;
DatabaseReference dbExercises;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_workout);
dbExercises = FirebaseDatabase.getInstance().getReference("exercises");
exerciseNameET = findViewById(R.id.exerciseNameET);
setsET = findViewById(R.id.setsET);
repsET = findViewById(R.id.repsET);
restTimeET = findViewById(R.id.restTimeET);
addButton = findViewById(R.id.addButton);
exerciseList = findViewById(R.id.exerciseList);
exercises = new ArrayList<>();
addButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
addExercise();
}
});
}
#Override
protected void onStart() {
super.onStart();
dbExercises.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
exercises.clear();
for(DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
Exercise exercise = postSnapshot.getValue(Exercise.class);
exercises.add(exercise);
}
ExerciseList exerciseAdapter = new ExerciseList(WorkoutActivity.this, exercises);
exerciseList.setAdapter(exerciseAdapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void addExercise() {
String name = exerciseNameET.getText().toString();
int sets = Integer.parseInt(setsET.getText().toString());
int reps = Integer.parseInt(repsET.getText().toString());
int restTime = Integer.parseInt(restTimeET.getText().toString());
if((!TextUtils.isEmpty(name)) || (!TextUtils.isEmpty(setsET.getText().toString())) || (!TextUtils.isEmpty(repsET.getText().toString())) || (!TextUtils.isEmpty(restTimeET.getText().toString()))) {
String id = dbExercises.push().getKey();
Exercise exercise = new Exercise(id,name,sets,reps,restTime);
dbExercises.child(id).setValue(exercise);
exerciseNameET.setText("");
setsET.setText("");
repsET.setText("");
restTimeET.setText("");
} else {
Toast.makeText(this, "Invalid fields. Please complete the missing fields.", Toast.LENGTH_LONG).show();
}
}
}
I have created a custom adapter to be used for a ListView of one of my activites. This custom adapter is created in the onStart() method. I also have a separate layout file for each item in this ListView. The app uses Firebase and it successfully saves information to the database, but the app crashes when trying to display this same information on the ListView. I have followed many tutorials and my professor's lab solutions but I still do not know why my app is crashing. The XML files for the main activity is included below:
<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="match_parent"
tools:context="com.josh2.mygains.WorkoutActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="#+id/exerciseNameET"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Exercise name"
android:inputType="textPersonName" />
<EditText
android:id="#+id/setsET"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Number of sets"
android:inputType="textPersonName" />
<EditText
android:id="#+id/repsET"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Number of reps"
android:inputType="textPersonName" />
<EditText
android:id="#+id/restTimeET"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Length of rest time"
android:inputType="textPersonName" />
<Button
android:id="#+id/addButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#+id/exerciseList"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</ScrollView>
</LinearLayout>
The XML file for the items of the ListView is found below:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/nameTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp" />
<TextView
android:id="#+id/setsTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="15sp" />
<TextView
android:id="#+id/repsTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="15sp" />
<TextView
android:id="#+id/restTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="15sp" />
your adapter code is minefield for possible null pointer exceptions. String.valueOf(null) returns NullPointerException, so you should carefully handle any exception here.
if(exercise!=null && exercise.getSets()!=null){
setsTextView.setText(String.valueOf(exercise.getSets()));
}
apply same procedure for rest 2 setters as well.
In addition, the way you have handled your data update in the custom adapter is not standard. You should initiate your adapter in onCreate as you don't have to initialize the adapter every time the list is updated.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_workout);
dbExercises = FirebaseDatabase.getInstance().getReference("exercises");
exerciseNameET = findViewById(R.id.exerciseNameET);
setsET = findViewById(R.id.setsET);
repsET = findViewById(R.id.repsET);
restTimeET = findViewById(R.id.restTimeET);
addButton = findViewById(R.id.addButton);
exerciseList = findViewById(R.id.exerciseList);
exercises = new ArrayList<>();
ExerciseList exerciseAdapter = new ExerciseList(WorkoutActivity.this,
exercises);
exerciseList.setAdapter(exerciseAdapter);
addButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
addExercise();
}
});
}
and keep an updateExerciseList method on your custom adapter so that you can update the list in your adapter every time data is updated
public void updateExerciseList(List<Exercise> exercises) {
this.exercises = exercises;
}
simply update your data list after database is updated
#Override
protected void onStart() {
super.onStart();
dbExercises.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
exercises.clear();
for(DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
Exercise exercise = postSnapshot.getValue(Exercise.class);
exercises.add(exercise);
}
exerciseAdapter.updateExerciseList(exercises);
exerciseAdapter.setNotifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}