android fragment to fragment communication : update recyclerView of the ReceiverFragment via interface - android

I have two fragments and I am trying to update the recyclerView of the ReceiverFragment via interface. Both fragments have its own adapter (SenderAdapter and ReceiverAdapter).
I have to mention that I also have two SQLDatabase, where group.db is used to populate the SenderFragment and client.db is used to populate the ReceiverFragment.
But ReceiverFragment will only be populate if a CheckBox is ticked in the SenderAdapter.
All the communication between the fragments is ok. When I tick a CheckBox, The SenderAdapter sends a message to MainActivity and the MainActivity sends the same message to ReceiverFragment.
This is SenderFragment:
This would be the desired result.
When I use the message from interface to read the client.db, I get the nullException.
This is the ReceiverFragment:
public class ReceiverFragment extends Fragment {
View view;
private RecyclerView mClientList;
private RecyclerView.Adapter mClientListAdapter;
private RecyclerView.LayoutManager mClientListLayoutManager;
private String receivedFromSender;
ArrayList<ClientObject> clientList;
SQLiteDatabase clientListTable;
ClientRepository clientRepository;
private static String rootPath = Environment.getExternalStorageDirectory()+"/PassKeyBF/";
public ReceiverFragment() {
// Required empty public constructor
}
public String getMessageFromSender(String message){
if (message != null) {
receivedFromSender = message;
Log.i("debinf recfrag", "message from sender (function) is : " + receivedFromSender);
//Log.i("debinf recgfrag", "mContext in interface : " + mContext);
if (message != null) {
if (new File(rootPath + receivedFromSender, "client.db").isFile()) {
clientReading(message);
}
}
}
return null;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_receiver, container, false);
// If I use mContext instead of getContext(), I get rid of the context error showed below.
//mContext = getContext();
clientList = new ArrayList<>();
initializeRecyclerView();
//clientReading("-LWBPaM7RA9UOcUVty79");
return view;
}
private void clientReading(String pathToClientTable) {
if (new File(rootPath + pathToClientTable, "client.db").isFile()) {
Log.i("debinf recgfrag", "mContext in clientReading" + mContext);
ClientDatabaseHelper clientDatabaseHelper = new ClientDatabaseHelper(mContext,"client.db", rootPath+pathToClientTable+"/");
clientListTable = clientDatabaseHelper.getReadableDatabase();
clientRepository = new ClientRepository(clientListTable);
clientList = clientRepository.SearchAllClients();
Log.i("debinf recfrag", "clientList in clientReading is " + clientList.get(0).getName());
mClientListAdapter = new ReceiverAdapter(mContext,clientList);
mClientList.setAdapter(mClientListAdapter);
//mClientListAdapter.notifyDataSetChanged();
}
}
private void initializeRecyclerView() {
mClientList = (RecyclerView) view.findViewById(R.id.clientList);
mClientList.setNestedScrollingEnabled(false);
mClientList.setHasFixedSize(false);
mClientListLayoutManager = new LinearLayoutManager(mContext,LinearLayout.VERTICAL,false);
mClientList.setLayoutManager(mClientListLayoutManager);
mClientListAdapter = new ReceiverAdapter(mContext,clientList);
mClientList.setAdapter(mClientListAdapter);
}
}
This is the ReceiverAdapter
public class ReceiverAdapter extends RecyclerView.Adapter<ReceiverAdapter.ReceiverViewHolder> {
ArrayList<ClientObject> clientList;
Context mContext;
private ReceiverAdapter adapter;
public ReceiverAdapter(Context mContext, ArrayList<ClientObject> clientList) {
this.clientList = clientList;
this.mContext = mContext;
}
#NonNull
#Override
public ReceiverViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_callcenter_client, null, false);
RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
layoutView.setLayoutParams(lp);
ReceiverViewHolder rcv = new ReceiverViewHolder(layoutView);
return rcv;
}
#Override
public void onBindViewHolder(#NonNull ReceiverViewHolder holder, int position) {
holder.mName.setText(clientList.get(position).getName());
holder.mPhone.setText(clientList.get(position).getPhone());
}
#Override
public int getItemCount() {
return clientList.size();
}
public class ReceiverViewHolder extends RecyclerView.ViewHolder {
public TextView mName, mPhone;
//public LinearLayout mLayout;
public ReceiverViewHolder(#NonNull View itemView) {
super(itemView);
mName = (TextView) itemView.findViewById(R.id.client_name);
mPhone = (TextView) itemView.findViewById(R.id.client_phone);
//mLayout = (LinearLayout) itemView.findViewById(R.id.layoutItemClient);
}
}
}
EDIT
I changed the ReceiverFragment so that it could be more understandable.
That's the FATAL ERROR I get when I use the getContext(). I simply cannot make a connection with my SQLDatabase.
2019-01-31 15:41:45.118 22318-22318/com.example.aliton.passkeybetweenfrags E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.aliton.passkeybetweenfrags, PID: 22318
java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.File android.content.Context.getDatabasePath(java.lang.String)' on a null object reference
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:352)
at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:322)
at com.example.aliton.passkeybetweenfrags.ReceiverFragment.clientReading(ReceiverFragment.java:104)
at com.example.aliton.passkeybetweenfrags.ReceiverFragment.getMessageFromSender(ReceiverFragment.java:53)
at com.example.aliton.passkeybetweenfrags.MainActivity.getMessage(MainActivity.java:64)
at com.example.aliton.passkeybetweenfrags.SenderAdapter$1.onCheckedChanged(SenderAdapter.java:54)
at android.widget.CompoundButton.setChecked(CompoundButton.java:171)
at android.widget.CompoundButton.toggle(CompoundButton.java:127)
at android.widget.CompoundButton.performClick(CompoundButton.java:132)
at android.view.View.performClickInternal(View.java:6574)
at android.view.View.access$3100(View.java:778)
at android.view.View$PerformClick.run(View.java:25885)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Now, when I suppress getContext() and make it static in mContext. I can make a connection with SQLDatabase, but I get this FATAL error because the ReceiverAdapter:
2019-01-31 15:35:05.541 21936-21936/com.example.aliton.passkeybetweenfrags E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.aliton.passkeybetweenfrags, PID: 21936
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setAdapter(android.support.v7.widget.RecyclerView$Adapter)' on a null object reference
at com.example.aliton.passkeybetweenfrags.ReceiverFragment.clientReading(ReceiverFragment.java:110)
at com.example.aliton.passkeybetweenfrags.ReceiverFragment.getMessageFromSender(ReceiverFragment.java:53)
at com.example.aliton.passkeybetweenfrags.MainActivity.getMessage(MainActivity.java:64)
at com.example.aliton.passkeybetweenfrags.SenderAdapter$1.onCheckedChanged(SenderAdapter.java:54)
at android.widget.CompoundButton.setChecked(CompoundButton.java:171)
at android.widget.CompoundButton.toggle(CompoundButton.java:127)
at android.widget.CompoundButton.performClick(CompoundButton.java:132)
at android.view.View.performClickInternal(View.java:6574)
at android.view.View.access$3100(View.java:778)
at android.view.View$PerformClick.run(View.java:25885)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I can either get an error while reading the SQLDatabase (client.db) or while updating the ReceiverAdapter.
This is the link for the Main folder of the app:
https://1drv.ms/u/s!AjteqjTsJm9qgn6kODT9OJmMcY4e
This is the link to the SQLDatabase (group.db and client.db)
https://1drv.ms/u/s!AjteqjTsJm9qgn_L52cz3lDWOOWe

