Fitting Constructor for a Custom adapter - java

I am trying to create a custom adapter, I have an error saying there is no default constructor available
public class GuessAdapter extends ArrayAdapter <Game> {
Context context;
int resource;
Peg[] guess;
LayoutInflater inflater;
public void PegArrayAdapter(Peg[] array, Context ctxt){
guess= array;
context = ctxt;
inflater = (LayoutInflater) ctxt.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
return guess.length;
}
#Override
public Game getItem(int arg0){
return guess[arg0];
}
public long getItemId(int arg0){
return arg0;
}
#Override
public View getView(int arg0, View arg1, ViewGroup arg2){
View view = arg1;
if (arg1==null){
arg1 = inflater.inflate(android.R.layout.simple_list_item_1, arg2, false);
}
ImageView imageView =(ImageView)arg1.findViewById(R.id.imageView);
ImageView imageView2=(ImageView)arg1.findViewById(R.id.imageView2);
ImageView imageView3=(ImageView)arg1.findViewById(R.id.imageView3);
ImageView imageView4=(ImageView)arg1.findViewById(R.id.imageView4);
return view;
}
}
what would the fitting constructor for this adapter be?

this
public void GuessAdapter(Peg[] array, Context ctxt){
super(ctxt, 0, array);
}

You haven't added any constructor to your custom adapter. You need to make a constructor which would call super.
Add this method in your custom adapter
public GuessAdapter(Peg[] array, Context ctxt) {
super(ctxt, 0, array);
guess= array;
context = ctxt;
inflater = (LayoutInflater) ctxt.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
Also, there is no use of method PegArrayAdapter, you can remove this afterwards.

The Best way of making custom Adapter is to use BASEADAPTER.
There will be no issue in that.
Just extend your CustomAdapter class to BaseAdapter.
I hope it works fine.

Related

Pass data from recyclerView to another in fragment

I want to pass data from recyclerview to another both in fragment, first adapter
for display item, and second adapter for basket fragment that want to put selected item in.
Adapter I want to take data from:
public class FruitItemAdapter extends RecyclerView.Adapter<FruitItemAdapter.viewHolder> {
ArrayList<FruitItem> fruitItems = new ArrayList<>();
private Context context;
public FruitItemAdapter(ArrayList<FruitItem> fruitItems, Context context) {
this.fruitItems = fruitItems;
this.context = context;
notifyDataSetChanged();
}
public FruitItemAdapter() {
}
#NonNull
#Override
public viewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view =
LayoutInflater.from(parent.getContext()).inflate(R.layout.fruits_item,parent,false);
viewHolder viewHolder = new viewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull viewHolder holder, int position) {
final FruitItem data_position = fruitItems.get(position);
holder.fruit_img.setImageResource(fruitItems.get(position).getFruit_img());
holder.fruit_name.setText(fruitItems.get(position).getFruit_name());
holder.fruit_price.setText(fruitItems.get(position).getFruit_price());
}
#Override
public int getItemCount() {
return fruitItems.size();
}
public void setfruitItem(ArrayList<FruitItem> fruitItems) {
this.fruitItems = fruitItems;
}
public static class viewHolder extends RecyclerView.ViewHolder {
private ImageView fruit_img;
private TextView fruit_price, fruit_name;
public viewHolder(#NonNull View itemView) {
super(itemView);
fruit_img = itemView.findViewById(R.id.fruit_img);
fruit_price = itemView.findViewById(R.id.fruit_price);
fruit_name = itemView.findViewById(R.id.fruit_name)
}
}
}
this is adapter for basket fragment that I want to put the data in
public class Basket_Adapter extends RecyclerView.Adapter<Basket_Adapter.viewHolder> {
private Context context;
ArrayList<FruitItem> fruitItems = new ArrayList<>();
public Basket_Adapter(Context context, ArrayList<FruitItem> fruitItems) {
this.context = context;
this.fruitItems = fruitItems;
notifyDataSetChanged();
}
public Basket_Adapter(){
}
#NonNull
#Override
public Basket_Adapter.viewHolder onCreateViewHolder(#NonNull ViewGroup parent, int
viewType) {
View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.fruits_item,parent,false);
viewHolder viewHolder = new viewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull Basket_Adapter.viewHolder holder, int position) {
holder.fruit_img.setImageResource(fruitItems.get(position).getFruit_img());
holder.fruit_name.setText(fruitItems.get(position).getFruit_name());
holder.fruit_price.setText(fruitItems.get(position).getFruit_price());
}
#Override
public int getItemCount() {
return fruitItems.size();
}
public void setfruitItem(ArrayList<FruitItem> fruitItems) {
this.fruitItems = fruitItems;
}
public class viewHolder extends RecyclerView.ViewHolder {
private ImageView fruit_img;
private TextView fruit_name;
private TextView fruit_price;
public viewHolder(#NonNull View itemView) {
super(itemView);
fruit_img = itemView.findViewById(R.id.fruit_img);
fruit_name = itemView.findViewById(R.id.fruit_name);
fruit_price = itemView.findViewById(R.id.fruit_price);
}
}
Now, what I can use to pass data between them.
You can achieve this by using the delegation pattern. Basically you create an interface relative to the first adapter (you can put it inside the adapter class or outside depending on your coding style) and you require it as an argument inside the adapter constructor like this:
public class FruitItemAdapter extends RecyclerView.Adapter<FruitItemAdapter.viewHolder> {
private Delegate delegate;
ArrayList<FruitItem> fruitItems = new ArrayList<>();
private Context context;
public FruitItemAdapter(Delegate delegate, ArrayList<FruitItem> fruitItems, Context context) {
this.delegate = delegate;
this.fruitItems = fruitItems;
this.context = context;
notifyDataSetChanged();
}
...
interface Delegate {
public void passItem(FruitItem item);
}
}
As you can see the interface has the method you need, but there's no implementation yet.
In this class you can just pretend that your delegate works and do the magic for you, for example by setting a click listener on the root view of your item in onBindViewHolder that will call delegate.passItem(fruitItems.get(position)) on each click.
Let's move on to the fragment.
Here is the key part. The fragment must implement the interface we just created by overriding its methods. Like so:
class ExampleFragment extends Fragment implements FruitItemAdapter.Delegate {
...
#Override
public void passItem(FruitItem item) {
// here you pass the item in a list inside
// the shared preferences.
}
}
For your case the best way is to store your items in a database or in the shared preferences. We go with the shared preferences because is simpler, but keep in mind that shared preferences have limited memory capacity and you should use a database like Room instead.
Inside the override method you pass your item to a list stored in the shared preferences. Since your item is not a primitive object i suggest you to look at this answer that show how to store complex object as a string:
https://stackoverflow.com/a/18463758/18740763.
In your case the object that needs to be serialized is an Array or a List of objects.
Every time you need to put a new object in the list you need to follow these steps:
get the list from shared preferences
deserialize it
add the new item
serialize it again
put it back in the shared preferences under the same key
If you stored your items correctly now you should be able to access the shared list in every fragment or activity of your application. So simply access your list from the fragment that implements the second adapter, deserialize it, just addAll() the items the the adapter list and notifyDataSetChanged().

