custom ArrayAdapter is not being called - java

I'm writing an app the gets information off an RSS feed, parses it using the DOM parser (issues with the clients RSS feed) and then shows the parsed objects in a ListView.
For some reason, the getView() is not being called...
here is the code for the Activity:
public class NoPicList extends Activity {
ListView list;
NoPicAdapterV2 adapter2;
ProgressDialog mDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.no_pic_list);
list = (ListView) findViewById(R.id.noPicListView);
// get the request from the main activity
Bundle b = getIntent().getExtras();
String request = b.getString("REQUEST");
mDialog = new ProgressDialog(this);
mDialog.setCancelable(false);
mDialog.setMessage("Lodaing Data");
mDialog.show();
new GetNewsAndCalendar().execute(request);
}
#Override
protected void onPause() {
mDialog.dismiss();
super.onPause();
}
class GetNewsAndCalendar extends
AsyncTask<String, Void, ArrayList<Message>> {
#Override
protected ArrayList<Message> doInBackground(String... params) {
String url = params[0];
DOMFeedParser parser = new DOMFeedParser(url);
return parser.parse();
}
#Override
protected void onPostExecute(ArrayList<Message> result) {
adapter2 = new NoPicAdapterV2(NoPicList.this, R.layout.no_pic_list_item, result);
list.setAdapter(adapter2);
mDialog.dismiss();
}
}
}
here is the code for the adapter:
public class NoPicAdapterV2 extends ArrayAdapter<NewAndCalendar> {
private ArrayList<Message> data;
private LayoutInflater inflator;
private Activity mActivity;
public NoPicAdapterV2(Context context, int textViewResourceId,
ArrayList<Message> result) {
super(context, textViewResourceId);
data = (ArrayList<Message>) result;
mActivity = (Activity) context;
inflator = (LayoutInflater) mActivity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
if (vi == null)
vi = inflator.inflate(R.layout.no_pic_list_item, parent, false);
TextView title = (TextView) vi.findViewById(R.id.noPicTitle);
TextView subtitle = (TextView) vi.findViewById(R.id.noPicSubtitle);
TextView id = (TextView) vi.findViewById(R.id.noPicID);
title.setText(data.get(position).getTitle().toString());
subtitle.setText(data.get(position).getDate().toString());
id.setText(data.get(position).getDescription());
return vi;
}
}
the DOMFeedParser code is built according to the IBM open source Java XML parser article.
thanks a bunch...

you should override (in your custom adapter)
getCount()
and return the size of data in order to let the adpater works. Or you call the ArrayAdapter constructor that takes data
public ArrayAdapter (Context context, int textViewResourceId, T[] objects)