I finally found an answer.
The whole problem happened in the MainActivity. I was communicating from the MainActivity to the ReceiverFragment like this :
ReceiverFragment receiverFragment = new ReceiverFragment();
And sending the message like this:
#Override
public void getMessage(String message) {
receiverFragment.getMessageFromSender(message);
}
The message was been passed from MainActivity to ReceiverFragment normally, But I was getting a NullPointerException for the recyclerView of the ReceiverFragment.
The problem was solved by using the following way to deliver the message to the ReceiverFragment (answer found in this link https://www.journaldev.com/14207/android-passing-data-between-fragments):
#Override
public void getMessage(String message) {
String tag = "android:switcher:" + R.id.tabs_pager + ":" + 1;
ReceiverFragment rf = (ReceiverFragment) getSupportFragmentManager().findFragmentByTag(tag);
rf.getMessageFromSender(message);
}
The links for the code and the SQLDatabase (group.db and client.db) are still available for download.
For those who are starting in Android like me and interested in the code, please do not forget to change the delivering function in the MainActivity.
Thank you all and good luck!

Related

Why am i getting a nullpointerexception when I try to setAdapter?

I have a simple adapter that uses 2 String based array lists. For some reason I am getting a NullPointerException even though I am sure the information is being passed by.
My adapter:
public class MovieAdapter extends RecyclerView.Adapter<MovieAdapter.ViewHolder> {
private ArrayList<String> names = new ArrayList<>();
private ArrayList<String> details = new ArrayList<>();
private Context mContext;
public MovieAdapter(ArrayList<String> names, ArrayList<String> details, Context mContext) {
this.names = names;
this.details = details;
this.mContext = mContext;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.detail_view, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.name.setText(names.get(position));
holder.detail.setText(details.get(position));
}
#Override
public int getItemCount() {
return names.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
private TextView name;
private TextView detail;
private ConstraintLayout cl;
public ViewHolder(#NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.name);
detail = itemView.findViewById(R.id.detial);
cl = itemView.findViewById(R.id.layout);
}
}
}
My REST call and recylerView initialization activity(added the REST call in case the problem is lying there):
// ArrayList<String> namesArray = new ArrayList<>(Arrays.asList("Rated:", "Released:", "Runtime:", "Genre:", , "Writer:", "Actors:", "Plot:", "Language:", "Country:"));
ArrayList<String> namesArray = new ArrayList<>();
namesArray.add("Rated:");
namesArray.add("Released:");
namesArray.add("Runtime:");
namesArray.add("Genre:");
namesArray.add("Director:");
namesArray.add("Writer:");
namesArray.add("Actors:");
namesArray.add("Plot");
namesArray.add("Language:");
namesArray.add("Country");
trazi.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Call<Movie> call;
movieApi = ApiClient.getClient().create(MovieApi.class);
if (paramYear.getText().toString().matches("")) {
call = movieApi.getDetails(key, paramName.getText().toString(), null);
} else {
call = movieApi.getDetails(key, paramName.getText().toString(), Integer.parseInt(paramYear.getText().toString()));
}
call.enqueue(new Callback<Movie>() {
#Override
public void onResponse(Call<Movie> call, Response<Movie> response) {
Toast.makeText(getApplication().getApplicationContext(), " valja", Toast.LENGTH_LONG).show();
movie = response.body();
// ArrayList<String> details = new ArrayList<>(Arrays.asList(movie.getRated(), movie.getReleased(), movie.getRuntime(), movie.getGenre(), movie.getDirector(), movie.getWriter(), movie.getActors(), movie.getPlot(), movie.getLanguage(), movie.getCountry()));
ArrayList<String> details = new ArrayList<>();
details.add(movie.getRated());
details.add(movie.getReleased());
details.add(movie.getRuntime());
details.add(movie.getGenre());
details.add(movie.getDirector());
details.add(movie.getWriter());
details.add(movie.getActors());
details.add(movie.getPlot());
details.add(movie.getLanguage());
details.add(movie.getCountry());
Picasso.get().load(movie.getPoster()).fit().centerInside().into(image);
image.setVisibility(View.VISIBLE);
title.setText(movie.getTitle());
title.setVisibility(View.VISIBLE);
recyclerView = findViewById(R.id.layout);
movieAdapter = new MovieAdapter(namesArray, details, getApplication().getApplicationContext());
recyclerView.setAdapter(movieAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplication().getApplicationContext()));
}
So
Picasso.get().load(movie.getPoster()).fit().centerInside().into(image);
and
title.setText(movie.getTitle());
work perfectly so the information is passed to the adapter and I tried to initialize array lists on two different ways just in case. Still no success. Any ideas on where the problem is?
Edit:
My error log:
2020-05-24 17:20:22.600 27595-27595/com.example.cetvrtizadatak E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.cetvrtizadatak, PID: 27595
java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.recyclerview.widget.RecyclerView.setAdapter(androidx.recyclerview.widget.RecyclerView$Adapter)' on a null object reference
at com.example.cetvrtizadatak.MainActivity$1$1.onResponse(MainActivity.java:115)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.lambda$onResponse$0$DefaultCallAdapterFactory$ExecutorCallbackCall$1(DefaultCallAdapterFactory.java:81)
at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCall$1$3wC8FyV4pyjrzrYL5U0mlYiviZw.run(Unknown Source:6)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6702)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:911)
Your NullPointerException is happening when you try to access a member of you recyclerView object, meaning that its value is probably null.
Looking at your code I can presume that the id you're passing is not of yout recyclerView but for an layout object.
Double check if in your layout xml file the id given to the recyclerView is the one you're referencing on you call to findViewById.