Strange NullPointerException in my own ArrayAdapter

I'm beginner in programming in Android Studio and I'm making now some kind of messenger via bluetooth. So I have my own ArrayAdapter class which extends ArrayAdapter class and it is for outgoing and incoming messages. I want incoming messages to be at the left side ang outgoing ones at the right, so I made two layouts for this Adapter. I know, that on stackoverflow there is a lot of solutions to make ArrayAdapter with few diffrent layouts for each row, but every one of them doesn't work - changing layouts cause change view of every row. So my solution is to make another ArrayList of booleans, and in getView() I check what I have in this List - true or false - and use right layout on that row in ArrayAdapter (I'm checking it by position field from getView()). And when I send a lot of messages to second device and try to response to first device there is NullPointerException in line with
(TextView)row.findViewById(R.id.singleIncomingMessage);
or
(TextView)row.findViewById(R.id.singleOutgoingMessage);
This exceptions seems to appear in random situation, but of course there must be some pattern. Here's the whole code. What it's wrong? And I'm sorry for my language if there is some misspells ;)
public class MyArrayAdapter extends ArrayAdapter<String> {
public MyArrayAdapter(Context context, ArrayList<String> list) {
super(context, 0, list);
this.list =list;
this.context=context;
}
ArrayList<String> list;
Context context;
#Override
public int getCount() {
return list.size();
}
#Override
public String getItem(int position) {
return list.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
if(Messenger.inOut){
return 1;
}
else{
return 0;
}
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
int type=getItemViewType(position);
View row=convertView;
if(row==null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(Messenger.inOutList.get(position)==0){
row=inflater.inflate(R.layout.outgoing_message_layout, parent, false);
}
if(Messenger.inOutList.get(position)==1){
row=inflater.inflate(R.layout.incoming_message_layout, parent, false);
}
}
String message=getItem(position);
TextView label;
if(Messenger.inOutList.get(position)==0){
label=(TextView)row.findViewById(R.id.singleOutgoingMessage);
label.setText(message);
}
if(Messenger.inOutList.get(position)==1){
label=(TextView)row.findViewById(R.id.singleIncomingMessage);
label.setText(message);
}
return row;
}
}
I think the issue is from the case where row is non-null. It may have previously been inflated as an outgoing message layout, now you are recycling it and trying to treat it as an incoming message layout, so it can't find the TextView.
It's hard to say for sure this is the issue though since I don't really know how the Messenger.* calls behave in your code. Since you already get type in getView you should use that rather than Messenger.inOutList.get(position)==X to determine which view logic to use if you keep it this way. This question has some good answers on how to do this consistently.
Also keep in mind that for this to work getItemViewType must always return the same type for a given position, or else you have to detect the change and inflate a new layout in getView. If Messenger.inOut is constant, there's not reason to use this format (multi-layout format). If it's not a constant and it gets changed, then you need to detect this in getView
Okay, thank you very much, I finally did it. I was using two list (of booleans and messages) and after I read about ArrayAdapter I decided to make class with this two fields and make a list of its object. That error was probably because of that second list of booleans. Here's below my final code if anyone have similiar problem.
public class MyArrayAdapter extends ArrayAdapter<MessageWithType> {
public MyArrayAdapter(Context context, ArrayList<MessageWithType> list) {
super(context, 0, list);
this.list =list;
this.context=context;
}
public static final int TYPE_OUT = 0;
public static final int TYPE_IN = 1;
ArrayList<MessageWithType> list;
Context context;
#Override
public int getCount() {
return list.size();
}
#Override
public MessageWithType getItem(int position) {
return list.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
if(list.get(position).inOut){
return 1;
}
else{
return 0;
}
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
MessageWithType item=getItem(position);
int type=getItemViewType(position);
View row=convertView;
ViewHolder viewHolder=null;
if(row==null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(type==TYPE_OUT){
row=inflater.inflate(R.layout.outgoing_message_layout, parent, false);
}
if(type==TYPE_IN){
row=inflater.inflate(R.layout.incoming_message_layout, parent, false);
}
TextView label=(TextView)row.findViewById(R.id.singleMessage);
viewHolder=new ViewHolder(label);
row.setTag(viewHolder);
}
else{
viewHolder=(ViewHolder)row.getTag();
}
viewHolder.textView.setText(item.message);
return row;
}
public class ViewHolder{
TextView textView;
public ViewHolder(TextView textView){
this.textView=textView;
}
}
}

