Cannot insert value in Room Database Android - java

I am trying to insert info about movie but I am getting this error:
java.lang.NullPointerException: Attempt to invoke virtual method 'void kawi15.myapplication.database.DatabaseViewModel.addWatchlistMovie(info.movito.themoviedbapi.model.MovieDb)' on a null object reference
I am sure that Movie is not null because I have Toast which showing me info about this movie.
I find that I need initializate DatabaseViewModel in my OnCreate():
databaseViewModel = new ViewModelProvider(this).get(DatabaseViewModel.class);
but I tried this in OnCreate and OnCreateView and in both its error with 'this':
new ViewModelProvider(this)
I try to put there getContext() or some other stuff but nothing worked here.
This is my Entity class:
#Entity
public class Watchlist {
#PrimaryKey
#ColumnInfo(name = "id")
private int movieId;
#ColumnInfo(name = "movie_title")
private String movieTitle;
#ColumnInfo(name = "poster_path")
private String posterPath;
#ColumnInfo(name = "overview")
private String overview;
#ColumnInfo(name = "release_date")
private String releaseDate;
and getters and setters for all
My Dao class:
#Dao
public interface WatchlistDao {
#Query("SELECT * FROM watchlist ORDER BY movie_title ASC")
List<Watchlist> getAll();
#Insert
void addMovie(Watchlist watchlistMovie);
}
ViewModel class:
public class DatabaseViewModel extends AndroidViewModel {
private AppDatabase db;
public DatabaseViewModel(#NonNull Application application) {
super(application);
db = AppDatabase.getDatabase(application);
}
public void addWatchlistMovie(MovieDb movieDb){
Watchlist addedMovie = new Watchlist();
addedMovie.setMovieId(movieDb.getId());
addedMovie.setMovieTitle(movieDb.getOriginalTitle());
addedMovie.setOverview(movieDb.getOverview());
addedMovie.setPosterPath(movieDb.getPosterPath());
addedMovie.setReleaseDate(movieDb.getReleaseDate());
db.watchlistDao().addMovie(addedMovie);
}
My Fragment class where I am clicking on Movie from list that I want to insert to database:
public class FragmentOne extends Fragment /*implements CustomAdapter.ListItemClickListener*/{
private static RecyclerView.Adapter adapter;
private RecyclerView.LayoutManager layoutManager;
private DatabaseViewModel databaseViewModel;
private static RecyclerView recyclerView;
private List<MovieDb> data;
//private CustomAdapter.ListItemClickListener mOnClickListener;
public static FragmentOne newInstance() {
FragmentOne fragment = new FragmentOne();
return fragment;
}
/*#Override
public void onListItemClick(int position) {
Toast.makeText(getContext(), data.get(position).getOriginalTitle(), LENGTH_SHORT).show();
}*/
public class MovieTask extends AsyncTask<Void, Void, List<MovieDb>> {
#Override
protected List<MovieDb> doInBackground(Void... voids) {
MovieResultsPage movies = new TmdbApi("f753872c7aa5c000e0f46a4ea6fc49b2").getMovies().getUpcoming("en-US", 1, "US");
List<MovieDb> listMovies = movies.getResults();
return listMovies;
}
#Override
protected void onPostExecute(List<MovieDb> movieDb) {
data = movieDb;
adapter = new CustomAdapter(data);
((CustomAdapter) adapter).setOnMovieDbClicked(movieDb2 -> {
Toast.makeText(getActivity(), movieDb2.getReleaseDate(), LENGTH_SHORT).show();
databaseViewModel.addWatchlistMovie(movieDb2);
});
recyclerView.setAdapter(adapter);
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View returnView = inflater.inflate(R.layout.fragment_one, container, false);
recyclerView = (RecyclerView) returnView.findViewById(R.id.my_recycler_view);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(getContext()); // ???
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
MovieTask mt = new MovieTask();
mt.execute();
return returnView;
}
}
and my adapter class, maybe not neccessary:
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder>{
private List<MovieDb> dataSet;
private OnMovieDbClicked onMovieDbClicked;
public void setOnMovieDbClicked(OnMovieDbClicked onMovieDbClicked) {
this.onMovieDbClicked = onMovieDbClicked;
}
//final private ListItemClickListener mOnClickListener;
public class MyViewHolder extends RecyclerView.ViewHolder /*implements View.OnClickListener*/{
TextView textViewName;
TextView textViewVersion;
ImageView imageViewIcon;
//private ListItemClickListener mOnClickListener;
public MyViewHolder(View itemView) {
super(itemView);
this.textViewName = (TextView) itemView.findViewById(R.id.text1);
this.textViewVersion = (TextView) itemView.findViewById(R.id.text2);
this.imageViewIcon = (ImageView) itemView.findViewById(R.id.imageView);
itemView.setOnClickListener(view -> {
int pos = getAdapterPosition();
if (onMovieDbClicked != null && pos != RecyclerView.NO_POSITION) {
MovieDb movieDb = dataSet.get(pos);
onMovieDbClicked.movieDbClicked(movieDb);
}
});
//itemView.setOnClickListener(this);
//itemView.setOnClickListener(CustomAdapter.myOnClickListener);
}
/*#Override
public void onClick(View v) {
int position = getAdapterPosition();
mOnClickListener.onListItemClick(position);
}*/
}
public CustomAdapter(List<MovieDb> data /*ListItemClickListener mOnClickListener*/) {
this.dataSet = data;
//this.mOnClickListener = mOnClickListener;
}
public interface OnMovieDbClicked {
void movieDbClicked(MovieDb movieDb);
}
/*public interface ListItemClickListener{
void onListItemClick(int position);
}*/
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.cards_layout, parent, false);
//view.setOnClickListener(FragmentOne.myOnClickListener);
MyViewHolder myViewHolder = new MyViewHolder(view);
return myViewHolder;
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int listPosition) {
TextView textViewName = holder.textViewName;
TextView textViewVersion = holder.textViewVersion;
ImageView imageView = holder.imageViewIcon;
Glide.with(imageView).load("https://image.tmdb.org/t/p/w500" + dataSet.get(listPosition).getPosterPath()).into(imageView);
textViewName.setText(dataSet.get(listPosition).getOriginalTitle());
textViewVersion.setText(dataSet.get(listPosition).getReleaseDate());
}
#Override
public int getItemCount() {
if(dataSet == null){
return 0;
}
return dataSet.size();
}
}

You have not initialized your databaseViewModel anywhere so the NPE is expected. Make sure to fill the field before accessing it in MovieTask

Related

Show data in Nested Recyclerview in android

As I fetched and show the dates (see image) as the title of the main recyclerview. I want to show the available slots data instead of the 0 1 2 etc elements. The code is attached below
Url for json data
https://run.mocky.io/v3/c9bd7858-0e41-422f-b1d2-cd490c08583b
AppointmentTimeActivity.java
public class AppointmentTimeActivity extends AppCompatActivity {
SharedPrefManager sharedPrefManager;
Button appointmentTimeButton;
private TextView doctorFullName;
ConstraintLayout constraintLayout;
public static List<List<String>> availableSlots;
RecyclerView rvGroup;
public static ArrayList<String> arrayListGroup;
LinearLayoutManager layoutManagerGroup;
GroupAdapter groupAdapter;
private DoctorScheduleResponse timings;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.select_appointment_time);
getSupportActionBar().setTitle("Appointment time");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
sharedPrefManager = new SharedPrefManager(this);
constraintLayout = findViewById(R.id.constraintLayout);
appointmentTimeButton = findViewById(R.id.book_video_call_appointment_btn);
doctorFullName = findViewById(R.id.doctor_full_name);
rvGroup = findViewById(R.id.rv_group);
String docName = getIntent().getStringExtra("doctorFullName");
doctorFullName.setText(docName);
arrayListGroup = new ArrayList<>();
fetchAndShowAppointmentsTime();
}
private void fetchAndShowAppointmentsTime() {
String id = String.valueOf(SpecialityActivity.doctorID);
Call<DoctorScheduleResponse> call = RetrofitClient.getInstance().getMyInterface().getAppointmentTime("Bearer " + sharedPrefManager.getAccessToken(), id);
call.enqueue(new Callback<DoctorScheduleResponse>() {
#Override
public void onResponse(#NotNull Call<DoctorScheduleResponse> call, #NotNull Response<DoctorScheduleResponse> response) {
arrayListGroup = new ArrayList<>();
if (response.isSuccessful()) {
assert response.body() != null;
for (List<Slot> slots : response.body().getSlot()) {
for (Slot slot : slots) {
arrayListGroup.add(slot.getScheduleDate());
}
}
groupAdapter = new GroupAdapter(AppointmentTimeActivity.this, response.body().getSlot());
layoutManagerGroup = new LinearLayoutManager(getApplicationContext());
rvGroup.setLayoutManager(layoutManagerGroup);
rvGroup.setAdapter(groupAdapter);
}
}
#Override
public void onFailure(#NotNull Call<DoctorScheduleResponse> call, #NotNull Throwable t) {
Toast.makeText(getBaseContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
DoctorScheduleResponse.java
public class DoctorScheduleResponse {
#SerializedName("slot")
#Expose
private List<List<Slot>> slot = null;
public List<List<Slot>> getSlot() {
return slot;
}
public void setSlot(List<List<Slot>> slot) {
this.slot = slot;
}
}
GroupAdater.java
public class GroupAdapter extends RecyclerView.Adapter<GroupAdapter.ViewHolder> {
private Activity activity;
ArrayList<String> arrayListGroup, arrayListMember;
LinearLayoutManager linearLayoutManager;
SharedPrefManager sharedPrefManager;
List<List<Slot>> slotsList;
public GroupAdapter(Activity activity, ArrayList<String> arrayListGroup) {
this.activity = activity;
this.arrayListGroup = arrayListGroup;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.custom_slot_layout, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.dummyTV.setText(arrayListGroup.get(position));
arrayListMember = new ArrayList<>();
sharedPrefManager = new SharedPrefManager(activity);
for (int i = 0; i < 5; i++) {
arrayListMember.add(String.valueOf(i));
}
CustomAdapter customAdapter = new CustomAdapter(arrayListMember);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(activity);
holder.rvMember.setLayoutManager(linearLayoutManager);
holder.rvMember.setAdapter(customAdapter);
}
#Override
public int getItemCount() {
return arrayListGroup.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView dummyTV;
RecyclerView rvMember;
public ViewHolder(#NonNull View itemView) {
super(itemView);
dummyTV = itemView.findViewById(R.id.dummyTextView);
rvMember = itemView.findViewById(R.id.rv_member);
}
}
}
CustomAdapter.java
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.SlotsViewHolder> {
ArrayList<String> slots;
public CustomAdapter(ArrayList<String> slots) {
this.slots = slots;
}
#NonNull
#Override
public SlotsViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.available_slots_list, parent, false);
return new CustomAdapter.SlotsViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull SlotsViewHolder holder, int position) {
holder.tvSlots.setText(slots.get(position));
}
#Override
public int getItemCount() {
return slots.size();
}
public class SlotsViewHolder extends RecyclerView.ViewHolder {
TextView tvSlots;
public SlotsViewHolder(#NonNull View itemView) {
super(itemView);
tvSlots = itemView.findViewById(R.id.tv_slots);
}
}
}
Nested recycler view will be more complex in terms of memory. So you can achieve same UI with different approach.
You should try with single recycler view with dynamic layout binding.
Example: For single item of recycler view, there will be a header(for date) and a viewgroup(may be linear layout) then bind any no. of child views inside that linear layout.
The problem is in GroupAdater.java. Inside onBindViewHolder method you are adding the value of loop variable to your list that you pass to your nested recycler view adaptor.
for (int i = 0; i < 5; i++) {
arrayListMember.add(String.valueOf(i));
}
You have to add the correct date from arrayListGroup object.

How can I get a variable from RecyclerView Adapter passed to MainActivity?

I was just playing around with some code, learning new things, when I ran into this problem... I'm trying to pass a variable from my RecylcerViewAdapter to a method in MainActivity, but I just can't seem to accomplish it.
I tried a lot of different thing with interfaces and casting, but nothing did the trick. Since I'm fairly new to all of this, maybe I'm making a trivial mistake somewhere?
My Interface:
public interface AdapterCallback {
void onMethodCallback(int id);
}
This is my adapter class:
public class PostAdapter extends RecyclerView.Adapter<PostAdapter.ViewHolder> {
private List<Post> postList;
private Context context;
private AdapterCallback listener;
public PostAdapter() {
}
public PostAdapter(List<Post> postList, Context context) {
this.postList = postList;
this.context = context;
}
public void setListener(AdapterCallback listener) {
this.listener = listener;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recycler_layout, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder viewHolder, final int position) {
viewHolder.tvTitle.setText(postList.get(position).getTitle());
viewHolder.tvBody.setText(new StringBuilder(postList.get(position).getBody().substring(0, 20)).append("..."));
viewHolder.tvId.setText(String.valueOf(postList.get(position).getUserId()));
viewHolder.parentLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int id = postList.get(position).getId();
if (listener != null) {
listener.onMethodCallback(id);
}
}
});
}
#Override
public int getItemCount() {
return postList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tvTitle;
TextView tvBody;
TextView tvId;
LinearLayout parentLayout;
public ViewHolder(View itemView) {
super(itemView);
tvTitle = itemView.findViewById(R.id.tvTitle);
tvBody = itemView.findViewById(R.id.tvBody);
tvId = itemView.findViewById(R.id.tvId);
parentLayout = itemView.findViewById(R.id.parentLayout);
}
}
}
And my MainActivity:
public class MainActivity extends AppCompatActivity {
public static final String TAG = "MainActivityLog";
private CompositeDisposable disposable = new CompositeDisposable();
#BindView(R.id.rvPosts)
RecyclerView rvPosts;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
rvPosts.setHasFixedSize(true);
rvPosts.setLayoutManager(new LinearLayoutManager(this));
populateList();
logItems();
}
private void populateList() {
MainViewModel viewModel = ViewModelProviders.of(MainActivity.this).get(MainViewModel.class);
viewModel.makeQuery().observe(MainActivity.this, new Observer<List<Post>>() {
#Override
public void onChanged(#Nullable List<Post> posts) {
PostAdapter adapter = new PostAdapter(posts, getApplicationContext());
rvPosts.setAdapter(adapter);
}
});
}
public void logItems() {
PostAdapter adapter = new PostAdapter();
adapter.setListener(new AdapterCallback() {
#Override
public void onMethodCallback(int id) {
MainViewModel viewModel = ViewModelProviders.of(MainActivity.this).get(MainViewModel.class);
viewModel.makeSingleQuery(id).observe(MainActivity.this, new Observer<Post>() {
#Override
public void onChanged(#Nullable final Post post) {
Log.d(TAG, "onChanged: data response");
Log.d(TAG, "onChanged: " + post);
}
});
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
disposable.clear();
}
}
The populateList() method works just fine, but the logItems() method is the problem.
So when i click on a view in RecyclerView I expect the log to output the title, description and ID of the post that was clicked. nut nothing happens...
So, any help would be appreciated.
Make adapter global variable i.e. a field. Use the same object to set every properties.
private PostAdapter adapter;
Replace your logItems method with this:
public void logItems() {
adapter.setListener(new AdapterCallback() {
#Override
public void onMethodCallback(int id) {
MainViewModel viewModel = ViewModelProviders.of(MainActivity.this).get(MainViewModel.class);
viewModel.makeSingleQuery(id).observe(MainActivity.this, new Observer<Post>() {
#Override
public void onChanged(#Nullable final Post post) {
Log.d(TAG, "onChanged: data response");
Log.d(TAG, "onChanged: " + post);
}
});
}
});
}
And populateList with this:
private void populateList() {
MainViewModel viewModel = ViewModelProviders.of(MainActivity.this).get(MainViewModel.class);
viewModel.makeQuery().observe(MainActivity.this, new Observer<List<Post>>() {
#Override
public void onChanged(#Nullable List<Post> posts) {
adapter = new PostAdapter(posts, getApplicationContext());
rvPosts.setAdapter(adapter);
logItems();
}
});
}
And don't call logItems() from onCreate
This is how I implement with my ListAdapters:
public class FeedbackListAdapter extends RecyclerView.Adapter<FeedbackListAdapter.ViewHolder> {
private final ArrayList<Feedback> feedbacks;
private View.OnClickListener onItemClickListener;
private View.OnLongClickListener onItemLongClickListener;
private final Context context;
public FeedbackListAdapter(ArrayList<Feedback> feedbacks, Context context) {
this.feedbacks = feedbacks;
this.context = context;
}
public void setItemClickListener(View.OnClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public void setOnItemLongClickListener(View.OnLongClickListener onItemLongClickListener){
this.onItemLongClickListener = onItemLongClickListener;
}
public class ViewHolder extends RecyclerView.ViewHolder{
final TextView feedback, created, updated;
final LinearLayout mainLayout;
ViewHolder(View iv) {
super(iv);
/*
* Associate layout elements to Java declarations
* */
mainLayout = iv.findViewById(R.id.main_layout);
feedback = iv.findViewById(R.id.feedback);
created = iv.findViewById(R.id.created_string);
updated = iv.findViewById(R.id.updated_string);
}
}
#Override
public int getItemCount() {
return feedbacks.size();
}
#Override
#NonNull
public FeedbackListAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_feedback_table_row, parent, false);
return new FeedbackListAdapter.ViewHolder(view);
}
#Override
public void onBindViewHolder(final #NonNull FeedbackListAdapter.ViewHolder holder, final int position) {
/*
* Bind data to layout
* */
try{
Feedback feedback = feedbacks.get(position);
holder.feedback.setText(feedback.getContent());
holder.created.setText(feedback.getCreated());
holder.updated.setText(feedback.getUpdated());
holder.mainLayout.setOnClickListener(this.onItemClickListener);
holder.mainLayout.setOnLongClickListener(this.onItemLongClickListener);
holder.mainLayout.setTag(feedback.getDbID());
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);
holder.mainLayout.setBackgroundResource(outValue.resourceId);
}catch(IndexOutOfBoundsException e){
e.printStackTrace();
}
}
}
In onPopulateList you create an adaptor:
PostAdapter adapter = new PostAdapter(posts, getApplicationContext());
rvPosts.setAdapter(adapter);
However in public void logItems() { you used a different adapter
PostAdapter adapter = new PostAdapter();
adapter.setListener(new AdapterCallback() {
#Override
public void onMethodCallback(int id) {
...
}
});
Therefore the list is being populated with 1 adapter, but you are setting the listener on an unused second adapter.
The fix is to use the same adapter for both. If you make the adapater a field, and don't create a new one inside of logItems, but just set your listener it should work.
i.e.
// as a field in your class
private PostAdapter adapter;
then
// in `populateList()`
adapter = new PostAdapter(posts, getApplicationContext());
rvPosts.setAdapter(adapter);
and
// in `logItems()`
adapter.setListener(new AdapterCallback() {
#Override
public void onMethodCallback(int id) {
...
}
});
In Adapter
public class CustomerListAdapter extends RecyclerView.Adapter<CustomerListAdapter.OrderItemViewHolder> {
private Context mCtx;
ProgressDialog progressDialog;
//we are storing all the products in a list
private List<CustomerModel> customeritemList;
public CustomerListAdapter(Context mCtx, List<CustomerModel> orderitemList) {
this.mCtx = mCtx;
this.customeritemList = orderitemList;
progressDialog = new ProgressDialog(mCtx);
}
#NonNull
#Override
public OrderItemViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mCtx);
View view = inflater.inflate(R.layout.activity_customer_list, null);
return new OrderItemViewHolder(view, mCtx, customeritemList);
}
#Override
public void onBindViewHolder(#NonNull OrderItemViewHolder holder, int position) {
CustomerModel customer = customeritemList.get(position);
try {
//holder.textViewPINo.setText("PINo \n"+Integer.toString( order.getPINo()));
holder.c_name.setText(customer.getCustomerName());
holder.c_address.setText(customer.getAddress());
holder.c_contact.setText(customer.getMobile());
holder.i_name.setText(customer.getInteriorName());
holder.i_contact.setText(customer.getInteriorMobile());
holder.i_address.setText(customer.getAddress());
} catch (Exception E) {
E.printStackTrace();
}
}
#Override
public int getItemCount() {
return customeritemList.size();
}
class OrderItemViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener, View.OnClickListener {
AlertDialog.Builder alert;
private Context mCtx;
TextView c_name, c_contact, c_address, i_name, i_contact, i_address;
TextView OrderItemID, MaterialType, Price2, Qty, AQty;
//we are storing all the products in a list
private List<CustomerModel> orderitemList;
public OrderItemViewHolder(View itemView, Context mCtx, List<CustomerModel> orderitemList) {
super(itemView);
this.mCtx = mCtx;
this.orderitemList = orderitemList;
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
// CatelogOrderDetailModel catelogOrderDetailModel = new CatelogOrderDetailModel();
c_name = itemView.findViewById(R.id.customerName);
c_contact = itemView.findViewById(R.id.contact);
c_address = itemView.findViewById(R.id.address);
i_name = itemView.findViewById(R.id.interiorName);
i_address = itemView.findViewById(R.id.interiorAddress);
i_contact = itemView.findViewById(R.id.interiorContact);
}
#Override
public void onClick(View v) {
int position = getAdapterPosition();
CustomerModel orderitem = this.orderitemList.get(position);
}
#Override
public boolean onLongClick(View v) {
int position = getAdapterPosition();
CustomerModel orderitem = this.orderitemList.get(position);
if (v.getId() == itemView.getId()) {
// showUpdateDeleteDialog(order);
try {
} catch (Exception E) {
E.printStackTrace();
}
Toast.makeText(mCtx, "lc: ", Toast.LENGTH_SHORT).show();
}
return true;
}
}
}