Firebase data is not getting displayed and getting error [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 2 years ago.
When I searched anything it did nothing but when I press button my app get crash and getting error. I don't know know what is wrong.
Main Activity
public class CriminalRecords extends Fragment {
private static final String TAG = "CriminalRecords";
private EditText msearchfield;
private ImageButton msearchbtn;
private FloatingActionButton mFab;
private RecyclerView mResultList;
private DatabaseReference mCriminalDatabase;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.frag_criminal_records, container, false);
msearchfield=view.findViewById(R.id.SearchCriminal);
msearchbtn = view.findViewById(R.id.SearchButton);
mFab = view.findViewById(R.id.AddCriminals);
mResultList = view.findViewById(R.id.Criminal_result_list);
mResultList.setHasFixedSize(true);
mResultList.setLayoutManager(new LinearLayoutManager(getContext()));
mCriminalDatabase = FirebaseDatabase.getInstance().getReference("Criminals");
mFab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent =new Intent(getContext(), Add_Criminals.class);
startActivity(intent);
}
});
msearchbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String searchText = msearchfield.getText().toString();
firebaseSearch(searchText);
}
});
return view;
}
private void firebaseSearch(String searchText) {
Query firebaseSearchQuery = mCriminalDatabase.orderByChild("name").startAt(searchText).endAt(searchText + "\uf8ff");
Log.d(TAG, "firebaseSearch: searching");
FirebaseRecyclerOptions<Criminalupload>options=new FirebaseRecyclerOptions.Builder<Criminalupload>()
.setQuery(firebaseSearchQuery,Criminalupload.class)
.build();
FirebaseRecyclerAdapter<Criminalupload, CriminalViewHolder> firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Criminalupload, CriminalViewHolder>(options)
{
#Override
protected void onBindViewHolder(#NonNull CriminalViewHolder holder, int position, #NonNull Criminalupload model) {
Log.d(TAG, "onBindViewHolder: BindView Active");
holder.setDetails(getActivity().getApplicationContext(),model.getName(),model.getImageid(),model.getAddress1(),model.getAddress2(),model.getAddress3(),model.getMobnum());
Log.d(TAG, "onBindViewHolder: Bindview done");
}
#NonNull
#Override
public CriminalViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return null;
}
};
firebaseRecyclerAdapter.startListening();
Log.d(TAG, "firebaseSearch: setting adapter");
mResultList.setAdapter(firebaseRecyclerAdapter);
Log.d(TAG, "firebaseSearch: addapter set");
}
//View Holder Class
public static class CriminalViewHolder extends RecyclerView.ViewHolder{
View mView;
public CriminalViewHolder(View itemView) {
super(itemView);
mView = itemView;
}
public void setDetails(Context ctx,String CName, String Cimg, String Addres1, String Addres2, String Addres3, Long Mob){
Log.d(TAG, "setDetails: setting details");
TextView cname = (TextView)mView.findViewById(R.id.cProfileName);
TextView caddress1 = (TextView)mView.findViewById(R.id.CriminalAddress);
TextView caddress2 = (TextView)mView.findViewById(R.id.CriminalAddress2);
TextView caddress3 = (TextView)mView.findViewById(R.id.CriminalAddress3);
TextView cmobile = (TextView)mView.findViewById(R.id.CriminalMobile);
CircleImageView cprof = (CircleImageView)mView.findViewById(R.id.cProfileImg);
cname.setText(CName);
caddress1.setText(Addres1);
caddress2.setText(Addres2);
caddress3.setText(Addres3);
cmobile.setText(Math.toIntExact(Mob));
Glide.with(ctx).load(Cimg).into(cprof);
}
}
}
Error
2020-02-22 19:57:17.804 15653-15653/com.example.crimerecords D/AndroidRuntime: Shutting down VM
2020-02-22 19:57:17.805 15653-15653/com.example.crimerecords E/AndroidRuntime:
FATAL EXCEPTION: main
Process: com.example.crimerecords, PID: 15653
java.lang.NullPointerException: Attempt to read from field 'android.view.View androidx.recyclerview.widget.RecyclerView$ViewHolder.itemView' on a null object reference
at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:7079)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6235)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1627)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851)
at androidx.recyclerview.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1897)
at androidx.recyclerview.widget.RecyclerView$1.run(RecyclerView.java:414)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:949)
at android.view.Choreographer.doCallbacks(Choreographer.java:761)
at android.view.Choreographer.doFrame(Choreographer.java:693)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2020-02-22 19:57:17.820 15653-15653/com.example.crimerecords I/Process: Sending signal. PID: 15653 SIG: 9
Your onCreateViewHolder method returns null, while it should return a new view holder for the data from the database.
A typical implementation would look something like this:
public CriminalViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.criminal, parent, false);
return new CriminalViewHolder(view);
}
Where R.layout.criminal is the layout that you want to use to show a node from the database.
This is all quite well covered in the FirebaseUI documentation on using the FirebaseRecyclerAdapter, so I recommend spending some time reading that.