Cannot resolve getSystemService method in ListView adapter

I am working through John Horton's Android Programming for Beginners, and am currently attempting to create a note-taking app. Horton has just introduced ListViews. However, I am having trouble with the adapter class:
public class NoteAdapter extends BaseAdapter {
List<Note> mNoteList = new ArrayList<Note>();
#Override
public int getCount(){
return mNoteList.size();
}
#Override
public Note getItem(int whichItem){
return mNoteList.get(whichItem);
}
#Override
public long getItemId(int whichItem){
return whichItem;
}
#Override
public View getView(int whichItem, View view, ViewGroup viewGroup){
// check if view has been inflated already
if (view == null){
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); // ERROR HERE
view = inflater.inflate(R.layout.listitem, viewGroup, false);
}
return view;
}
}
The problem is in the getView method, where I'm attempting to inflate the layout: Android Studio throws an error: 'Cannot resolve getSystemService(java.lang.String)'.
As a complete newcomer just following through the book I have no idea where to go from here or what to try to resolve it - can anyone help?
The best way to get a LayoutInflater is by calling getLayoutInflater() on an Activity. That way, the activity's theme is taken into account. If NoteAdapter is defined inside of an Activity, just call getLayoutInflater(). If NoteAdapter is defined in its own separate Java class file, pass in a LayoutInflater via the constructor.
To more directly address your question, any View, like ListView, can call getContext() to get a Context. That is where getSystemService() is defined. So, replacing getSystemService() with viewGroup.getContext().getSystemService() would work.
You should pass Context to your adapter and then replace this line:
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
I hope this will help.
Use
view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.listitem, viewGroup,false);
Create a class variable and a Constructor for your adapter:
Context context;
public NoteAdapter(Context context){
this.context = context;
}
Then initialize the layoutinflater the following way:
LayoutInflater inflater = LayoutInflater.from(context);
Try
public class NoteAdapter extends BaseAdapter {
Context mContext = null;
public NoteAdapter(Context context){
mContext = context;
}
#Override
public View getView(int whichItem, View view, ViewGroup viewGroup){
// check if view has been inflated already
if (view == null){
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); // ERROR HERE
view = inflater.inflate(R.layout.listitem, viewGroup, false);
}
return view;
}
}
First make the constructor of Adapter: like follow :
Context context;
public NoteAdapter(Context context)
{
this.context = context
}
Now use this context:
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
In my views, if you are learning then learn RecyclerView. bcz it is better than ListView. i am not saying that ListView has been depricated. But there alot of internal things in which RecyclerView is better.
Following is example of Adapter
public class NoteAdapter extends BaseAdapter {
List<Note> mNoteList = new ArrayList<Note>();
Context context;
public NoteAdapter(Context context){
this.context = context;
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount(){
return mNoteList.size();
}
#Override
public Note getItem(int whichItem){
return mNoteList.get(whichItem);
}
#Override
public long getItemId(int whichItem){
return whichItem;
}
#Override
public View getView(int whichItem, View view, ViewGroup viewGroup){
// check if view has been inflated already
if (view == null){
view = inflater.inflate(R.layout.listitem, viewGroup, false);
}
return view;
}
}
Inside MainActivity.java
NoteAdapter noteA = new NoteAdapter(MainActivity.this);
OR
NoteAdapter noteA = new NoteAdapter(getContext());
OR
NoteAdapter noteA = new NoteAdapter(getActivity);
// if in Fragment
OR
NoteAdapter noteA = new NoteAdapter(getApplicationContext);
// will work but no need to use it. bcz this is context of whole application. For an adapter you don't need context of whole application.
mContext is Context which you pass to Custom Adapter
public boolean CheckInternet() {
ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState() == NetworkInfo.State.CONNECTED ||
connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState() == NetworkInfo.State.CONNECTED) {
//we are connected to a network
return true;
}
return false;
}//end of check internet