Recyclerview not showing data serializable

I'm trying to list data from serializable object but it doesn't work show nothing.
I am listing information from a recyclerview with serialized object. When passing to another activity, the recyclerview does not show any data.
Sorry about my english.
MainActivity
private void onOrderProduct() {
bOrder.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Cart cart = new Cart();
cart.setComida(tvTitle.getText().toString());
cart.setPreco(tvTotal.getText().toString());
cart.setQuantidade(tvQtd.getText().toString());
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("cart", cart);
startActivity(intent);
}
});
}
SecondActivity
public class SecondActivity extends AppCompatActivity {
RecyclerView rvCart;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.secondactivity);
rvCart = (RecyclerView) findViewById(R.id.tela5recycler_view);
rvCart.setHasFixedSize(true);
LinearLayoutManager manager = new LinearLayoutManager(this);
rvCart.setLayoutManager(manager);
if (getIntent().getSerializableExtra("cart") != null) {
Intent intent = getIntent();
Cart cart = (Cart) intent.getSerializableExtra("cart");
ArrayList<Cart> eList = new ArrayList<>() cart;
Adapter adapter =new Adapter(getApplicationContext(), eList );
rvCart.setAdapter(adapter);
}
}
}
Adapter
public class Adapter extends RecyclerView.Adapter<Adapter.ItemViewHolder> {
private Context context;
private ArrayList<Cart> itemList;
public Adapter(Context context, ArrayList<Cart> itemList){
this.context = context;
this.itemList = itemList;
}
#Override
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.from(parent.getContext())
.inflate(R.layout.adapter_card, parent, false);
ItemViewHolder itemViewHolder = new ItemViewHolder(view);
return itemViewHolder;
}
#Override
public void onBindViewHolder(ItemViewHolder holder, int position) {
Cart item = itemList.get(position);
holder.tvQtdcard.setText(item.getQuantidade());
holder.tvComidacard.setText(item.getComida());
holder.tvPrecocard.setText(item.getPreco());
}
#Override
public int getItemCount() {
if(itemList != null){
return itemList.size();
}
return 0;
}
public static class ItemViewHolder extends RecyclerView.ViewHolder{
public CardView cvItem;
public TextView tvQtdcard, tvComidacard, tvPrecocard;
public ItemViewHolder(View itemView) {
super(itemView);
cvItem = (CardView)itemView.findViewById(R.id.tela1_1_1_1_1card);
tvQtdcard = (TextView)itemView.findViewById(R.id.tela5qtdcard);
tvComidacard = (TextView)itemView.findViewById(R.id.tela5comidacard);
tvPrecocard = (TextView)itemView.findViewById(R.id.tela5precocard);
}
}
}
Cart.class Serializable
import java.io.Serializable;
public class Cart implements Serializable{
private static final long serialVersionUID = 42L;
private String comida;
private String quantidade;
private String preco;
public String getComida() {
return comida;
}
public void setComida(String comida) {
this.comida = comida;
}
public String getQuantidade() {
return quantidade;
}
public void setQuantidade(String quantidade) {
this.quantidade = quantidade;
}
public String getPreco() {
return preco;
}
public void setPreco(String preco) {
this.preco = preco;
}
public String toString(){
return comida;
}
}
You are missing adapter.notifyDataSetChanged() after and you are passing empty arraylist eList
ArrayList<Cart> eList = new ArrayList<>();
eList.add(cart);
Adapter adapter =new Adapter(getApplicationContext(), eList );
rvCart.setAdapter(adapter);
To pass the serialized object
Solution 1 (Hackytack solution)
public class CardListHolder implements Serializable{
private ListcardList=new ArrayList<>();
public List<Card>getCardList(){
return cardList;
}
public void setCardList(List<Card> cardList){
this.cardList=cardList;
}
}
Use this holder object to pass the list of card
Solution 2
Implement Parcelable for Card object, it can pass list of card but it is little bit complex to understand. Try www.parcelabler.com to auto generate the Parceable class for Card.