Getting a null object exception when using an interface

I have created a shopping cart via recyclerview. Each viewholder also has a + and - button to add or remove quantity. This functionality is done in the adapter and I have to notify the parent fragment of the updated total amount. This last bit is done via an interface. The problem is, I am getting the following error:
Process: com.ecomm.market, PID: 6630
java.lang.NullPointerException: Attempt to invoke interface method 'void com.ecomm.market.SelectionAdapter$OnUpdateCartListener.onUpdateCart(int)' on a null object reference
at com.ecomm.market.SelectionAdapter$ViewHolder$1.onClick(SelectionAdapter.java:103)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
The selected item and corresponding quantity are stored in a hashmap that I convert to an array to populate the recycler view cart. This is what the relevant part of my main fragment MenuFragment looks like:
// Using the adapter interface to add items to cart and adding up total amount
menuItemAdapter.setOnAddToCartListener(new MenuItemAdapter.OnAddToCartListener() {
#Override
public void onAddToCart(final HashMap selectionItemsHashMap) {
setupSelectionRecycler(menuView);
totalAmount = mapToArray(selectionItemsHashMap);
selectionAdapter = new SelectionAdapter(selectionItemArrayList, selectionItemsHashMap, totalAmount);
selectionRecycler.setAdapter(selectionAdapter);
cartItemsHashmap = selectionItemsHashMap;
selectionAdapter.setUpdateCartListener(new SelectionAdapter.OnUpdateCartListener() {
#Override
public void onUpdateCart(int updatedTotalAmount) {
String stringTotalAmount = Integer.toString(updatedTotalAmount);
Log.d(TAG, "received total:" +stringTotalAmount);
tvTotalAmount.setText("$"+ stringTotalAmount);
totalAmount = updatedTotalAmount;
}
});
}
});
}
And here is an excerpt from my adapter SelectionAdapter:
public class SelectionAdapter extends RecyclerView.Adapter<SelectionAdapter.ViewHolder> {
private static final String TAG = SelectionAdapter.class.getSimpleName();
private ArrayList<SelectionItem> selectionItemArrayList = new ArrayList<>();
public HashMap<String, Integer> selectionItemsHashMap = new HashMap<String, Integer>();
public int totalAmount;
private OnUpdateCartListener updateCartListener;
public interface OnUpdateCartListener {
void onUpdateCart(int totalAmount);
}
public void setUpdateCartListener(OnUpdateCartListener updateCartListener) {
this.updateCartListener = updateCartListener;
}
public SelectionAdapter(ArrayList<SelectionItem> selectionItemArrayList, HashMap<String, Integer> selectionItemsHashMap, int currentTotalAmount) {
this.selectionItemArrayList = selectionItemArrayList;
this.selectionItemsHashMap = selectionItemsHashMap;
this.totalAmount = currentTotalAmount;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.selection_card, viewGroup, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int position) {
viewHolder.tvSelectItem.setText(selectionItemArrayList.get(position).getSelectionName());
String quantity = Integer.toString(selectionItemArrayList.get(position).getSelectionQuantity());
viewHolder.tvDishQuantity.setText(quantity);
}
#Override
public int getItemCount() {
return selectionItemArrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tvSelectItem, tvDishQuantity;
ImageView addQuantity, subtractQuantity, deleteItem;
public ViewHolder(#NonNull View itemView) {
super(itemView);
tvSelectItem = itemView.findViewById(R.id.dish_selection);
tvDishQuantity = itemView.findViewById(R.id.dish_quantity);
addQuantity = itemView.findViewById(R.id.button_add);
subtractQuantity = itemView.findViewById(R.id.button_subtract);
deleteItem = itemView.findViewById(R.id.delete_item);
addQuantity.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Find the name of the menu item
int position = getAdapterPosition();
String itemName = selectionItemArrayList.get(position).getSelectionName();
// Increase quantity
int currentQuantity = selectionItemsHashMap.get(itemName);
currentQuantity += 1;
// Update the hashmap with the new quantity
selectionItemsHashMap.put(itemName,currentQuantity);
//Update total amount
for (Object name: selectionItemsHashMap.keySet()) {
String key = (String) name;
if (key.equals(selectionItemArrayList.get(position).getSelectionName())) {
int eachPrice = Integer.parseInt(selectionItemArrayList.get(position).getSelectionPrice());
totalAmount += eachPrice;
}
}
// Display the new quantity
String stringCurrentQuantity = Integer.toString(currentQuantity);
tvDishQuantity.setText(stringCurrentQuantity);
//updateCartListener.onUpdateCart(totalAmount);
}
});
}
EDIT
A couple of points:
- When the cart is initially filled, I use this same code and it works fine.
- The problem occurs once the user returns to the cart and I have to repopulate it from a bundle. Everything works fine, except when the user goes straight to the cart and attempts to alter the quantity from there.
Pass interface implementation into the constructor of Adapter as follows :
public SelectionAdapter(ArrayList<SelectionItem> selectionItemArrayList, HashMap<String, Integer> selectionItemsHashMap, int currentTotalAmount,UpdateCartListener updateCartListener ) {
this.selectionItemArrayList = selectionItemArrayList;
this.selectionItemsHashMap = selectionItemsHashMap;
this.totalAmount = currentTotalAmount;
this.updateCartListener = updateCartListener
}
This will provide an implementation of your interface on the initialization of your adapter so it will be not null when you are using it for update cart.
So you try to access the listener inside the ViewHolder which is probably the cause of the crash, what the standard way is setting the OnClickListener inside your adapter
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int position) {
viewHolder.tvSelectItem.setText(selectionItemArrayList.get(position).getSelectionName());
String quantity = Integer.toString(selectionItemArrayList.get(position).getSelectionQuantity());
viewHolder.tvDishQuantity.setText(quantity);
viewHolder.addQuantity.setOnClickListener(new View.OnClickListener() {
...
}
}
You need to instantiate your updateCartListener begfore you use it. Do updateCartListener = new WhatverClassThatImplementsYourInterafce() before you use it or make your method to override Default if you are using Java 8 using the new FunctionalInterface in java.util.Function.
I guess you forget assignment the updateCartListener in your adapter.
SelectionAdapter(selectionItemArrayList, selectionItemsHashMap, totalAmount);
cartItemsHashmap = selectionItemsHashMap;
selectionAdapter.setUpdateCartListener(new SelectionAdapter.OnUpdateCartListener() {
#Override
public void onUpdateCart(int updatedTotalAmount) {
String stringTotalAmount = Integer.toString(updatedTotalAmount);
Log.d(TAG, "received total:" +stringTotalAmount);
tvTotalAmount.setText("$"+ stringTotalAmount);
totalAmount = updatedTotalAmount;
}
});
selectionRecycler.setAdapter(selectionAdapter);

how to include different intent in recyclerview

I plan to include a CardView in my project. i have already included RecyclerView and card view in my project. the problem is, i want to call for different activity for each card. i have implement different intent for each card. but it require me to initialize the data. this is my original code:
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private Context context;
private String[] titles = {"Add new Research",
"View Your Research"};
private String[] details = {"Add your research files here",
"View all of your posted research"};
private int[] images = { R.drawable.add,
R.drawable.view};
class ViewHolder extends RecyclerView.ViewHolder{
public int currentItem;
public ImageView itemImage;
public TextView itemTitle;
public TextView itemDetail;
public ViewHolder(View itemView) {
super(itemView);
itemImage = (ImageView)itemView.findViewById(R.id.item_image);
itemTitle = (TextView)itemView.findViewById(R.id.item_title);
itemDetail =
(TextView)itemView.findViewById(R.id.item_detail);
itemView.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View v) {
int position = getAdapterPosition();
Intent intent = new Intent(context, Choose.class);
if(position==0){
intent = new Intent(context, AddFiles.class);
}else if(position==1){
intent = new Intent(context, ViewFiles.class);
}
context.startActivity(intent);
}
});
}
}
when i click on the card view, it stated that my program are not responding.
even if i initialize intent as
Intent intent = null;
if(position==0){
intent = new Intent(context, AddFiles.class);
}else if(position==1){
intent = new Intent(context, ViewFiles.class);
}
context.startActivity(intent);
there still an error, what should i do? or is there better way to do it.
this is my logcat error.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.user.mcormpelo, PID: 3645
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:128)
at android.content.Intent.<init>(Intent.java:4449)
at com.example.user.mcormpelo.RecyclerAdapter$ViewHolder$1.onClick(RecyclerAdapter.java:46)
at android.view.View.performClick(View.java:5198)
at android.view.View$PerformClick.run(View.java:21147)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
You did not initialize the context
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private Context context;
public RecyclerAdapter(Context context) {
this.context = context;
}
Pass the Activity reference from the caller activity.
sample usage
RecyclerAdapter rcAdapter = new RecyclerAdapter(MainActivity.this);

