NullPointerException in getView in ListView with multiple views in Android - android

I know there are lots and lots of questions like the one that I'm going to ask, however, none of them can give me a solution. I've read blogs and questions here, but no luck. I have a ListView in Android, and I want to display some news with two types of views/layouts: one for news that have pictures, and another one for news that don't have (only text),so the app can display something like this. But everytime I run my app I am getting an error:
E/AndroidRuntime(3973): FATAL EXCEPTION: main
E/AndroidRuntime(3973): Process: com.example.test23, PID: 3973
E/AndroidRuntime(3973): java.lang.NullPointerException
E/AndroidRuntime(3973): at com.example.test23.ItemAdapter.getView(ItemAdapter.java:80)
E/AndroidRuntime(3973): at android.widget.AbsListView.obtainView(AbsListView.java:2263)
E/AndroidRuntime(3973): at android.widget.ListView.measureHeightOfChildren(ListView.java:1263)
I am implementing the methods getItemViewType and getViewTypeCount(). I've implemented the famous ViewHolder but no luck either. Right now this is the Adapter class (cause I've changed it plenty of times):
public class ItemAdapter extends BaseAdapter implements OnItemClickListener {
Item item = null;
private ArrayList<Item> news = new ArrayList<Item>();
private static final int NO_PICTURE_VIEW = 0;
private static final int PICTURE_VIEW = 1;
public ItemAdapter(Context context, ArrayList<Item> items) {
super();
news.addAll(items);
}
#Override
public int getCount() {
return news.size();
}
#Override
public Item getItem(int index) {
return getItem(index);
}
#Override
public long getItemId(int index) {
return index;
}
public int getViewTypeCount() {
return 2;
}
public int getItemViewType(int position) {
Item article = news.get(position);
if (article.getImageUrl() != null && !article.getImageUrl().equals("")
&& article.getImageUrl().indexOf("no_pic.png") == -1)
// if there's no pic ?
// TYPE_SEPARATOR
// :
// TYPE_ITEM;
return NO_PICTURE_VIEW;
else
return PICTURE_VIEW;
}
#Override
public View getView(int index, View view, ViewGroup parent) {
item = news.get(index);
int type = getItemViewType(index);
int resource;
if (type == NO_PICTURE_VIEW) {
resource = R.layout.item_no_picture_list;
} else {
resource = R.layout.item_picture_list;
}
if (view == null) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
view = inflater.inflate(resource, parent, false);
TextView titleView = (TextView) view
.findViewById(R.id.titleArticle);
titleView.setText(item.getTitle());// this is the line that gives me
// the nullpointerexception
}
return view;
}
#Override
public void onItemClick(...) {
}
}
The layouts of both views are ok, I've tested them and no problem. I don't want like a separator, like I've seen on other blogs, I just want to be able to display both view for the same type of information, which is an array. If you need more info or more pieces of code, let me know. Any help or info is appreciated. Thanks in advance.
UPDATE here are the two layouts, for new with pics:
<ImageView
android:id="#+id/imageItem"
android:layout_width="80dp"
android:layout_height="80dp"
android:adjustViewBounds="true"
android:scaleType="fitXY"
android:contentDescription="DescripciĆ³n del contenido de la imagen"
android:src="#drawable/rr_logo"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical" >
<TextView
android:id="#+id/titleArticle"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:textStyle="bold"
android:textSize="18sp"
android:textColor="#000000"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"/>
</LinearLayout>
</LinearLayout>
For news with no pics:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/itemNoPicture" >
<TextView
android:id="#+id/titleNoPicture"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="18dp"/>
</LinearLayout>

There are only two reasons you could get the error
1) In either one of the layout files (item_no_picture_list or item_picture_list) there is no child with id titleArticle
2) The item in your arrayList news at index index is null
Check whichever is the case.. You can use Logs.. Write below code above the line which is causing error..
if(item == null)
Log.i("WhoIsNull", "item");
if(titleView == null)
Log.i("WhoIsNull", "titleView");

Related

Android FlexBox Layout shows only fixed number of lines