Stackoverflow error

I'm using Retrofit, picasso and recyclerview.But the below error is coming.
Process: com.example.user.recyclerview, PID: 4871
java.lang.StackOverflowError
MainActivity.class
public class MainActivity extends AppCompatActivity
{
private RecyclerView recyclerView;
private DataAdapter dataAdapter;
private List<ModelData> modelDataList;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.card_recycle_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
getPopularMovies();
}
private void getPopularMovies()
{
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://pratikbutani.x10.mx")
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitInterface service = retrofit.create(RetrofitInterface.class);
Call<ModelDataList> call =service.getJSON();
call.enqueue(new Callback<ModelDataList>()
{
#Override
public void onResponse(Call<ModelDataList> call, Response<ModelDataList> response)
{
ModelDataList modelDataList = response.body();
dataAdapter = new DataAdapter(modelDataList.getResults());
recyclerView.setAdapter(dataAdapter);
}
#Override
public void onFailure(Call<ModelDataList> call, Throwable t)
{
Log.d("Main","failure");
}
});
}
}
ModelDataList.java
public class ModelDataList
{
private List<ModelData> results;
public List<ModelData> getResults()
{
return results;
}
}
DataAdapter.java
public class DataAdapter extends RecyclerView.Adapter<DataAdapter.ViewHolder>
{
private List<ModelData> modelDataList;
private LayoutInflater layoutInflater;
private Context context;
public DataAdapter(List<ModelData> modelDataList)
{
this.context = new AppCompatActivity();
this.modelDataList = modelDataList;
this.layoutInflater = LayoutInflater.from(context);
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view = layoutInflater.inflate(R.layout.card_view, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position)
{
ModelData modelData = modelDataList.get(position);
holder.textView.setText(modelData.getName());
Picasso.with(context).load(String.valueOf(modelData.getDisplay_pic())).placeholder(R.color.colorAccent).into(holder.imgview);
}
#Override
public int getItemCount()
{
return modelDataList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder
{
private ImageView imgview;
private TextView textView;
public ViewHolder(View itemView)
{
super(itemView);
imgview = (ImageView) itemView.findViewById(R.id.tv_image);
textView = (TextView) itemView.findViewById(R.id.tv_name);
}
}
}
Not sure about your StackOverflowError issue. One issue is how you get...context. You can get context from view instead of "this.context = new AppCompatActivity();"
ex:
LayoutInflater.from(parent.getContext()).inflate(R.layout.card_view, parent, false);
Picasso.with(holder.imgview.getContext()).load(String.valueOf(modelData.getDisplay_pic())).placeholder(R.color.colorAccent).into(holder.imgview);

RecyclerView isn't attached to Adapter

I have this strage error. I'm downloading data from API and I want to print it in RecyclerView nested in Fragment called ListFragment. This fragment is one of three which I use in ViewPager. ViewPager works fine. For now, I want to display only two textViews. Layout for them has name single_data_layout. List<Feature> features is my DataResponse. Project builds normaly without issues and I receive in Log that "Data is successfully downloaded". When I run app in DebugMode I get message that my RecyclerView isn't attached to adapter. Any ideas?
ApiClient:
public interface ApiClient {
#GET("/query?format=geojson&starttime&minsig=700")
Call<DataResponse> getData();
}
ApiClientFactory:
public class ApiClientFactory {
public static final String baseURL = "https://earthquake.usgs.gov/fdsnws/event/1/";
public ApiClient createApiClient(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseURL)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit.create(ApiClient.class);
}
}
DataAdapter:
public class DataAdapter extends RecyclerView.Adapter<DataAdapter.DataViewHolder> {
private List<Feature> features;
private ListFragment listFragment;
private Context context;
private LayoutInflater inflater;
public DataAdapter(List<Feature> features) {
this.features = features;
}
#Override
public DataViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
inflater = LayoutInflater.from(context);
View contractView = inflater.inflate(R.layout.single_data_layout, parent, false);
return new DataViewHolder(contractView);
}
#Override
public void onBindViewHolder(DataViewHolder holder, int position) {
holder.place.setText(features.get(position).getProperties().getPlace());
holder.alert.setText(features.get(position).getProperties().getAlert());
}
#Override
public int getItemCount() {
return features.size();
}
public static class DataViewHolder extends RecyclerView.ViewHolder {
private final TextView place;
private final TextView alert;
public DataViewHolder(View view) {
super(view);
place = (TextView) view.findViewById(R.id.place_text_view);
alert = (TextView) view.findViewById(R.id.alert_text_view);
}
}
}
ListFragment:
public class ListFragment extends Fragment {
private RecyclerView recyclerView;
private static final String TAG = ListFragment.class.getSimpleName();
private ApiClient apiClient;
private List<Feature> features;
private RecyclerView.LayoutManager layoutManager;
private DataAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_list, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
getData();
return view;
}
private void getData() {
apiClient = new ApiClientFactory().createApiClient();
apiClient.getData().enqueue(new Callback<DataResponse>() {
#Override
public void onResponse(Call<DataResponse> call, Response<DataResponse> response) {
if (response.isSuccessful()) {
features = response.body().getFeatures();
adapter = new DataAdapter(features);
layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(layoutManager);
}
Log.d(TAG, "Data successfully downloaded");
}
#Override
public void onFailure(Call<DataResponse> call, Throwable t) {
Log.e(TAG, t.toString());
}
});
}
}
You should change the way you inflate the layout. This should do the trick.
public class DataAdapter extends RecyclerView.Adapter<DataAdapter.DataViewHolder> {
private List<Feature> features;
public DataAdapter(List<Feature> features) {
this.features = features;
}
#Override
public DataAdapter.DataViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.single_data_layout, parent, false);
return new DataViewHolder(view);
}
#Override
public void onBindViewHolder(DataViewHolder holder, int position) {
holder.place.setText(features.get(position).getProperties().getPlace());
holder.alert.setText(features.get(position).getProperties().getAlert());
}
#Override
public int getItemCount() {
return features.size();
}
public static class DataViewHolder extends RecyclerView.ViewHolder {
private final TextView place;
private final TextView alert;
public DataViewHolder(View view) {
super(view);
place = (TextView) view.findViewById(R.id.place_text_view);
alert = (TextView) view.findViewById(R.id.alert_text_view);
}
}
}
I see that the adapter class don't have a context , I guess if you add to the adapter constructor Context c as a second parameter your problem will be solved
try to replase
public DataAdapter(List<Feature> features) {
this.features = features;
}
by this
public DataAdapter(List<Feature> features, Context c) {
this.features = features;
this.context = c;
}
and replace this line in the fragment class
adapter = new DataAdapter(features);
by this
adapter = new DataAdapter(features,getActivity());
hope this will help you :)

Categories

Resources