Add new items to a ListView from a database

Recently I learned how to get informations from a database with Volley library.So I know now how to receive data from a php script in an Activity.
My problem is to display the data on my Activity, I'll explain it :
I have a project that is to create the app of a website which have news articles.
So in my database I have a table called article which contain a lot of articles. Of course I don't want to load them all at the start of the activity, so I wrote a php script which send articles to the app 5 by 5. The script is Ok.
In my request class which does a volley StringRequest, I receive these articles like this : String titles[] = new String[numberOfArticlesIWantToLoad]and String texts[] = new String[numberOfArticlesIWantToLoad].
With a Callback I send them to my activity and I display them in a ListView whith an Adapter.
The adapter works well but I don't know how can I load more items from my database and display them below the articles previously loaded... when I do again the request in my database (which send to my activity the 5 next articles) and I call again the adapter, new articles are displayed but not the former...
I know that I'm not far from the answer I expect...
First of all, is my script good for what I need ?
Secondly, what do I have to change in my Adapter to load next articles below former articles ?
That would help me a lot, thanks by advance for the time you would take on my issue !
Here is my adapter :
public class MonAdapter extends ArrayAdapter<String>{
private final Context context;
private String[] values;
private String[] values2;
public MonAdapter(Context context, String[] values, String[] values2) {
super(context, -1, values);
this.context = context;
this.values = values;
this.values2 = values2;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.list_layout, parent, false);
TextView titre = (TextView) rowView.findViewById(R.id.titre);
TextView article = (TextView) rowView.findViewById(R.id.article);
titre.setText(values[position]);
article.setText(values2[position]);
return rowView;
}
public void addItems(String[] titres, String[] texts){
String[] listTitres = new String[this.values.length + titres.length];
String[] listTexts = new String[this.values2.length + texts.length];
for(int i=0;i<this.values.length;i++){
listTitres[i] = this.values[i];
listTexts[i] = this.values2[i];
}
for(int i=0;i<titres.length;i++){
listTitres[this.values.length+i] = titres[i];
listTexts[this.values.length+i] = texts[i];
}
this.values = listTitres;
this.values2 = listTexts;
}
}
And here is my activity, from where I call the StringRequest (in MyRequest class) and the Adapter :
I tried to do my best to remove irrevelant code, I hope it's not too long
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
footerLayout = (RelativeLayout)getLayoutInflater().inflate(R.layout.footer_layout, null);
pb_charger = (ProgressBar)footerLayout.findViewById(R.id.pb_charger);
text = (TextView)findViewById(R.id.text);
pb_loader = (ProgressBar)findViewById(R.id.pb_loader);
list = (ListView)findViewById(R.id.list);
btn_charger = (Button)footerLayout.findViewById(R.id.btn_charger);
queue = VolleySingleton.getInstance(this).getRequestQueue();
request = new MyRequest(this, queue);
request.getArticles(nombreCharger, NOMBRE_ARTICLE_CHARGER, new MyRequest.GetArticlesCallback() {
#Override
public void onSuccess(String[] listeTitres, String[] listeArticles, boolean fin) {
*Some irrelevant code*
final MonAdapter adapterTitres = new MonAdapter(getApplicationContext(), listeTitres, listeArticles);
list.setAdapter(adapterTitres);
adapterTitres.notifyDataSetChanged();
list.addFooterView(footerLayout);
// list.removeFooterView(footerLayout);
}
nombreCharger++;
}
#Override
public void onError(String error, String id) {
}
});
btn_charger.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
btn_charger.setVisibility(View.INVISIBLE);
pb_charger.setVisibility(View.VISIBLE);
list.removeFooterView(footerLayout);
request.getArticles(nombreCharger, NOMBRE_ARTICLE_CHARGER, new MyRequest.GetArticlesCallback() {
#Override
public void onSuccess(String[] listeTitres, String[] listeArticles, boolean fin) {
*Some irrelevant code*
MonAdapter a = (MonAdapter) list.getAdapter();
a.addItems(listeTitres, listeArticles);
list.addFooterView(footerLayout);
list.setAdapter(a);
a.notifyDataSetChanged();
}
nombreCharger++;
}
#Override
public void onError(String error, String id) {
}
});
}
});
}
EDIT :
Here is the error since changes :
04-12 22:47:34.640 12584-12584/com.example.thib.databaseaffichage E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.thib.databaseaffichage, PID: 12584
java.lang.ClassCastException: android.widget.HeaderViewListAdapter cannot be cast to com.example.thib.databaseaffichage.MonAdapter
at com.example.thib.databaseaffichage.MainActivity$2$1.onSuccess(MainActivity.java:142)
at com.example.thib.databaseaffichage.myrequest.MyRequest$1.onResponse(MyRequest.java:63)
at com.example.thib.databaseaffichage.myrequest.MyRequest$1.onResponse(MyRequest.java:39)
at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:67)
at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:30)
at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:99)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5292)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
at dalvik.system.NativeStart.main(Native Method)
where is the HeaderViewListAdapter in your project?
java.lang.ClassCastException: android.widget.HeaderViewListAdapter cannot be cast to com.example.thib.databaseaffichage.MonAdapter

Categories

Resources