Array Adapter NotifyDataSetChanged() NullPointerException Android - java

I am adding a map to a list and then refreshing the array adapter. This was working perfectly earlier, but now that I am using an addItem() method from two different methods, it throws a NullPointer. I hope my code will clear up what I am saying:
SimpleAdapter adapter;
List<HashMap<String, String>> painItems = new ArrayList<HashMap<String, String>>();
ListView listthings;
int[] to;
String[] from;
String painLevelString, timeOfPainString, textTreatmentString,
painLocation, row1, row2, name;
OnCreate(){
if(getIntent().getStringExtra("newPainLevel")!= null){
createNewEditedEntry();
}
adapter = new SimpleAdapter(this, painItems, R.layout.mylistlayout,
from, to);
listthings.setAdapter(adapter);
}
private void createNewEditedEntry() {
String newPainLevel = this.getIntent().getStringExtra("newPainLevel");
String newPainTime =this.getIntent().getStringExtra("newPainTime");
String newTreatment =this.getIntent().getStringExtra("newTreatment");
painLevelString = newPainLevel;
timeOfPainString = newPainTime;
textTreatmentString = newTreatment;
row1 = "sample1";
row2 = "sample2";
addItem();
//painItems.remove(getIntent().getStringExtra("position"));
//adapter.notifyDataSetChanged();
}
#Override
// on the activityresult,get the string extra, then add the item to the list
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == 1) {
row1 = data.getStringExtra("com.painLogger.row1");
row2 = data.getStringExtra("com.painLogger.row2");
painLevelString = data.getStringExtra("com.painLogger.painLevel");
painLocation = data.getStringExtra("painLocation");
timeOfPainString = data.getStringExtra("com.painLogger.painTime");
textTreatmentString = data
.getStringExtra("com.painLogger.treatment");
addItem();
}
}
// to add the item, put it in the map, and add the map into the list
private void addItem() {
HashMap<String, String> map = new HashMap<String, String>();
map.put("row_1", row1);
map.put("row_2", row2);
map.put("row_3", painLevelString);
map.put("row_4", painLocation);
map.put("row_5", timeOfPainString);
map.put("row_6",textTreatmentString);
painItems.add(map);
adapter.notifyDataSetChanged(); //Null Pointer **HERE**
}
Just to be clear, createNewEditedEntry() and onActivityResult() are never called at the same time and never clash. They are two completely different occurrences. It was working with just the OnActivityResult, but now when I use CreateNewEditedEntry(), it has stopped working. I have also checked and made sure that none of the Strings that I fetch from my intent are null.

You need to initialize adapter before you call createNewEditedEntry in onCreate:
OnCreate(){
adapter = new SimpleAdapter(this, painItems, R.layout.mylistlayout, from, to);
if(getIntent().getStringExtra("newPainLevel")!= null){
createNewEditedEntry();
}
// ...
}
Otherwise, adapter will be null in addItem called from there (last line of createNewEditedEntry).

You should also be aware that your call to addItem can fail if your activity was destroyed by Android while you were in the sub-activity. Have a read of my answer to this question to understand what can happen when resources get low.

Related

Keeping list entries when I move activity

I have a ListView.
I populate this list from 2 editTexts
When I move activity and go back to it the entries are gone again.
I kind of understand why this is but dont know how to correct it.
ListView lv2 = (ListView) findViewById(R.id.listView2);
final SimpleAdapter simpleAdpt = new SimpleAdapter(this, planetsList, android.R.layout.simple_list_item_1, new String[]{"planet"}, new int[]{android.R.id.text1});
planetsList.add(createPlanet("planet", "testme"));
lv2.setAdapter(simpleAdpt);
button21.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
iinitList();
simpleAdpt.notifyDataSetChanged();
editText5.setText("");
editText6.setText("");
}
});
}
private void iinitList() {
String st,str;
Double db;
if (editText5.getText().toString()!= "" && editText6.getText().toString()!="") {
st = editText5.getText().toString();
str = editText6.getText().toString();
db = Double.parseDouble(str);
planetsList.add(createPlanet("planet", ""+st+
": \n" +db+""));
}
}
HashMap<String, String> createPlanet(String key, String name) {
HashMap<String, String> planet = new HashMap<String, String>();
planet.put(key, name);
return planet;
}
As you can see I have added a value to the list manually called test also, when I move activity this stays in the list, I would love if the editText entries were to stay in there also when I move activities.
Activities can be destroyed when you navigate to a new one or rotate. This will clear anything that is only referenced by the activity, like your EditTexts. However, Android provides a nice utility for saving things you want to remain in a method called, which you can override in your activity:
#Override
protected void onSaveInstanceState(Bundle state) {
// Put your values in the state bundle here
}
#Override
protected void onCreate(Bundle savedState) {
// Load your UI elements as usual
if (savedState != null) {
// Load your state from the bundle
}
}
That same bundle will be given back to you in onCreate, where you create your UI to begin with so you can reload the state from it.
This is a really good description of how activities work:
http://developer.android.com/reference/android/app/Activity.html