java.lang.IllegalStateException: ViewPager

My application gets all images URL from server and saves that to an ArrayList and displays these images in ViewPager. But it generates a IllegalStateException. Adapter given below:
public class FullScreenImageAdapter extends PagerAdapter {
private Context _activity;
private ArrayList<String> _imagePaths;
private LayoutInflater inflater;
// constructor
public FullScreenImageAdapter(Context activity,
ArrayList<String> imagePaths) {
this._activity = activity;
this._imagePaths = imagePaths;
}
#Override
public int getCount() {
return this._imagePaths.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView imgDisplay;
inflater = (LayoutInflater) _activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View viewLayout = inflater.inflate(R.layout.item, container,
false);
imgDisplay = (ImageView) viewLayout.findViewById(R.id.cardImage);
Picasso.with(_activity).load(_imagePaths.get(position)).into(imgDisplay);
((ViewPager) container).addView(viewLayout, 0);
return viewLayout;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((ImageView) object);
}
}
Adapter created as
FullScreenImageAdapter adapter=new FullScreenImageAdapter(FullScreenActivity.this,all_url);
viewPager.setAdapter(adapter);
And the log looks like below:
java.lang.IllegalStateException: The application's PagerAdapter
> changed the adapter's contents without calling
> PagerAdapter#notifyDataSetChanged! Expected adapter item count: 1,
> found: 3 Pager id: com.wat.clickzy:id/view_pager Pager class: class
> android.support.v4.view.ViewPager Problematic adapter: class
> com.wat.clickzy.FullScreenImageAdapter
Please help me
You need to call notifysetdatachanged on the adapter that you're using, every time you're adding/removing something to that adapter.
Look here for even more clarity.