I'm trying to build a word-to-word RTL language ebook application. The data for the ebook is stored in an Sqlite database. After vigorous searching I found Flexbox layout suitable to my need in order to display my data in my required format. The following link helped me out: Android GridLayout with dynamic number of columns per row But the issue is that if the data passed in the view is large, then partial data is being displayed. If the data passed is small, then i have no issues at all.
Here is the adapter code:
public class VerseAdapter extends RecyclerView.Adapter<VerseAdapter.ViewHolder> {
private List<verseItem> items;
private Context context;
wordsAdapter sAdapter;
GridLayoutManager layoutManager;
public VerseAdapter(List<verseItem> items, Context context) {
this.items = items;
this.context = context;
}
// This method is used to attach
// custom layout to the recycler view
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View vw = LayoutInflater.from(parent.getContext()).inflate(R.layout.verse_row, parent, false);
return new ViewHolder(vw);
}
// This method is used to set the action
// to the widgets of our custom layout.
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
verseItem item = items.get(position);
ArrayList<wordsModel> models = new ArrayList<>(item.getWordsModelList());
String ayahnum = "" + item.getAyah();
holder.ayah.setText(ayahnum);
holder.verses_telugu.setText(item.getVerses_telugu());
// FlexboxLayoutManager code:
FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(context);
layoutManager.setFlexDirection(FlexDirection.ROW_REVERSE);
layoutManager.setJustifyContent(JustifyContent.FLEX_START);
ViewHolder.wordsrecyclerView.setLayoutManager(layoutManager);
sAdapter = new wordsAdapter(models);
ViewHolder.wordsrecyclerView.setAdapter(sAdapter);
sAdapter.notifyItemChanged(position);
holder.setIsRecyclable(false);
}
#Override
public int getItemCount() {
return items.size();
}
#Override
public int getItemViewType(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView ayah;
TextView verses_telugu;
public static RecyclerView wordsrecyclerView;
public ViewHolder(View itemView) {
super(itemView);
ayah = itemView.findViewById(R.id.ayah);
verses_telugu = itemView.findViewById(R.id.telugu_line);
wordsrecyclerView = itemView.findViewById(R.id.words_RV_id);
}
}
}
Here is my layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/ayah"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_margin="5dp"
android:textAlignment="viewStart"
android:textColor="#27A82C"
android:textSize="18sp"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/words_RV_id"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/telugu_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_margin="5dp"
android:textAlignment="textStart"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
This is how the final result show actually look like:
This is how my app looks like:
Now if you notice from the screenshots, the data that i'm trying to display is same. But in my app, not all words are being displayed as you can notice.
Another thing i have noticed is for larger data if the screen orientation is vertical the maximum lines i can see is 10 and if it is horizontal i can see 6 lines at max. These number of lines are fixed for all the places where the data is large. If the data is smaller it is displayed in the exact number of lines required and as mentioned earlier I have no issues at all.
Hoping someone helps me out soon. Thanks in advance. (:

android listView row height

I implemented a listview with 2 kinds of rows from here listViews with multiple rows tutorial
all is working properly,
the problem that I have now is setting the height for the rows,
if I leave the background as a color, all is good,
but if I use an image for background, I only get a tall row [on other simple list views the height respect the programatically set height], but in this case, the row changes
so
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/category_item_row"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:background="#ff00ff"
android:layout_height="70dp"
android:padding="3dp"
>
<ImageView
android:id="#+id/image"
android:layout_width="40dp"
android:layout_height="70dp"
android:gravity="center_vertical"/>
<TextView
android:id="#+id/title"
android:textSize="20sp"
android:layout_width="90dp"
android:layout_height="70dp"
android:gravity="center_vertical"/>
</LinearLayout>
works fine,
but
android:background="#drawable/phone_cat_cell">
is not respecting the assigned height,
how to fix this height using my image background?
thanks!
edit 1, adapter
listViewItem.setAdapter(new PhoneItemAdapter(new ItemPhoneDataSource().getItems()));
private class PhoneItemAdapter extends BaseAdapter {
final List<RowPhone> rows;//row
//data source, style
PhoneItemAdapter(List<ItemPhone> animals) {
rows = new ArrayList<RowPhone>();//member variable
//choose cell! iterator
for (ItemPhone item : animals) {
//if it has an image, use an ImageRow
if (item.getImageId() != null) {
rows.add(new RowFolderPhone(LayoutInflater.from(getActivity()), item)); //imageRow!
} else {//otherwise use a DescriptionRow
rows.add(new RowItemPhone(LayoutInflater.from(getActivity()), item));
}
}
}
//delegate
#Override
public int getViewTypeCount() {
return RowTypePhone.values().length;
}
#Override
public int getItemViewType(int position) {
//con cast
return ((RowPhone) rows.get(position)).getViewType();
}
public int getCount() {
return rows.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
//cambiado con cast!
return ((RowPhone) rows.get(position)).getView(convertView);
}
}
Check your adapter code, if you are passing null while inflating the view then please replace that code with this.
view = inflater.inflate(R.layout.listview_row, parent, false);
you just need to make not static images, but "9patch" images.
All android versions are supporting that.
Have a look here http://developer.android.com/tools/help/draw9patch.html
Try this:
<ImageView
android:id="#+id/image"
android:layout_width="40dp"
android:layout_height="70dp"
android:scaleType="fitXY"
android:adjustViewBounds="true"
android:gravity="center_vertical"/>

Invisible TextView's start to be visible when scrolling ListView

I've got huge problem that I don't understand. I have got custom ListView with my own adapter. Each row in ListView has two TextViews - one is a title and the second one is invisible at start. It's going to be visible when there is something new in this item.
In my adapter I set title for every row and set second TextView to be visible when it should be. When I run my app it's fine, but when i scroll down and up the list almost every row is changing invisible TextView to be visible!
I don't know why, but I spaculate that this is something with convertView. Can anybody tell me what's going on?
My adapter:
public class MyListAdapter extends BaseAdapter {
#SuppressWarnings("unused")
private Activity activity;
private ArrayList<String> titles;
private LayoutInflater inflater;
public MyListAdapter (Activity activity, ArrayList<String> titles) {
this.activity = activity;
this.titles = titles;
inflater = (LayoutInflater)activity.getLayoutInflater();
}
public int getCount() {
return titles.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if (convertView == null) {
vi = inflater.inflate(R.layout.wpis_list_row, null);
}
TextView title = (TextView)vi.findViewById(R.id.movie_title);
title.setText(titles.get(position));
String name = titles.get(position);
if (name.equals("Name 1") || name.equals("Name 2")
|| name.equals("Name 3")) {
TextView news = (TextView)vi.findViewById(R.id.new_sounds);
news.setVisible(0);
}
return vi;
}
}
and my layout for single row:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/LinearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/list_selector"
android:orientation="horizontal"
android:padding="5dip" >
<TextView
android:id="#+id/movie_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="9"
android:layout_marginLeft="#dimen/list_margin"
android:text="#string/entry"
android:textColor="#FFFFFF"
android:textSize="22sp" />
<TextView
android:id="#+id/new_sounds"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:textColor="#8C1717"
android:textSize="13sp"
android:text="#string/news"
android:visibility="invisible" />
</LinearLayout>
Sometimes you are setting the visibility of the text view as visible, based on some if condition . Make sure to change the visibility to gone in the else part.I hope this work . Also you are assigning view view= convertview and then doing if( convertview = null) . Assign the view to convert view in the else part of this check.
To make a View invisible in its layout, use android:visibility attribute set to gone or invisible depending on what you want to do.
Programmatically, to change visibility, call the View.setVisibility(VISIBILITY_YOU_WANT) method. There are some constants in View class you can use: View.GONE , View.VISIBLE , View.INVISIBLE.
BTW, read this post to better understand the ListView recycling.

Custom adapter failing without error

issue is this:
There are 49 items in the arraylist, and the adapter is stopping at item 3 without any error notification. The app does not crash, and no textviews are displayed. Here is the adapter:
public class ExhibitorObjectAdapter extends ArrayAdapter<ExhibitorObject> {
public ArrayList<ExhibitorObject> exhibitors;
public Activity act;
public TextView tvExhibitorName;
public ImageView ivExhibitorLogo;
public ExhibitorObjectAdapter(Activity a, int layoutResourceId, ArrayList<ExhibitorObject> ex) {
super(a, layoutResourceId,ex);
this.exhibitors = ex;
this.act = a;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return exhibitors.size();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) act.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.single_exhibitor, null);
}
ExhibitorObject ex = exhibitors.get(position);
if (ex != null) {
//System.out.println(ex.companyName);
tvExhibitorName = (TextView) v.findViewById(R.id.textViewListExhibitorName);
tvExhibitorName.setText( ex.companyName );
}
return v;
}
}
EDIT: here is the xml containing the listview:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:background="#134882"
android:paddingBottom="15sp"
android:paddingTop="5sp"
android:paddingLeft="5sp"
android:textColor="#FFFFFF"
android:text="Exhibitors" />
<ListView android:id="#+id/listViewExhibitors"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
</LinearLayout>
I have several other adapters that are exactly like this one and they work just fine. I have wasted an entire day on this (it's probably a silly problem), any help would be appreciated. Thanks.
It is bad to save tvExhibitorName in the scope of your adapter. Make it local within getView(), or you subject yourself to all kinds of leaks. That well may be the source of your problem.
Also, it is very strange that you don't inflate your new view under the parent. May be using inflate(layout, parent , false) will help.

Android - Custom GridView with separated XML

My goal is to display a chessboard. I have an Activity which displays a menu and load an instance of "ChessView" which extends GridView. I've created a custom GridView because I want to have a class fully dedicated to its display. So that class have its own layout.xml etc ...
GameActivity.java :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
//init a game
CChess.getInstance().init();
//creating the chessboard
ChessView lChessView = (ChessView) findViewById(R.id.chessView);
}
activity_game.xml :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background"
tools:context=".GameActivity" >
<project.chess.view.ChessView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/ChessView" >
</project.chess.view.ChessView>
</RelativeLayout>
ChessView.java :
public class ChessView extends GridView {
public ChessView(Context pContext, AttributeSet pAttrs) {
super(pContext, pAttrs);
GridView.inflate(pContext, R.layout.view_chess, null);
this.setAdapter(new ChessAdapter(pContext));
}
}
view_chess.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<GridView
android:id="#+id/gridView"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:numColumns="8"
android:gravity="center"
>
</GridView>
</LinearLayout>
ChessAdapter.java :
public class ChessAdapter extends BaseAdapter
{
private Context mContext;
public ChessAdapter (Context pContext)
{
this.mContext = pContext;
}
#Override
public int getCount()
{
return 64;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView lImageView;
if (convertView == null) {
lImageView = new ImageView(mContext);
int size = parent.getWidth()/8;
lImageView.setLayoutParams(new GridView.LayoutParams(size,size));
//background black or white depending of the position
int col = position/8 %2;
if (col == 0)
{
if (position%2 == 0)
lImageView.setBackgroundColor(Color.WHITE);
else
lImageView.setBackgroundColor(Color.BLACK);
}
else
{
if (position%2 == 0)
lImageView.setBackgroundColor(Color.BLACK);
else
lImageView.setBackgroundColor(Color.WHITE);
}
//load images
CPiece p = CChess.getInstance().getPiece(position/8, position%8);
if( p != null)
lImageView.setImageResource(mContext.getResources().getIdentifier(p.toString(), "drawable", mContext.getPackageName()));
} else {
lImageView = (ImageView) convertView;
}
return lImageView;
}
}
The result is : i have just 1 column of 64 squares all with an image (my init() in CChess is ok). To be clear, i want a 8x8 grid like all standards chessboards.
Few days ago, i had all this stuff in one activity without my custom view but just a simple gridView and all was working correctly. I have broken it since i've decided to separate my code in different classes
I'm sure i forgot something like an inflater somewhere but i don't understand how it works and what it does. I've parsed google for hours but i couldn't find the answer.
Can you help me please ? Thanks a lot for reading me and sorry for my english
I Think the problem with this LayoutInflator in ChessView.java
remove this line from that class
No Need to Inflate the GridView in that class
GridView.inflate(pContext, R.layout.view_chess, null);
and set the Column count and gravity in Chess View in activity_game.xml file.
android:layout_width="wrap_content"
android:numColumns="8"
I Think this works for you.

Categories

Resources