USING collections in Android

I was looking at this code while surfing through Stackoverflow
CODE::
public class MainActivity extends Activity {
// Declare Variables
JSONObject jsonobject;
JSONArray jsonarray;
ListView listview;
ListViewAdapter adapter;
ProgressDialog mProgressDialog;
ArrayList<HashMap<String, String>> arraylist;
static String NAME = "rank";
static String TYPE = "country";
static String DISTANCE = "distance";
static String RATING = "rating";
static String FLAG = "flag";
static String PRICE= "price";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the view from listview_main.xml
setContentView(R.layout.listview_main);
// Locate the listview in listview_main.xml
listview = (ListView) findViewById(R.id.listview);
// Execute DownloadJSON AsyncTask
new DownloadJSON().execute();
}
// DownloadJSON AsyncTask
private class DownloadJSON extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Create a progressdialog
mProgressDialog = new ProgressDialog(MainActivity.this);
// Set progressdialog title
//mProgressDialog.setTitle("Fetching the information");
// Set progressdialog message
mProgressDialog.setMessage("Loading...");
mProgressDialog.setIndeterminate(false);
// Show progressdialog
mProgressDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
// Create an array
arraylist = new ArrayList<HashMap<String, String>>();
// Retrieve JSON Objects from the given URL address
jsonobject = JSONfunctions.getJSONfromURL("--------------URL----------");
try {
// Locate the array name in JSON
jsonarray = jsonobject.getJSONArray("ARRAY");
for (int i = 0; i < jsonarray.length(); i++) {
HashMap<String, String> map = new HashMap<String, String>();
jsonobject = jsonarray.getJSONObject(i);
// Retrive JSON Objects
map.put(MainActivity.NAME, jsonobject.getString("collegeNAME"));
map.put(MainActivity.TYPE, jsonobject.getString("collegeTYPE"));
map.put(MainActivity.FLAG, jsonobject.getString("collegeIMAGE"));
map.put(MainActivity.DISTANCE, jsonobject.getString("collegeDISTANCE"));
map.put(MainActivity.RATING, jsonobject.getString("collegeRATING"));
map.put(MainActivity.PRICE, jsonobject.getString("collegePrice"));
// Set the JSON Objects into the array
arraylist.add(map);
}
} catch (JSONException e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void args) {
// Pass the results into ListViewAdapter.java
adapter = new ListViewAdapter(MainActivity.this, arraylist);
// Set the adapter to the ListView
listview.setAdapter(adapter);
// Close the progressdialog
mProgressDialog.dismiss();
}
}
}
My Question is Why we use collection in android ?
What is the use ?
Why a hashmap is added to ArrayList in the above code ?
Can't we directly set views in android without collection,( I tried
it dosent work when dealing with group of key,value pairs)
.
~ I am a newbie so please go easy on with answers to my questions
I'm not sure how to answer your first 2 questions about collections... but I'll give it a shot.
1, 2) Collections are good for keeping groups of information lumped together and accessible through 1 variable. They also make it very easy to iterate over them, which makes them ideal for things like ListView adapters since that is also a list (or a collection).
Consider the following if you dont have an array
String var1 = "hi1";
String var2 = "hi2";
String var3 = "hi3";
String var4 = "hi4";
String var5 = "hi5";
String var6 = "hi6";
String var7 = "hi7";
String var8 = "hi8";
String var9 = "hi9";
// do something with the variables
Toast.makeText(this, var1, Toast.LENGTH_SHORT).show();
Toast.makeText(this, var2, Toast.LENGTH_SHORT).show();
Toast.makeText(this, var3, Toast.LENGTH_SHORT).show();
Toast.makeText(this, var4, Toast.LENGTH_SHORT).show();
Toast.makeText(this, var5, Toast.LENGTH_SHORT).show();
Toast.makeText(this, var6, Toast.LENGTH_SHORT).show();
Toast.makeText(this, var7, Toast.LENGTH_SHORT).show();
Toast.makeText(this, var8, Toast.LENGTH_SHORT).show();
Toast.makeText(this, var9, Toast.LENGTH_SHORT).show();
Now consider this, if you have arrays:
ArrayList<String> vars = new ArrayList<String(9);
for (int i = 1; i <= 9; i++)
{
vars.add("hi" + i);
Toast.makeText(this, vars.get(i), Toast.LENGTH_SHORT).show();
}
Much, much easier to work with.
3) The Hashmap is added to the array because the author wanted to keep a collection of separate name/value pairs. You can't have multiple keys with the same value in a Hashmap, so if you want that then you have to make a new Hashmap. The adding them to an array was to keep it neat, and then allowed the author to pass the array to a ListView adapter for displaying the values to the user using Android's built-in mechanism.
Basically the author created this Hierarchy:
item1
name
type
flag
distance
rating
price
item2
name
type
flag
distance
rating
price
item3
name
type
flag
distance
rating
price
...etc...
So when the ListView iterated over the array, each separate collection of hashmap values will be available to a new listview item for displaying.
4) You can set values directly, but working with adapters in ListViews makes it much less of a chore. You create an array, pass the array to the listview, and bada-bing-bada-boom, there's your list. Otherwise you will be creating ListView items and setting the display text all yourself for each item. In a similar way to why collections are useful when you have many variables of the same type, passing that collection to a ListView makes it much, much easier to code, maintain, and troubleshoot, not to mention that it just works!
I hope this helps! We are all beginners once :)
This piece of code will go populate an ListView, there are several ways to do that. I believe in this case, the coder is SimpleAdapter http://developer.android.com/reference/android/widget/SimpleAdapter.html.
Some think like:
// In This case the value os NAME is shown on android.R.id.text1 (TextView)
// and PRICE is shown on android.R.id.text2 (TextView)
String[] from = new String[]{MainActivity.NAME, MainActivity.PRICE}; // Map keys
int[] to = new int[]{android.R.id.text1, android.R.id.text2}; // List Layout item views
SimpleAdapter adapter = new SimpleAdapter(context, arraylist, android.R.layout.simple_list_item_2, String[] from, int[] to);
listview.setAdapter(adapter);