Your ArrayAdapter does not know the content of your array, and therefore the count is 0.
Use this super constructor instead : http://developer.android.com/reference/android/widget/ArrayAdapter.html#ArrayAdapter%28android.content.Context,%20int,%20java.util.List%3CT%3E%29
Like this :
public NoPicAdapterV2(Context context, int textViewResourceId,
ArrayList<Message> result) {
// Here
super(context, textViewResourceId, result);
data = (ArrayList<Message>) result;
mActivity = (Activity) context;
inflator = (LayoutInflater) mActivity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

I hope below code will work just add one more argument to super(...)
public NoPicAdapterV2(Context context, int textViewResourceId,
ArrayList<Message> result) {
super(context, textViewResourceId,result);
data = (ArrayList<Message>) result;
mActivity = (Activity) context;
inflator = (LayoutInflater) mActivity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

Related

Custom Adapter starts before ArrayList is ready

I'm making a list of links and for that I have made a custom adapter, but the list is not ready when the adapter starts so I get the following error:
java.lang.RuntimeException: Unable to start activity ComponentInfo{}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.content.Context.getSystemService(java.lang.String)' on a null object reference
this is because when the adapter is started the list is empty, and just moments after the list is filled but it's too late here is my code:
UPDATE: the code has been changed so now I du not get the error but it doesn't run getView in the adapter:
public class Controller extends Activity {
private String TAG = Controller.class.getSimpleName();
private String http;
CustomAdapter adapter;
public Controller con = null;
private ListView lv;
private static String url;
ArrayList<Selfservice> linkList = new ArrayList<Selfservice>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_view);
con = this;
http = this.getString(R.string.http);
url = this.getString(R.string.path1);
new GetLinks().execute();
lv = (ListView)findViewById(R.id.list);
//Resources res = getResources();
//adapter = new CustomAdapter(con, linkList, res);
//lv.setAdapter(adapter);
}
private class GetLinks extends AsyncTask<Void, Void, List<Selfservice>> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected List<Selfservice> doInBackground(Void... arg0) {
Document doc;
Elements links;
List<Selfservice> returnList = null;
try {
doc = Jsoup.connect(url).timeout(0).get();
links = doc.getElementsByClass("processlink");
returnList = ParseHTML(links);
} catch (IOException e) {
e.printStackTrace();
}
return returnList;
}
#Override
protected void onPostExecute(final List<Selfservice> result) {
super.onPostExecute(result);
runOnUiThread(new Runnable() {
#Override
public void run() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//setSupportActionBar(toolbar);
//getSupportActionBar().setDisplayShowTitleEnabled(false);
toolbar.setTitle("");
toolbar.setSubtitle("");
Resources res = getResources();
Log.e(TAG, linkList.toString());
linkList = (ArrayList<Selfservice>) result;
adapter = new CustomAdapter(con, result, res);
adapter.notifyDataSetChanged();
lv.setAdapter(adapter);
}
});
}
}
and my adapter:
public class CustomAdapter extends BaseAdapter implements OnClickListener {
private String TAG = CustomAdapter.class.getSimpleName();
Context context;
List<Selfservice> data;
private Activity activity;
public Resources res;
Selfservice self = null;
private static LayoutInflater inflater;
int layoutResourceId = 0;
public CustomAdapter(Activity act, List<Selfservice> dataList, Resources resources) {
res = resources;
activity = act;
data = dataList;
}
private class Holder {
TextView title;
TextView link;
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int pos) {
return pos;
}
#Override
public long getItemId(int pos) {
return pos;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = convertView;
Holder holder;
if(rowView == null){
rowView = inflater.inflate(R.layout.list_item, null);
holder = new Holder();
holder.title = (TextView) rowView.findViewById(R.id.title);
holder.link = (TextView) rowView.findViewById(R.id.link);
rowView.setTag(holder);
}else{
holder = (Holder)rowView.getTag();
}
if(data.size()<=0){
holder.title.setText("did not work");
}else{
self = null;
self = (Selfservice) data.get(position);
holder.title.setText(self.getTitle());
holder.link.setText(self.getLink());
Log.i(TAG, "adapter");
rowView.setOnClickListener(new OnItemClickListener(position));
}
return rowView;
}
#Override
public void onClick(View v){
Log.v("CustomAdapter", "row clicked");
}
private class OnItemClickListener implements OnClickListener{
private int mPos;
OnItemClickListener(int position){
mPos = position;
}
#Override
public void onClick(View arg0){
Controller con = (Controller)activity;
con.onItemClick(mPos);
}
}
}
So How do I get the adapter to wait to the list is full?
firstly use ArrayAdapter<Selfservice> instead of BaseAdapter
use constructor
public CustomAdapter(Context context, int resource, List<Selfservice> objects) {
super(context, resource, objects);
data = objects;
}
then override only two methods
public int getCount()
public View getView(int position, View convertView, ViewGroup parent)
then return list.size() in getCount()
in getView() method
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.list_item, null);
}
in doInBackground() method in the try block
instead of linkList = ParseHTML(links);
do linkList.addAll(ParseHTML(links));
and in onPostExcecute() method
adapter.notifyDatasetChanged(); in the ui thread
You can create the adapter in the onPostExecute;
Change the Async Task to this:
private class GetLinks extends AsyncTask<Void, Void, List<Selfservice>> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... arg0) {
Document doc;
Elements links;
List<Selfservice> returnList
try {
doc = Jsoup.connect(url).timeout(10000).get();
links = doc.getElementsByClass("processlink");
returnList = ParseHTML(links);
} catch (IOException e) {
e.printStackTrace();
}
return returnList;
}
#Override
protected void onPostExecute(List<Selfservice> result) {
super.onPostExecute(result);
runOnUiThread(new Runnable() {
#Override
public void run() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//setSupportActionBar(toolbar);
//getSupportActionBar().setDisplayShowTitleEnabled(false);
toolbar.setTitle("");
toolbar.setSubtitle("");
linkList = result
adapter = new CustomAdapter(con, result, res);
lv.setAdapter(adapter);
}
});
}
This way you will only create the adapter when your list is ready.
Edit:
You are not creating the variable context inside your adapter. Change your constructor to this:
public CustomAdapter(Context context, Activity act, List<Selfservice> dataList, Resources resources) {
res = resources;
activity = act;
data = dataList;
this.context = context;
}
And you will stop seeing the NullPointerExecption

