I have implemented the firebase recycler like this
public class HomeActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final String REQUIRED = "Required";
// [START declare_database_ref]
private DatabaseReference mDatabase;
// [END declare_database_ref]
private FirebaseAuth mAuth;
private static String LOG_TAG = "CardViewActivity";
public static class PostHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
View mView;
public PostHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
mView = itemView;
}
public void setName(String name) {
TextView field = (TextView) mView.findViewById(R.id.name);
field.setText(name);
}
public void setText(String text) {
TextView field = (TextView) mView.findViewById(R.id.body);
field.setText(text);
}
public void setImage(String image){
ImageView pp = (ImageView) mView.findViewById(R.id.image);
Picasso.with(Application.getAppContext()).load(image).placeholder(R.drawable.nodp).error(R.drawable.nodp).transform(new CircleTransform()).into(pp);
}
#Override
public void onClick(View mView) {
//what to do here
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
findViewById(R.id.progressBar3).setVisibility(View.VISIBLE);
findViewById(R.id.nopost).setVisibility(View.GONE);
//mListview = (ListView) findViewById(R.id.listview);
mAuth = FirebaseAuth.getInstance();
//the post list shit is happening here
final DatabaseReference root = FirebaseDatabase.getInstance().getReference();
FirebaseUser user = mAuth.getCurrentUser();
DatabaseReference postRef = root.child("users").child(user.getUid().toString()).child("posts");
RecyclerView recycler = (RecyclerView) findViewById(R.id.recyclerview);
recycler.setHasFixedSize(true);
recycler.setLayoutManager(new LinearLayoutManager(this));
FirebaseRecyclerAdapter mAdapter = new FirebaseRecyclerAdapter<PostList, PostHolder>(PostList.class, R.layout.row_one, PostHolder.class, postRef) {
#Override
public void populateViewHolder(PostHolder postViewHolder, PostList postList, int position) {
//try catch block to catch events of no posts, it will most likely return a null error, so im catching it, else
//find its exception and catch it
try {
String firstname = postList.getFirstname();
String lastname = postList.getLastname();
firstname = firstname.substring(0, 1).toUpperCase() + firstname.substring(1); //convert first string to uppercase
lastname = lastname.substring(0, 1).toUpperCase() + lastname.substring(1);// same thing happening here
String name = (firstname + " " + lastname); // concatenate firstname and lastname variable.
postViewHolder.setName(name);
postViewHolder.setText(postList.getBody()); // set the vew holder
//note that picasso view holder was applied in the view holder instead
String image = postList.getImgUrl().toString();
postViewHolder.setImage(image);
findViewById(R.id.progressBar3).setVisibility(View.GONE);
}
catch(NullPointerException e) {
findViewById(R.id.nopost).setVisibility(View.VISIBLE);
}
}
};
recycler.setAdapter(mAdapter);
}
}
and it works perfectly for my use case, I have gone through questions about how to set up onClick listeners for recycler adapter, and I think I've got it as seen in my code above.
My question is:
minor issue: when an item is clicked, I want to pass data through an intent to another activity to display details about the post. I can achieve this through intent.putExtra() on my ViewHolder as referenced by another question. But my problem is that my view holder class is outside the activity's onCreate() (that's the only way it seemed to work) so I can't call start activity from within ViewHolder,
major issue: since PostList, from which my data is from, is not yet set in the ViewHolder, so I can't put postList.getName() and getBody() in an intent, but I think it would be okay if my onClick() can go inside the firebase block itself, here:
FirebaseRecyclerAdapter mAdapter = new FirebaseRecyclerAdapter<PostList, PostHolder>(PostList.class, R.layout.row_one, PostHolder.class, postRef) {
#Override
public void populateViewHolder(PostHolder postViewHolder, PostList postList, int position) {
//try catch block to catch events of no posts, it will most likely return a null error, so im catching it, else
//find its exception and catch it
try {
String firstname = postList.getFirstname();
String lastname = postList.getLastname();
firstname = firstname.substring(0, 1).toUpperCase() + firstname.substring(1); //convert first string to uppercase
lastname = lastname.substring(0, 1).toUpperCase() + lastname.substring(1);// same thing happening here
String name = (firstname + " " + lastname); // concatenate firstname and lastname variable.
postViewHolder.setName(name);
postViewHolder.setText(postList.getBody()); // set the vew holder
//note that picasso view holder was applied in the view holder instead
String image = postList.getImgUrl().toString();
postViewHolder.setImage(image);
findViewById(R.id.progressBar3).setVisibility(View.GONE);
}
catch(NullPointerException e) {
findViewById(R.id.nopost).setVisibility(View.VISIBLE);
}
}
//onclick goes here with all the put extra and startactivity stuff
};
recycler.setAdapter(mAdapter);
You mean that you cannot get the origin activity to create the intent? have you tried getContext(), getActivity() or getBaseContext()?
Context context = getContext();
final Intent intent = new Intent(context, FirstActivity.class);
// all your stuff
context.startActivity(intent);
If you want to perform good item click functionality with a proper way then create a separate class for FirebaseRecyclerAdapter and use Interface as item click listener so you can perform intent functionality from HomeActivity.
OR
Create reference of HomeActivity class and use that reference at
#Override
public void onClick(View mView) {
//what to do here
//mcontect will be your class reference
Intent i = new (mcontext,SecondActivity.class);
startActivity(i);
}
Related
I'm currently working on an app in which users can create groups and add members to groups. Today I created a new user to test the app. When I logged in this new user I checked to see if it was a part of any groups, which I didn't expect it to be seeing as it was new. And it wasn't. But then when I logged in my usual user and clicked groups I saw the name of the test user. Why does it appear that this user is a part of a group it was never added to?
It should be noted that when looking through my firebase this test user doesn't appear to have been invited either. I'm using firestore recycler adapter to fetch data in a recyclerView.
Below is the code for my adapter responsible for adding members to a specific group.
FirestoreMemberAdapter.java:
public class FirestoreMemberAdapter extends FirestoreRecyclerAdapter<MemberModel, FirestoreMemberAdapter.MemberViewHolder> {
private static final String TAG = FirestoreMemberAdapter.class.getSimpleName();
private Context context;
private String projectId;
private String projectName;
public FirestoreMemberAdapter(#NonNull FirestoreRecyclerOptions<MemberModel> options, Context context, String projectId, String projectName) {
super(options);
this.context = context;
this.projectName = projectName;
this.projectId = projectId;
}
#Override
protected void onBindViewHolder(#NonNull MemberViewHolder holder, int position, #NonNull final MemberModel model) {
holder.mTextView.setText(model.getName());
if (model.getProfile_image() == null) {
Picasso.get().load(R.drawable.profile_image).into(holder.mImageview);
} else {
Picasso.get().load(model.getProfile_image()).into(holder.mImageview);
}
holder.mLinearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d(TAG, "onClick: Clicked on FirestoreMemberAdapter ");
Intent intent = new Intent(context, ProfileMemberPage.class);
intent.putExtra(StringCreator.PROJECT_TITLE, projectName);
intent.putExtra(StringCreator.PROJECT_ID, projectId);
intent.putExtra(StringCreator.NAME, model.getName());
intent.putExtra(StringCreator.EMAIL, model.getEmail());
intent.putExtra(StringCreator.USER_ID, model.getUser_id());
intent.putExtra(StringCreator.USER_INFORMATION, model.getUser_information());
context.startActivity(intent);
}
});
}
#NonNull
#Override
public MemberViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_projectmembers, parent, false);
return new MemberViewHolder(view);
}
public class MemberViewHolder extends RecyclerView.ViewHolder {
private LinearLayout mLinearLayout;
private TextView mTextView;
private ImageView mImageview;
public MemberViewHolder(#NonNull View itemView) {
super(itemView);
mTextView = itemView.findViewById(R.id.memberTitle);
mLinearLayout = itemView.findViewById(R.id.layout_members);
mImageview = itemView.findViewById(R.id.memberImage);
}
}
}
Here is the activity in wihch the adapter is used.
projectClicked.java:
//widgets
private RecyclerView recyclerViewMembers;
private TextView projectName;
private Button cameraBtn;
private FloatingActionButton addUserBtn;
//Firebase
private FirebaseFirestore firebaseFirestore = FirebaseFirestore.getInstance();
private Query query;
private FirestoreRecyclerOptions<MemberModel> options;
private FirestoreMemberAdapter adapter;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_project_clicked);
projectName = findViewById(R.id.projectName);
addUserBtn = findViewById(R.id.addUserBtn);
cameraBtn = findViewById(R.id.cameraBtn);
initRecyclerView();
addUserBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent newIntent = new Intent(projectClicked.this, UserToProject.class);
Bundle projectBundle = getIntent().getExtras();
if (projectBundle != null) {
newIntent.putExtras(projectBundle);
}
startActivity(newIntent);
}
});
}
private void initRecyclerView() {
Log.d(TAG, "InitRecyclerView: init recyclerview");
if (getIntent().hasExtra(StringCreator.PROJECT_TITLE) && getIntent().hasExtra(StringCreator.PROJECT_ID)) {
final String pName = getIntent().getStringExtra(StringCreator.PROJECT_TITLE);
final String pID = getIntent().getStringExtra(StringCreator.PROJECT_ID);
projectName.setText(pName);
recyclerViewMembers = findViewById(R.id.recyclerView_members);
query = firebaseFirestore.collection("users");
options = new FirestoreRecyclerOptions.Builder<MemberModel>().setQuery(query, MemberModel.class).build();
adapter = new FirestoreMemberAdapter(options, projectClicked.this, pID, pName);
recyclerViewMembers.setHasFixedSize(true);
recyclerViewMembers.setAdapter(adapter);
recyclerViewMembers.setLayoutManager(new LinearLayoutManager(projectClicked.this));
}
}
#Override
public void onStart() {
super.onStart();
adapter.startListening();
}
#Override
public void onStop() {
super.onStop();
adapter.stopListening();
}
Hope this makes sense, please reach out if it doesn't. Thank you in advance.
As #McSlinPlay mentioned, the reason could be pointed out to your code in projectClicked.java where you created your query and all the users (including the test user) are part of this collection:
query = firebaseFirestore.collection("users");
When I make changes to the data which is displayed using ListView and DataSnapshot the data is not refreshed in real time until I restart the Activity. The ListView loads and displays all the data without any problem. Why is this happening and how to solve this ?
MainMenuRequest.java
public class MainMenuRequest extends AppCompatActivity {
String UserNameString;
DatabaseReference db;
ListView lv;
ArrayList<RequestItem> list = new ArrayList<>();
RequestItemAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_menu_request);
makeItem();
}
public void makeItem ()
{
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReferenceFromUrl("https://vsem-inventory.firebaseio.com/ItemRequest");
ValueEventListener valueEventListener = new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
list = new ArrayList<RequestItem>();
for(DataSnapshot dSnapshot : dataSnapshot.getChildren()) {
for(DataSnapshot ds : dSnapshot.getChildren()) {
RequestItem Ri = ds.getValue(RequestItem.class);
Ri.setRefID(ds.getKey());
Log.d("myTag",ds.getKey());
list.add(Ri);
}
}
lv = findViewById(R.id.listViewRequest);
adapter = new RequestItemAdapter(MainMenuRequest.this,list);
lv.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d("DatabaseError", databaseError.getMessage()); //Don't ignore errors!
}
};
rootRef.addListenerForSingleValueEvent(valueEventListener);
}
}
RequestItemAdapter.java
public class RequestItemAdapter extends ArrayAdapter<RequestItem> {
private Context ctx;
private ArrayList<RequestItem> list;
ImageView statusimg;
Drawable lateIcon;
Drawable paidIcon;
public RequestItemAdapter(Context context, ArrayList<RequestItem> list)
{
super(context,0,list);
this.ctx = context;
this.list = list;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View listItem = convertView;
if(listItem == null)
listItem = LayoutInflater.from(ctx).inflate(R.layout.content_main_menu_request_list,parent,false);
final RequestItem rq = list.get(position);
final TextView tvAmount = listItem.findViewById(R.id.amountReq);
final TextView tvName = listItem.findViewById(R.id.nameReq);
final TextView tvSerial = listItem.findViewById(R.id.serialNoReq);
final TextView tvSupplier = listItem.findViewById(R.id.supplierNameReq);
final ImageView more = listItem.findViewById(R.id.moreReq);
statusimg = listItem.findViewById(R.id.statusReq);
lateIcon = listItem.getResources().getDrawable(R.drawable.late);
Drawable pendingIcon = listItem.getResources().getDrawable(R.drawable.pending);
String userName = rq.getRequestBy();
userName = userName.replace("#vsemtech.com","");
tvAmount.setText(userName);
tvName.setText(rq.getProductName());
tvSerial.setText(rq.getSerialNo());
tvSupplier.setText(rq.getCategory());
String status = rq.getStatus();
if(status.equals("REJECT"))
statusimg.setImageDrawable(lateIcon);
else if (status.equals("APPROVED"))
statusimg.setImageDrawable(paidIcon);
else if (status.equals("PENDING"))
statusimg.setImageDrawable(pendingIcon);
more.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v) {
String RequestBy = rq.getRequestBy();
String Status = rq.getStatus();
String ProductName = rq.getProductName();
String SerialNo = rq.getSerialNo();
String Model = rq.getModel();
String Category = rq.getCategory();
String Quantity = rq.getQuantity();
String Remarks = rq.getRemarks();
showMenu(rq,more);
}
});
return listItem;
}
public void showMenu (RequestItem reqItem,ImageView More)
{
final RequestItem finalItem = reqItem;
final ImageView more = More;
final String shortRequestby = reqItem.getRequestBy().replace("#vsemtech.com","");
final DatabaseReference DeleteRef = FirebaseDatabase.getInstance().getReference().child("ItemRequest").child(shortRequestby);
final DatabaseReference DbRef = FirebaseDatabase.getInstance().getReference().child("ItemRequest").child(shortRequestby).child(finalItem.getRefID());
//Creating the instance of PopupMenu
PopupMenu popup = new PopupMenu(ctx, more);
//Inflating the Popup using xml file
popup.getMenuInflater().inflate(R.menu.menu_options_req, popup.getMenu());
//registering popup with OnMenuItemClickListener
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.item_approve)
{
DeleteRef.child(finalItem.getRefID()).removeValue();
writeNewPost(new RequestItem(finalItem,"APPROVED"));
Toast.makeText(ctx,"Successfully approved request made by " + shortRequestby ,Toast.LENGTH_SHORT).show();
}
else if (itemId == R.id.item_reject)
{
DeleteRef.child(finalItem.getRefID()).removeValue();
writeNewPost(new RequestItem(finalItem,"REJECTED"));
Toast.makeText(ctx,"Successfully rejected request made by " + shortRequestby ,Toast.LENGTH_SHORT).show();
}
return true;
}
});
popup.show();//showing popup menu
}
public void writeNewPost(RequestItem item)
{
DatabaseReference dbReq = FirebaseDatabase.getInstance().getReference().child("ItemHistory").child(item.getRequestBy().replace("#vsemtech.com",""));
String key = dbReq.push().getKey();
Map<String, Object> postValues = toMap(item);
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put(key, postValues);
dbReq.updateChildren(childUpdates);
}
public Map<String, Object> toMap(RequestItem item)
{
HashMap<String, Object> result = new HashMap<>();
result.put("ProductName", item.getProductName());
result.put("SerialNo", item.getSerialNo());
result.put("Quantity", item.getQuantity());
result.put("Category",item.getCategory());
result.put("Model", item.getModel());
result.put("RequestBy", item.getRequestBy());
result.put("Status",item.getStatus());
result.put("Remarks",item.getRemarks());
return result;
}
}
You are using addListenerForSingleValueEvent() which will only listen for single value and then stop. You need to use addValueEventListener().
one way of doing this is you need to add elements in this ArrayList<RequestItem> list by making this as static in adapter class instead of the list in activity which you are passing to the adapter then you notifyDataSetChanged() function will work if you want to show changes in the list in real time
I suggest you to use the already built in library to make the list automatically updated when new data is pushed in firebase: check out this
If you want to stick with a custom implementation, define the adapter first in OnCreate callback and call adapter.notifyDataSetChanged() every time you updated your data.
If you want to insert/update/delete only one item inside your list call adapter.notifyItemChanged(position) from your adapter.
I strongly suggest you to switch to RecyclerView instead of ListView in Android (interesting comparison between them)
I am trying to do this..
.
I am consuming two different requests resources from the same API and in MainActivity doing two different calls. But, I can't show the content I want from both JSON on one RecyclerView view.
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Retrofit retrofit;
private static final String TAG = "Football";
private RecyclerView recyclerView;
private ListaPartidosAdapter listaPartidosAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
listaPartidosAdapter = new ListaPartidosAdapter(this);
recyclerView.setAdapter(listaPartidosAdapter);
recyclerView.setHasFixedSize(true);
final LinearLayoutManager layoutManager = new LinearLayoutManager(this, VERTICAL, true);
recyclerView.setLayoutManager(layoutManager);
retrofit = new Retrofit.Builder()
.baseUrl("http://api.football-data.org/v2/")
.addConverterFactory(GsonConverterFactory.create())
.build();
obtenerDatos();
}
private void obtenerDatos() {
Calendar calendar = Calendar.getInstance();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String todayDate=df.format(calendar.getTime());
calendar.add(Calendar.DATE,3);
String endDate = df.format(calendar.getTime());
Log.i(TAG, "todayDate : " + todayDate);
Log.i(TAG, "endDate : " + endDate);
footballdataService service = retrofit.create(footballdataService.class);
Call<PartidosRespuesta> partidosRespuestaCall = service.obtenerlistaPartidos(todayDate,endDate);
Call<StandingsRespuesta> standingsRespuestaCall = service.obtenerStandings();
partidosRespuestaCall.enqueue(new Callback<PartidosRespuesta>() {
#Override
public void onResponse(Call<PartidosRespuesta> call, Response<PartidosRespuesta> response) {
if(response.isSuccessful()) {
PartidosRespuesta partidosRespuesta = response.body();
List<Partido> listaPartidos = partidosRespuesta.getMatches();
listaPartidosAdapter.adicionarListaPartidos((ArrayList<Partido>) listaPartidos);
}
else {
Log.e(TAG, "onResponse: " + response.errorBody());
}
}
#Override
public void onFailure(Call<PartidosRespuesta> call, Throwable t) {
Log.e(TAG, "onFailure: " + t.getMessage());
}
});
standingsRespuestaCall.enqueue(new Callback<StandingsRespuesta>() {
#Override
public void onResponse(Call<StandingsRespuesta> call, Response<StandingsRespuesta> response) {
if(response.isSuccessful()) {
StandingsRespuesta standingsRespuesta = response.body();
List<Stand> listaStands = standingsRespuesta.getStandings();
listaPartidosAdapter.adicionarListaStands((ArrayList<Stand>) listaStands);
}
}
#Override
public void onFailure(Call<StandingsRespuesta> call, Throwable t) {
}
});
}
}
As I say before, each request has a different enqueue Call. I don't know if it is the right way of do it but think yes because each call has its own service.
ListaPartidosAdapter.java
public class ListaPartidosAdapter extends RecyclerView.Adapter<ListaPartidosAdapter.ViewHolder> {
private static final String TAG = "Football_Adapter";
private ArrayList<Partido> dataset;
private ArrayList<Stand> dataset_stand;
private Context context;
public ListaPartidosAdapter(Context context) {
this.context = context;
this.dataset = new ArrayList<Partido>();
this.dataset_stand = new ArrayList<Stand>();
}
#Override
public ListaPartidosAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_partidos, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ListaPartidosAdapter.ViewHolder holder, int position) {
Partido p = dataset.get(position);
String status = p.getStatus();
if (status.equals("SCHEDULED")){
String status_ = "SCH";
holder.status.setText(status_);
}
holder.utcDate.setText(p.getUtcDate());
Partido.EquipoCasa homeTeam = p.getHomeTeam();
String id_homeTeam = homeTeam.getId();
holder.homeTeam.setText(homeTeam.getName());
Partido.EquipoVisita awayTeam = p.getAwayTeam();
holder.awayTeam.setText(awayTeam.getName());
Stand s = dataset_stand.get(position);
Stand.Table table = (Stand.Table) s.getTable();
Stand.Table.Equipo team = (Stand.Table.Equipo) table.getEquipo();
String id_equipo = team.getId();
holder.homeTeam.setText(team.getName());
if(id_homeTeam.equals(id_equipo)){
Glide.with(context)
.load(team.getCrestUrl())
.centerCrop()
.crossFade()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(holder.team);
//holder.team.setImageDrawable(team.getCrestUrl());
}
}
#Override
public int getItemCount() {
return dataset.size()+dataset_stand.size();
}
public void adicionarListaPartidos(ArrayList<Partido> listaPartidos){
dataset.addAll(listaPartidos);
notifyDataSetChanged();
}
public void adicionarListaStands(ArrayList<Stand> listaStands){
dataset_stand.addAll(listaStands);
notifyDataSetChanged();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView status;
private TextView utcDate;
private TextView homeTeam;
private TextView awayTeam;
public ImageView team;
public ViewHolder(View itemView) {
super(itemView);
status = (TextView) itemView.findViewById(R.id.status);
utcDate = (TextView) itemView.findViewById(R.id.utcDate);
homeTeam = (TextView) itemView.findViewById(R.id.homeTeam);
awayTeam = (TextView) itemView.findViewById(R.id.awayTeam);
team = (ImageView) itemView.findViewById(R.id.team);
}
}
}
The problem comes in this line. Stand s = dataset_stand.get(position);, if a comment it with code below, It works without using the second JSON or the second request but as I showed on image I want to merge two different requests on the same RecyclerView view.
The problem statement
The problem comes in this line. Stand s = dataset_stand.get(position);, if a comment it with code below, It works without using the second JSON or the second request.
Yes, it's expected. Why? Because you're calling RecyclerView.Adapter#notifyDataSetChanged() method inside adicionarListaPartidos(ArrayList<Partido> listaPartidos) after inserting data to ArrayList in RecyclerView array adapter class which informs ArrayAdapter to redraw/refresh components inside RecyclerView container.
Now RecycelrView starts binding component within the onBindViewHolder(ListaPartidosAdapter.ViewHolder holder, int position) method. So, what's happening here?
#Override
public void onBindViewHolder(ListaPartidosAdapter.ViewHolder holder, int position) {
Partido p = dataset.get(position);
String status = p.getStatus();
if (status.equals("SCHEDULED")){
String status_ = "SCH";
holder.status.setText(status_);
}
holder.utcDate.setText(p.getUtcDate());
Partido.EquipoCasa homeTeam = p.getHomeTeam();
// other code
Stand s = dataset_stand.get(position); // <====== the problem
// other code
}
Your dataset_stand list will be empty (size of the list is 0) until you get data/response from standingsRespuestaCall.enqueue() method in your activity.
Keep in mind that Retrofit's Call#enque() method is Asynchronous. Which means in your case obtenerDatos() method executes top to bottom in a single hit. You only get data when Retrofit returns success response with onResponse() method.
The easiest way to fix this issue is to comment out the notifyDataSetChanged() method inside adicionarListaPartidos(ArrayList<Partido> listaPartidos). Like below
public void adicionarListaPartidos(ArrayList<Partido> listaPartidos){
dataset.addAll(listaPartidos);
// notifyDataSetChanged(); // <====== just COMMENT OUT this line
}
This will prevent onBindViewHolder() being called. When the second request standingsRespuestaCall.enqueue() completes it's operation, as per your code notifies dataset changed. Like below.
public void adicionarListaStands(ArrayList<Stand> listaStands){
dataset_stand.addAll(listaStands);
notifyDataSetChanged(); // <==== DO NOT remove this
}
Side Note: Your code is problematic. You're using multiple request to fill a single RecyclerView container. Your RecyclerView fails to display record if standingsRespuestaCall.enqueue() fails to get response from server.
PS: Please check method names I mentioned in my answer properly and alter the code accordingly. Do not get confused with the method names.
recently I been reading about the mvp pattern on Internet and to be honest, it has been a little bit confusing.
I'm trying to re-write an app using the mvp pattern but I reached a point using AsyncTask where I can't figure out how to pass the Object in the Interactor back to the View.
Here'e the code:
View:
public class DetailsActivity extends BaseActivity {
private DetailsPresenter presenter;
private Pet pet;
private TextView name, description, breed, lostAt, age;
private int idList;
#Override
protected void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
setContentView(R.layout.details_layout);
DetailsPresenter presenter = new DetailsPresenter();
Typeface font0 = Typeface.createFromAsset(getAssets(), "fonts/CaviarDreams.ttf");
Typeface font1 = Typeface.createFromAsset(getAssets(), "fonts/CaviarDreams_Bold.ttf");
TextView txtDescription = findViewById(R.id.textView8);
TextView txt1 = findViewById(R.id.textView6); //Age, Type
TextView txt2 = findViewById(R.id.textView9); //LostAt
Button btnContact = findViewById(R.id.button6);
description = findViewById(R.id.details);
menuRes = R.menu.details_menu;
name = findViewById(R.id.textView10);
breed = findViewById(R.id.breed);
lostAt = findViewById(R.id.lostAt);
age = findViewById(R.id.age);
name.setTypeface(font1);
breed.setTypeface(font0);
description.setTypeface(font0);
lostAt.setTypeface(font0);
txtDescription.setTypeface(font1);
txt2.setTypeface(font1);
txt1.setTypeface(font1);
btnContact.setTypeface(font0);
idList = getIntent().getExtras().getInt("TAG_LIST");
id = getIntent().getExtras().getInt("TAG_ID");
if(idList == 0){
txt1.setText(R.string.type);
txt2.setText(R.string.txt2);
} else{
txt1.setText(R.string.txt0);
txt2.setText(null);
}
btnContact.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(), ChatFragment.class);
startActivity(intent);
}
});
// Get pet details from database on background
pet = presenter.getPet(idList, id);
}
#Override
protected void onPostCreate(#Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
if(idList == 0){
name.setText(pet.getName());
breed.setText("(" + pet.getBreed() + ")");
description.setText(pet.getDescription());
lostAt.setText(pet.getLocation());
}else{
name.setText(pet.getBreed());
description.setText(pet.getDescription());
lostAt.setText(pet.getGender());
age.setText(pet.getAge());
}
}
}
Presenter:
public class DetailsPresenter {
private DetailsInteractor interactor;
public Pet getPet(int idList, int id) {
interactor = new DetailsInteractor(idList, id);
interactor.execute();
return interactor.pet;
}
}
Interactor:
public class DetailsInteractor extends AsyncTask<String, String, Pet> {
public Pet pet;
private int idList;
private int id;
private DBAction database;
public DetailsInteractor (int idList, int id) {
this.idList = idList;
this.id = id;
database = new DBAction();
}
#Override
protected Pet doInBackground(String... strings) {
pet = database.requestItem(idList, id);
return pet;
}
I need that after getting the data from the database, it updates the View, using object Pet.
Any answers and suggestions will be welcomed, Thanks!
When You create/initialize a presenter in Activity(This is your view) you should pass the view to the presenter. Something like this.
DetailsPresenter presenter = new DetailsPresenter(View view);
View can be any object with which you can update the UI or can call the methods in the activity.
Moreover, you have to go through few more good site to learn about MVP.
http://valokafor.com/learn-android-mvp-pattern-example/ this is really nice one.
In my app,I sucessfully retrieve from a webserver a list of images. They are read as urls ie
http://mw2.google.com/mw-panoramio/photos/medium/131093147.jpg
and so on.
I store the images in the SQLite as string urls. But now I want to display them in a recyclerview.
This is my adapter.
public class MySQLAdapter extends RecyclerView.Adapter<MySQLAdapter.RowHolderClass> {
private List<SQLiteModel> myList;
private Context mContext;
private int focused;
public MySQLAdapter(Activity activity,ArrayList<SQLiteModel> ss) {
this.myList = ss;
this.mContext=activity;
}
#Override
public MySQLAdapter.RowHolderClass onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_row, null);
final RowHolderClass holder = new RowHolderClass(v);
return holder;
}
#Override
public void onBindViewHolder(RowHolderClass holder, int position) {
final SQLiteModel listItems = myList.get(position);
holder.itemView.setSelected(focused==position);
holder.getLayoutPosition();
holder.fName.setText(myList.get(position).getSqliteFirstName());
holder.lName.setText(myList.get(position).getSqliteSecondName());
holder.jobRole.setText(myList.get(position).getSqliteRole());
//holder.imageView.setImageResource(Integer.parseInt(myList.get(position).getSqliteImage()));
holder.relativeLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String first_name = listItems.getSqliteFirstName();
String last_name = listItems.getSqliteSecondName();
String job_role = listItems.getSqliteRole();
//String image_url = listItems.get();
//String id= String.valueOf(listItems.getSqliteId());
//Log.v("id",id);
Intent i = new Intent(mContext, NoInternetDetailedActivity.class);
i.putExtra("firstName",first_name);
i.putExtra("lastName",last_name);
i.putExtra("jobRole",job_role);
//i.putExtra("imageUrl",image_url);
//i.putExtra("memberId",id);
mContext.startActivity(i);
}
});
}
#Override
public int getItemCount() {
return myList.size();
}
//ViewHolder pattern used to read the data of the row fast.
class RowHolderClass extends RecyclerView.ViewHolder {
protected NetworkImageView imageView;
protected TextView fName, lName, jobRole;
protected RelativeLayout relativeLayout;
public RowHolderClass(View itemView) {
super(itemView);
this.relativeLayout = (RelativeLayout) itemView.findViewById(R.id.recLayout);
this.imageView = (NetworkImageView) itemView.findViewById(R.id.imageView);
this.fName = (TextView) itemView.findViewById(R.id.firstName);
this.lName = (TextView) itemView.findViewById(R.id.lastName);
this.jobRole = (TextView) itemView.findViewById(R.id.roleView);
}
}
}
Ι display the rest of the data inside the onBindViewHolder as
holder.fName.setText(myList.get(position).getSqliteFirstName());
holder.lName.setText(myList.get(position).getSqliteSecondName());
holder.jobRole.setText(myList.get(position).getSqliteRole());
I think I need to convert the URL String into a byte array inside that method. I am not sure. Any ideas?
And something else. When I click on recyclerview's row I get the following exception.
java.lang.NullPointerException: Attempt to invoke virtual method
'java.lang.String android.content.Context.getPackageName()' on a null object
reference
at android.content.ComponentName.<init>(ComponentName.java:77)
This is how my recyclerview looks like without the image.
public void fetchDataFromDB() {
dba = new DatabaseHandler(getApplicationContext());
ArrayList<SQLiteModel> membersDB = dba.getMembersDetails();
for(int i=0; i<membersDB.size();i++){
int id = membersDB.get(i).getSqliteId();
String fname = membersDB.get(i).getSqliteFirstName();
String lname = membersDB.get(i).getSqliteSecondName();
String role = membersDB.get(i).getSqliteRole();
String image = membersDB.get(i).getSqliteImage();
//String desc = moviesFromDB.get(i).getContent();
SQLiteModel f = new SQLiteModel();
f.setSqliteId(id);
f.setSqliteFirstName(fname);
f.setSqliteSecondName(lname);
f.setSqliteRole(role);
f.setSqliteImage(image);
myarr.add(f);
}
dba.close();
}
}
Use
Picasso
This is very simple library which allows you to download and cache you images.
So in you case you should write something like:
Picasso.with(mContext)
.load(myList.get(position).getSqliteImage())
.into(holder.imageView);
You have there NetworkImageView, that is currently less and less used. I would suggest you to change this to standard ImageView + using Picasso library, then you can load image by:
Picasso.with(holder.imageView.getContext()).load(myList.get(position).getUrl()).into(holder.imageView);
Thanks to Mateusz Pryczkowski
The answer for the images is:
Picasso.with(holder.imageView.getContext())
.load(myList.get(position).getSqliteImage()).into(holder.imageView);