Why does my ListView not display the list of items?

I am trying to display my list of alarms in the ListActivity but it does not work. There rows appear but there is no text visible. I'm not sure if it's retrieving the data from the HashMap and inserting into the rows correctly.
Here is my code:
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alarm_list);
List<Alarm> list;
Database db = new Database(AlarmListActivity.this);
list = db.getAllAlarms();
List<HashMap<String, String>> alarmMap = new ArrayList<HashMap<String, String>>();
for (Alarm alarm: list) {
HashMap<String, String> map = new HashMap<String, String>();
map.put(Integer.toString(alarm.getID()), alarm.toString());
alarmMap.add(map);
}
if(!list.isEmpty() && list != null)
{
System.out.println("inside list");
System.out.println(list);
ListAdapter adapter = new SimpleAdapter(
AlarmListActivity.this,
alarmMap,
R.layout.list_item,
new String[] { "id", "hour"},
new int[] { R.id.id, R.id.time});
setListAdapter(adapter);
}
else
{
Toast.makeText(AlarmListActivity.this, "No Alarms Set",
Toast.LENGTH_SHORT).show();
}
}
This is what I get. You can vaguely see the lines of each row. But there is no text or anything. All the System.out.println() work as expected which print out the HashMap. It's just nothing is being displayed in the list. I've even added: android:text="Testing" to no avail

Android: FastScrolling SectionIndexer getSections() is called only once

I've created a ListView which is using FastScroll. (see pic) When the user clicks any of the below Button (viz. All Tracks, Artists, Album), everytime the following custom ArrayAdater is called
ArrayAdapter<String> adapter = new ScrollIndexListAdapter(Listing.this, elements);
//Code for ScrollIndexListAdapter is below
and the same ListView is updated.
PROBLEM: According to my investigation in Android, the getSections() method is called only once (i.e. only when the first time ScrollIndexListAdapter is called).
This time the sections are populated & the fastScrolling works perfectly.
But when I update the ListView by clicking on Artists/Album, the getSections() method is not called. So the older sections are used, and the FastScrolling still shows previews of old alphabets.
So, how can I make sections get updated everytime when the ListView is updated?
There is a setSections() method, but I'm not able to find how to use it.
Code for ScrollIndexListAdapter class:
public class ScrollIndexListAdapter extends ArrayAdapter implements
SectionIndexer {
// Variables for SectionIndexer List Fast Scrolling
HashMap<String, Integer> alphaIndexer;
String[] sections;
private static ArrayList<String> list = new ArrayList<String>();
public ScrollIndexListAdapter(Context context, ArrayList<String> list) {
super(context, android.R.layout.simple_list_item_1, android.R.id.text1,
list);
this.list.clear();
this.list.addAll(list);
/*
* Setting SectionIndexer
*/
alphaIndexer = new HashMap<String, Integer>();
int size = list.size();
for (int x = 0; x < size; x++) {
String s = (String) list.get(x);
// Get the first character of the track
String ch = s.substring(0, 1);
// convert to uppercase otherwise lowercase a -z will be sorted
// after upper A-Z
ch = ch.toUpperCase();
if (!alphaIndexer.containsKey(ch)) {
alphaIndexer.put(ch, x);
}
}
Set<String> sectionLetters = alphaIndexer.keySet();
// create a list from the set to sort
ArrayList<String> sectionList = new ArrayList<String>(
sectionLetters);
Collections.sort(sectionList);
sections = new String[sectionList.size()];
sectionList.toArray(sections);
}
/*
* Methods for AphhabelIndexer for List Fast Scrolling
*/
#Override
public int getPositionForSection(int section) {
String letter = (String) sections[section];
return alphaIndexer.get(letter);
}
#Override
public int getSectionForPosition(int position) {
String letter = (String) sections[position];
return alphaIndexer.get(letter);
}
#Override
public Object[] getSections() {
return sections;
}
}
It seems that latest FastScroll version doesn't have that problem. But, in your case, there's a turn around. When setting the adapter to the ListView, disable and enable the fast scrolling. See the code below:
adapter = new ScrollIndexListAdapter(this, data);
listView.setFastScrollEnabled(false);
listView.setAdapter(adapter);
listView.setFastScrollEnabled(true);