ListViewAdapter.NotifyDataSetChanged() not working [duplicate]

I have a list that can be updated by the user, but notifyDataSetChanged() is not working on the adapter associated with the listView. I am using it in a fragment. Datbase gets updated, however the adpater doesn't. Following is my implementation:
My Main Fargment:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myArrayList = new ArrayList<myList>();
myArrayList = Database.getSharedObject(getActivity()).getMyList();
if (myArrayList != null && myArrayList.size() > 0) {
adapter = new myListAdapter(getActivity(), 0, myArrayList);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.mainfragment, container, false);
myListView = (ListView) v.findViewById(R.id.my_list_view);
myListView.setOnItemClickListener(this);
if (adapter != null) {
myListView.setAdapter(adapter);
}
return v;
}
After some navigations process List gets updated and in my onResume() method I get the updated List from database and call notifyDatasetChanged() method that does not update my view, however corresponding array from DB is updated one.
#Override
public void onResume() {
super.onResume();
myArrayList = Database.getSharedObject(getActivity()).getMyList();
adapter.setItems (myArrayList);
adapter.notifyDataSetChanged();
}
MyListAdapter
public class MyListAdapter extends ArrayAdapter<Message> {
private ArrayList<Message> myList;
/* Context */
private Context context;
public void setItems (ArrayList<Message> myList) {
this.myList = myList;
}
public MyListAdapter (Context context, int textViewResourceId, ArrayList<Message> myList) {
super(context, textViewResourceId, myList);
this.context = context;
this.myList = myList;
}
#Override
public View getView (int position, View v, ViewGroup parent) {
// Keeps reference to avoid future findViewById()
MyViewHolder viewHolder;
if (v == null) {
LayoutInflater li = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = li.inflate(R.layout.list_row, parent, false);
viewHolder = new MyViewHolder();
viewHolder.txtImage = (ImageView) v.findViewById(R.id.message_icon);
viewHolder.txtMessage = (TextView) v.findViewById(R.id.message);
viewHolder.txtDate = (TextView) v.findViewById(R.id.date);
v.setTag(viewHolder);
} else {
viewHolder = (MyViewHolder) v.getTag();
}
Message myMessage = new Message();
myMessage = myList.get(position);
if (myMessage != null) {
viewHolder.txtMessage.setText(myMessage.getText());
viewHolder.txtDate.setText(myMessage.getDate());
}
return v;
}
static class MyViewHolder {
ImageView txtImage;
TextView txtMessage;
TextView txtDate;
}
}
Any thought on what is going wrong? Why is not listview getting updated? Any helps is appreciated.
notifyDataSetChanged() won't work for you. Reasons why
Your adapter loses reference to your list.
Always creating and adding a new list to the Adapter. Do like this:
initialize the ArrayList while declaring globally.
ArrayList<MyItemType> myArrayList=new ArrayList<>(); // as a global variable
Add List to the adapter directly without checking null and empty condition. Set the adapter to the list directly(don't check for any condition)
myListView.setAdapter(adapter);
Add data to the myArrayList Every time(if your data is completely new, then you can call adapter.clear() and myArrayList.clear() before actually adding data to the list) but don't set the adapter
i.e If the new data is populated in the myArrayList, then just adapter.notifyDataSetChanged()
adapter = new myListAdapter(getActivity(), 0, myArrayList);
Remove this line
adapter.setItems (myArrayList);
Just overrige getCount method
#Override
public int getCount() {
return myArrayList.count();
}
In your setItems method try to clear the old ArrayList.
instead of this:
public void setItems(ArrayList<Message> myList) {
this.myList = myList;
}
Try this:
public void setItems(ArrayList<Message> myList) {
this.myList.clear();
this.myList.addAll(myList);
notifyDataSetChanged();
}
The problem is in the constructor of MyListAdapter
Instead of
public MyListAdapter(Context context, int textViewResourceId, ArrayList<Message> myList) {
super(context, textViewResourceId, scheduledMessageList);
this.context = context;
this.myList = myList;
}
try
public MyListAdapter(Context context, int textViewResourceId, ArrayList<Message> myList) {
super(context, textViewResourceId, myList);
this.context = context;
this.myList = myList;
}
also instead of you own Method setItems you should call adapter.clear(); followed by adapter.addAll(myArrayList);
If you can use notifyDataSetChanged() but in Adapter !
create a little method inside

How to start intent inside custom Listadapter which extends ArrayAdapter

I want to start a new activity to send sms to some number. I have tried this code but my activity crashes. I get null NullPointerException. Guide me how to start new activity kindly. I have also added permission for sms in manifest file
public class ListAdapter extends ArrayAdapter<ParseUser> {
private Context context;
public ListAdapter(Context context, int resource, List<ParseUser> user1) {
super(context, resource, user1);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi;
vi = LayoutInflater.from(getContext());
v = vi.inflate(R.layout.list_item_layout, null);
}
final ParseUser p = (ParseUser) getItem(position);
if(p!=null){
TextView username = (TextView)v.findViewById(R.id.username);
TextView bloodType = (TextView)v.findViewById(R.id.bloodtype);
//TextView longitude = (TextView)v.findViewById(R.id.longitude);
//TextView latitude = (TextView)v.findViewById(R.id.latitude);
//TextView mobile = (TextView)v.findViewById(R.id.mobile);
Button msgButton = (Button)v.findViewById(R.id.message_me);
final String number = p.getString("Mobile");
if(username!=null){
username.setText(p.getString("Name"));
}
if(bloodType!=null){
bloodType.setText(p.getString("Bloodtype"));
}
msgButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent a = new Intent(getContext(),SmsActivity.class);
a.putExtra("number",number);
context.startActivity(a);
}
});
}
return v;
}
}
Problem is here: context.startActivity(a);. You are using context field but never assign it. You can assign it in the constructor:
public ListAdapter(Context context, int resource, List<ParseUser> user1) {
super(context, resource, user1);
this.context = context;
}
Or you can use getContext() instead of context: getContext().startActivity(a);. In this case you don't need context field completely.
can you replace to this
public void onClick(View v) {
Intent a = new Intent(this.ListAdapter ,SmsActivity.class);
Intent a = new Intent(getContext(),SmsActivity.class);
change to
Intent a = new Intent(context,SmsActivity.class);

How to set GridViewCustomAdapter from asyncTask?

In my app I have PostersFragment that will be a GridView with movies posters, in this fragment I need to initialize the GridView and customGridViewAdapter.
My customGridViewAdapter need to get the Bitmaps array and then work with it.
The problem that I call to AsyncTask that is in different class that gets all information from JSON and stores the information with the movies posters on local database.
I cant understand how and when to use the .setAdapter(gridViewCustomAdapter);
There is my code.
public class PostersFragment extends Fragment implements AdapterView.OnItemClickListener {
private GridView gv_posters;
private GridViewCustomAdapter gridViewCustomAdapter;
public PostersFragment() {
setHasOptionsMenu(true);
}
#Override
public void onStart() {
super.onStart();
UpdatePosters();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d("TESTAG","onCreateView");
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
gv_posters = (GridView) rootView.findViewById(R.id.gv_posters);
gv_posters.setAdapter(gridViewCustomAdapter);
gv_posters.setOnScrollListener(new PostersScrollListener(getActivity().getApplicationContext()));
gv_posters.setOnItemClickListener(this);
// Define new adapter for grid view
return rootView;
}
private void UpdatePosters() {
Log.d("TESTAG","UpdatePoster");
MoviesTask task = new MoviesTask(getActivity(),gridViewCustomAdapter);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
String path = prefs.getString(getString(R.string.sort_method_posters_pref), getString(R.string.default_path));
task.execute(path);
}
MoviesTask.java
public class MoviesTask extends AsyncTask<String, Void, Bitmap[]> {
// Byte array to handle bitmaps
private byte[] imgByte;
// Context and custom adapter variables
private final Context mContext;
private GridViewCustomAdapter mGridCustomAdapter;
// MovieTask Constructor
public MoviesTask(Context context, GridViewCustomAdapter gridAdapter) {
mContext = context;
mGridCustomAdapter = gridAdapter;
}
Parsing JSON methods...
#Override
protected void onPostExecute(Bitmap[] bitmaps){
Log.d("TESTAG","onPostExecute");
if (bitmaps != null)
mGridCustomAdapter = new GridViewCustomAdapter(mContext,R.id.single_gv_poster,bitmaps);
}
GridViewCustomAdapter.java
public class GridViewCustomAdapter extends BaseAdapter{
private Context context;
int layoutResource;
private Bitmap[] bitmaps;
public GridViewCustomAdapter(Context context,int layoutResource, Bitmap[] bitmaps){
this.context = context;
this.layoutResource = layoutResource;
this.bitmaps = bitmaps;
}
#Override
public int getCount() {
return 0;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
viewHolder holder = null;
if (view == null){
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
view = inflater.inflate(layoutResource,parent,false);
holder = new viewHolder();
holder.imageView = (ImageView)view.findViewById(R.id.single_gv_poster);
view.setTag(holder);
}else
holder = (viewHolder)view.getTag();
Bitmap bitmap = bitmaps[position];
holder.imageView.setImageBitmap(bitmap);
return view;
}
static class viewHolder{
ImageView imageView;
}
}
Anyone can help me with this issue please?
You can do this way:
Delete line from onCreate():
gv_posters.setAdapter(gridViewCustomAdapter);
Your PostExecute should looks like this:
#Override
protected void onPostExecute(Bitmap[] bitmaps){
Log.d("TESTAG","onPostExecute");
if (bitmaps != null)
mGridCustomAdapter = new GridViewCustomAdapter(mContext,R.id.single_gv_poster,bitmaps);
gv_posters.setAdapter(mGridCustomAdapter);
}
}
Hope this will help you.

How to change or set subitems of a listview from AsyncTask?

In my MainActivity I have a listview with two lines of text for each row. Only the first line is written when the app is started, the second line must be written based on the things processed by an AsyncTask class. When I try to do it, the first item of the listview gets all the values AsyncTask gives, because I don't understand how to update only the second line of the listview for each item, without rewriting the whole listview.
Every textView has its own id in the xml layout file. How can I do it in the onPostExecute()?
Here's the code:
In MainActivity onCreate():
final ListView listview = (ListView) findViewById(R.id.listview);
final String[] values = new String[10];
for(int i=0;i<10;i++){
//do stuff to write the values[] elements
}
MySimpleArrayAdapter adapter = new MySimpleArrayAdapter(this, values);
listview.setAdapter(adapter);
MySimpleArrayAdapter class:
public class MySimpleArrayAdapter extends ArrayAdapter<String> {
private final Context context;
private final String[] values;
int position=0;
public MySimpleArrayAdapter(Context context, String[] values) {
super(context, R.layout.list_layout, values);
this.context = context;
this.values = values;
}
#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 firstLine = (TextView) rowView.findViewById(R.id.label);
TextView secondLine = (TextView) rowView.findViewById(R.id.sublabel);
firstLine.setText(values[position]);
secondLine.setText(""); //I prefer to write an empty string for the secondLine
return rowView;
}
}
The AsyncTask:
private class Process extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
//do stuff
}
#Override
protected void onPostExecute(String message) {
TextView secondLine = (TextView) findViewById(R.id.sublabel);
//This of course udpdates only the secondLine of the first item of listview
secondLine.setText(processedValues);
}
}
pass the TextView as a parameter to the AsyncTask as follows
private class Process extends AsyncTask<Void, Void, String> {
private WeakReference<TextView> weakTextView;
public Process(TextView textView){
weakTextView = new WeakReference<TextView>(textView);
}
#Override
protected String doInBackground(Void... params) {
//do stuff
}
#Override
protected void onPostExecute(String message) {
TextView tv = weakTextView.get();
if(tv!=null){
tv.setText(message);
}
}
}
you call this in your getView as
Process p = new Process(yourTextView);
p.execute();
//method number two
private class Process extends AsyncTask<TextView, Void, String> {
private WeakReference<TextView> weakTextView;
#Override
protected String doInBackground(TextView... params) {
if(params == null||params.length=0){
return null;
}
TextView tv = (TextView)params[0];
weakTextView = new WeakReference<TextView>(tv);
//do stuff
}
#Override
protected void onPostExecute(String message) {
TextView tv = weakTextView.get();
if(tv!=null){
tv.setText(message);
}
}
}
you call this in your getView as
Process p = new Process();
p.execute(yourTextView);
//method 3
just update the underline data object of this list adapter
and call adapter.notifyDataSetChanged();
which will call getView again
this method, in most cases, is preferable to the other 2 above, unless you are displaying images from the internet

Categories