java.lang.IllegalArgumentException: Can't have a viewTypeCount < 1

I'm getting this error:
java.lang.IllegalArgumentException: Can't have a viewTypeCount < 1
I'm pretty sure I know exactly what's causing it, but I don't know how to fix it.
My app loads a users friends from the database. When the user has at least 1 friend to put in the list view, it's fine. When the user is brand new and has no friends yet, the app crashes because the listview has a count of 0.
Is this simply a case of error handling?
If I don't post all the necessary relevant code please let me know!
Here is my adapter:
public class MyAdapter extends ArrayAdapter<HashMap<String, String>> {
Context context;
int resourceId;
LayoutInflater inflater;
private Context mContext;
#Override
public int getViewTypeCount() {
return getCount();
}
#Override
public int getItemViewType(int position) {
return position;
}
ArrayList<HashMap<String, String>> items;
public MyAdapter (Context context, int resourceId, ArrayList<HashMap<String, String>> items)
{
super(context, resourceId, items);
mContext = context;
this.items =items;
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
final ViewHolder holder;
if (convertView == null){
convertView = inflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
holder.fbphoto = (ImageView)convertView.findViewById(R.id.fbphoto);
holder.name = (TextView)convertView.findViewById(R.id.name);
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
final HashMap<String,String> item = (HashMap<String,String> ) items.get(position);
if (item != null)
{
String facebookProfilePicUrl = "https://graph.facebook.com/"+item.get(TAG_FACEBOOKID)+"/picture?width=150&height=150";
Picasso.with(mContext)
.load(facebookProfilePicUrl)
.placeholder(R.drawable.no_image)
.into(holder.fbphoto);
holder.name.setText(item.get(TAG_USERNAME));
}
return convertView;
}
public class ViewHolder
{
ImageView fbphoto;
TextView name;
}
}
I think you miss the point of ViewTypeCount. You should return the number of Different View Types in your list.
This is important for recycling of the Views inside the List.
Imaging you have 2 Types of Listitems, one with a white Background and one with black Background. When you return 2 as ViewTypeCount the Listview knows ok, there a 2 types of Listitems and will not mix them up in the getView view recycling.
so just use:
public int getViewTypeCount() {
return 1;
}
or dont override that method at all.
Use this
#Override
public int getViewTypeCount() {
if(getCount() > 0){
return getCount();
}else{
return super.getViewTypeCount();
}
}
getViewTypeCount returns the number of different types of views this adaptor can return. Since you're only returning one type of view, this should just return 1.
Change this function in your Adapter class:
#Override
public int getViewTypeCount() {
return getCount();
}
to:
public int getViewTypeCount() {
if(getCount()<1) return 1;
return getCount();
}
**note: avoid #Override

Categories