Fatal exception caused by android.os.NetworkOnMainThreadException

As I am a beginner to Android programming, I was trying to run some tutorials, but upon running the programs( the source code is available here: http://www.androidhive.info/2012/01/android-json-parsing-tutorial/ ) I got an error.
The program is supposed to read in data from a website and process it, but I think there is something wrong with the networking part.
I am fully aware there have been similar questions here on SO, yet I had no clue how to solve it, perhaps anyone could give solutions which I also can understand.
Strange NetworkOnMainThreadException in Android app?
This is a questions which was asked earlier and is identical to my problem, but I had no clue what they are trying to say there, i.e. "To fix you just need to move any thing that is touching the network to its own thread." makes no sense to me whatsoever..
Can anyone please shed some light on this?
Use an AsyncTask to move your network operation off of the main/ui thread and onto a background/worker thread.
Expanding on the example from the tutorial, wrap the JSON stuff inside of an anonymous AsyncTask:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new AsyncTask<Void, Void, JSONObject>() {
protected JSONObject doInBackground(Void... args) {
// Creating JSON Parser instance
JSONParser jParser = new JSONParser();
// getting JSON string from URL
return jParser.getJSONFromUrl(url);
}
protected void onPostExecute(JSONObject json) {
// Hashmap for ListView
ArrayList<HashMap<String, String>> contactList = new ArrayList<HashMap<String, String>>();
try {
// Getting Array of Contacts
contacts = json.getJSONArray(TAG_CONTACTS);
// looping through All Contacts
for(int i = 0; i < contacts.length(); i++){
JSONObject c = contacts.getJSONObject(i);
// Storing each json item in variable
String id = c.getString(TAG_ID);
String name = c.getString(TAG_NAME);
String email = c.getString(TAG_EMAIL);
String address = c.getString(TAG_ADDRESS);
String gender = c.getString(TAG_GENDER);
// Phone number is agin JSON Object
JSONObject phone = c.getJSONObject(TAG_PHONE);
String mobile = phone.getString(TAG_PHONE_MOBILE);
String home = phone.getString(TAG_PHONE_HOME);
String office = phone.getString(TAG_PHONE_OFFICE);
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
// adding each child node to HashMap key => value
map.put(TAG_ID, id);
map.put(TAG_NAME, name);
map.put(TAG_EMAIL, email);
map.put(TAG_PHONE_MOBILE, mobile);
// adding HashList to ArrayList
contactList.add(map);
}
} catch (JSONException e) {
e.printStackTrace();
}
/**
* Updating parsed JSON data into ListView
* */
ListAdapter adapter = new SimpleAdapter(this, contactList,
R.layout.list_item,
new String[] { TAG_NAME, TAG_EMAIL, TAG_PHONE_MOBILE }, new int[] {
R.id.name, R.id.email, R.id.mobile });
setListAdapter(adapter);
// selecting single ListView item
ListView lv = getListView();
// Launching new screen on Selecting Single ListItem
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// getting values from selected ListItem
String name = ((TextView) view.findViewById(R.id.name)).getText().toString();
String cost = ((TextView) view.findViewById(R.id.email)).getText().toString();
String description = ((TextView) view.findViewById(R.id.mobile)).getText().toString();
// Starting new intent
Intent in = new Intent(getApplicationContext(), SingleMenuItemActivity.class);
in.putExtra(TAG_NAME, name);
in.putExtra(TAG_EMAIL, cost);
in.putExtra(TAG_PHONE_MOBILE, description);
startActivity(in);
}
});
}
}.execute((Void) null);
}

Categories

Resources