This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 7 years ago.
I have been playing around with some JSON, trying to get and display the strings to show in a custom ListView with Textviews in my app. But I'm getting an NullPointerException when running. Can somebody tell me where I'm making a mistake and point me to a right direction maybe.
This is the JSON:
[{"id":"1","client_id":"1","client_name":"Company A"},{"id":"2","client_id":"2","client_name":"Company B"}]
this is the Model class:
public class Model {
private String client_name;
public String getClient_name() {
return client_name;
}
public void setClient_name(String client_name) {
this.client_name = client_name;
}
}
Wrap class:
public class Wrap {
private ArrayList<Model> models;
public ArrayList<Model> getModels() {
return models;
}
public void setModels(ArrayList<Model> models) {
this.models = models;
}
}
this is my Adapter:
public class Adapter extends ArrayAdapter<Model> {
public Adapter(Context context, int resource) {
super(context, resource);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.listview_item, null);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
final Model p = getItem(position);
viewHolder.textone.setText(p.getClient_name());
return convertView;
}
}
The ViewHolder :
public class ViewHolder {
public TextView textone;
public ViewHolder(View convertView)
{
textone = (TextView)convertView.findViewById(R.id.txt_field);
}
}
The url:
private static final String SO_URL = "http://www.example.com/webservice/?value";
private static final String PARAMS = "[{\"table\":\"locations\",\"operation\":\"select\"}]";
This is the AsyncTask's doInBackground method :
protected String doInBackground(Void... params) {
try {
//Create an HTTP client
String URL = URLEncoder.encode(PARAMS, "UTF-8");
HttpClient client = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(SO_URL + URL);
//Perform the request and check the status code
HttpResponse response = client.execute(httpPost);
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
try {
//Read the server response and attempt to parse it as JSON
Reader reader = new InputStreamReader(content);
Wrap wrap = new Gson().fromJson(reader,Wrap.class);
for (Model model : wrap.getModels()) {
adapter.add(model);
}
adapter.notifyDataSetChanged();
content.close();
} catch (Exception ex) {
Log.e(TAG, "Failed to parse JSON due to: " + ex);
failedLoadingPosts();
}
} else {
Log.e(TAG, "Server responded with status code: " + statusLine.getStatusCode());
failedLoadingPosts();
}
} catch(Exception ex) {
Log.e(TAG, "Failed to send HTTP POST request due to: " + ex);
failedLoadingPosts();
}
return null;
I'm getting this exception msg :
Failed to parse JSON due to: java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.ArrayList com.bloomcore.dbnewapp.Wrap.getModels()' on a null object reference
OK, let's work through this logically...
When you get the exception you are seeing it is as a result of...
for (Model model : wrap.getModels()) {
...quite simply wrap is null, trying to call any method on a null object will through a NPE - no arguing about that - you didn't even need to show any other code to figure that one out.
So why is wrap null? Let's look at where it's instantiated (or at least where it SHOULD be)...
Wrap wrap = new Gson().fromJson(reader,Wrap.class);
...so if after calling new Gson().fromJson(...) then wrap turns out to be null, why is that? Well obviously fromJson(...) is returning null.
So, assuming you've read the documentation for fromJson(...) (which I suspect you might not have done), when using a Reader, from the docs...
Returns:
an object of type T from the string. Returns null if json is at EOF.
...it seems your Reader is at EOF. So why would that be?
Basically the HttpResponse doesn't have an HttpEntity with any valid content. Either your server simply isn't returning anything full stop OR the HttpPost doesn't contain valid data in order for the server to return anything valid.
In other words, check your server code and if that's fine, check what you're posting.
You should make sure getModels() is not null when the Object is created. Some Json parsers only use lists but never create them.
private ArrayList<Model> models = new ArrayList<>();
I assume it's trying to add elements to the list which is null.
Related
I have a problem populating separate TextView with the content from the same JSON.
Each fragment is having a ListView populated by adapter. Data is pulled from JSON file. First, I am importing data from JSONArray and adding it to object Article created separately:
JSONObject e = articlesJsonResponse.getJSONObject(i);
String title = e.getString("title");
int itemId = e.getInt("id");
Article article = new Article(title, itemId);
articles.add(article);
Then, I have created ArticleAdapter where I am putting this content into ListView. This works.
In my Activity, I am then creating a list out of that:
ListView mainListView = (ListView) findViewById(R.id.main_list);
mAdapter = new ArticleAdapter (getActivity(), new ArrayList<Article>());
mainListView.setAdapter(mAdapter);
Now, I would like to create a TextView in the same activity, which would pull "title" from the first object Article in the list.
TextView featuredImageTitle = (TextView) findViewById(R.id.featuredimage_title);
featuredImageTitle.setText(??????????);
Should I pass this info from adapter? Or from Article object? Or should I read it from the 0 position in the list I have built for the ListView?
Here is my full code which imports the content and creates the object.
public final class QueryUtils {
public QueryUtils() {
}
// Returns new URL object from the URL String
private static URL createUrl(String stringUrl) {
URL url = null;
try {
url = new URL(stringUrl);
} catch (MalformedURLException e) {
Log.e(LOG_TAG, "Problem building URL", e);
}
return url;
}
// makes a HTTP request to the URL and returns String
private static String makeHttpRequest(URL url) throws IOException {
String jsonResponse = "";
// If the URL is null, then return early.
if (url == null) {
return jsonResponse;
}
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /* milliseconds */);
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// If the request was successful (response code 200),
// then read the input stream and parse the response.
if (urlConnection.getResponseCode() == 200) {
inputStream = urlConnection.getInputStream();
jsonResponse = readFromStream(inputStream);
} else {
Log.e(LOG_TAG, "Error response code: " + urlConnection.getResponseCode());
}
} catch (IOException e) {
Log.e(LOG_TAG, "Problem retrieving articles JSON.", e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (inputStream != null) {
// Closing the input stream could throw an IOException, which is why
// the makeHttpRequest(URL url) method signature specifies than an IOException
// could be thrown.
inputStream.close();
}
}
return jsonResponse;
}
// Query the JSON info and return a list of {#link Article} objects.
public static List<Article> extractArticles(String requestUrl) {
// Create URL object
URL url = createUrl(requestUrl);
// Perform HTTP request to the URL and receive a JSON response back
String jsonResponse = null;
try {
jsonResponse = makeHttpRequest(url);
} catch (IOException e) {
Log.e(LOG_TAG, "Problem making the HTTP request.", e);
}
List<Article> articles = extractFromJson(jsonResponse);
// Return the list of articles
return articles;
}
/**
* Convert the {#link InputStream} into a String which contains the
* whole JSON response from the server.
*/
private static String readFromStream(InputStream inputStream) throws IOException {
StringBuilder output = new StringBuilder();
if (inputStream != null) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
BufferedReader reader = new BufferedReader(inputStreamReader);
String line = reader.readLine();
while (line != null) {
output.append(line);
line = reader.readLine();
}
}
return output.toString();
}
/**
* Return a list of {#link Article} objects that has been built up from
* parsing a JSON response.
*/
public static List<Article> extractFromJson(String articleJSON) {
// If the JSON string is empty or null, then return early.
if (TextUtils.isEmpty(articleJSON)) {
return null;
}
// Create an empty ArrayList that we can start adding earthquakes to
List<Article> articles = new ArrayList<>();
// Try to parse JSON response. If there's a problem with the way the JSON
// is formatted, a JSONException exception object will be thrown.
// Catch the exception so the app doesn't crash, and print the error message to the logs.
try {
// Create a JSONArray from the JSON response string
JSONArray articlesJsonResponse = new JSONArray(articleJSON);
// For each article in the articleArray, create an Article object
for (int i=0; i < articlesJsonResponse.length(); i++) {
// Parse the response given by the json string and
// build up a list of article objects with the corresponding data.
JSONObject e = articlesJsonResponse.getJSONObject(i);
String title = e.getString("title");
int articleId = e.getInt("id");
int views = e.getInt("views");
int comments = e.getInt("comments");
String thumb = e.getString("image");
String url = e.getString("url");
String date = e.getString("date");
Article article = new Article(title, articleId, views, comments, thumb, url, date);
articles.add(article);
}
} catch (JSONException e) {
// If an error is thrown when executing any of the above statements in the "try" block,
// catch the exception here, so the app doesn't crash. Print a log message
// with the message from the exception.
Log.e("QueryUtils", "Problem parsing JSON results", e);
}
// Return the list of articles
return articles;
}
}
If you need to access only the first object title on the list
get the 0 positions of your list but also check if list size > 0 to not give Index exception
like
if(articles.size > 0){
featuredImageTitle.setText(articles.get(0).getTitle)
}
but if you need to get the title from the clicked object in the list you need to implement OnItemClickListener to you listView
mainListView.setOnItemClickListener(new OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> arg0, View arg1,int position, long arg3)
{
featuredImageTitle.setText(articles.get(position).getTitle);
}
and be sure to set android:descendantFocusability="blocksDescendants" on the first parent layout inside the list
Before this post I have not found a post for my issue to be helpful for me.
First, I'm building a very simple android application that should connect to database (MySQL) to load foods data (food name) into ListView with count of food listed.
DB : db_food_resto
Table :
#id_row : int autoincrement primary key.
food_name : varchar 255 not null
food_country : varchar 255 not null //till now i don't need this column maybe in the future this way i added this.
I'm using eclipse with Genymontion emulator all things are great with no error compiler no exception thrown and work fine on emulator when I test it on cell phone the list of food not loaded however its loading on tablet!
I'm using asynctask to get the data I don't know why its not working on cell phone and working on tablet.
I have beat my head on this problem for days.
This is my code with some modifications to let it a little bit shorter.
public class HistoryActivity extends Activity
{
static ArrayList arr = new ArrayList<>(); // Info is a class contain a food name attribute and one constructor with one argument foodname
ListView historylistfood;
LayoutInflater mInflater;
TextView foodcount;
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
...
...
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) {
new Tasklist().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"load_all");
}
else {
new Tasklist().execute("load_all");
}
}
class Tasklist extends AsyncTask<String, String, String>
{
#Override
protected String doInBackground(String... params)
{
StringBuffer sb = null;
try
{
String link="mydomain.com/file.php?type="+params[0];
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(link);
HttpResponse response = httpclient.execute(httppost);
BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
sb = new StringBuffer("");
String line="";
while ((line = in.readLine()) != null)
{
sb.append(line);
//sb is a list of foods gotten from PHP file seperated with |
//something like that: food name 1|food name 2|food name 3|ABC|
//then i break the loop
break;
}
in.close();
getlistfood(sb.toString());
} catch(Exception e){
e.printStackTrace() ;
}
return null;
}
#Override
protected void onPostExecute(String result)
{
// TODO Auto-generated method stub
super.onPostExecute(result);
if(arr.size()>0)
{
ArrayAdapter<Info> adapter = new HArrayAdapter();
historylistfood.setAdapter(adapter);
Toast.makeText(getApplicationContext(), "On post exectue", Toast.LENGTH_LONG).show();
foodcount.setVisibility(View.VISIBLE);
foodcount.setText(""+arr.size());
foodcount.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(), R.anim.movecount));
}
else
{
Toast.makeText(getApplicationContext(), "Intenet issue.", Toast.LENGTH_LONG).show(); // this is what cell phones showed
}
}
}
public void getlistfood(String st) {
arr = new ArrayList<>();
String[] spl = st.toString().split("|");
for(int i=0;i<spl.length;i++)
{ Info i = new Info(spl[i]);
arr.add(i);
}
}
public class HArrayAdapter extends ArrayAdapter<Info>
{
public HArrayAdapter() {
super(HistoryActivity.this,R.layout.activity_item,arr);
}
public View getView(int position, View convertView, ViewGroup parent)
{
View itemv = convertView;
Info poo = arr.get(position);
if(itemv== null)
{
itemv = mInflater.inflate(R.layout.activity_item, parent,false);
}
TextView foodname = (TextView)itemv.findViewById(R.id.food);
foodname.setText(poo.getFoodname());
return itemv;
}
}
}
I'm doing and app who calls the same method two times and the second time I call the method it doesn't execute the line with HttResponse.
Here is the AsyncTask where everything starts:
private class FetchSubjectsTask extends AsyncTask<String, Void, List<Subject>> {
private ProgressDialog pd;
#Override
protected List<Subject> doInBackground(String... params) {
List<Subject> subjects = null;
try {
subjects = api.getMySubjects(params[0]);
} catch (Exception e) {
e.printStackTrace();
}
return subjects;
}
#Override
protected void onPostExecute(List<Subject> result) {
printSubjects(result);
if (pd != null) {
pd.dismiss();
}
}
}
Then I get the subjects through the method getMySubjects which is:
public List<Subject> getMySubjects(String username) {
List<Subject> subjects = new ArrayList<Subject>();
java.lang.reflect.Type arrayListType = new TypeToken<ArrayList<Subject>>() {
}.getType();
String url = BASE_URL_VM + "users/" + username + "/subjects";
HttpClient httpClient = WebServiceUtils.getHttpClient();
try {
System.out.println("inside try");
HttpResponse response = httpClient.execute(new HttpGet(url));
System.out.println("response executed");
HttpEntity entity = response.getEntity();
Reader reader = new InputStreamReader(entity.getContent());
subjects = gson.fromJson(reader, arrayListType);
} catch (Exception e) {
}
System.out.println("Array lenght " +subjects.size());
return subjects;
}
That's the first time HttpResponse executes and I get the "response executed" and "Array lenght 2" which are the number of subjects that user (username) has in the database.
The problem is when in onPostExecute I call the method printSubjects which is:
private void printSubjects(List<Subject> subjects){
adapter = new SubjectAdapter(this,(ArrayList<Subject>)subjects, (String) getIntent().getExtras().get("username"));
setListAdapter(adapter);
adapter.notifyDataSetChanged();
}
This calls the SubjectAdapter which prints the Subjects in a ListView:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder viewHolder = null;
if (convertView == null) {
convertView = inflater.inflate(R.layout.subject_detail, null);
viewHolder = new ViewHolder();
viewHolder.tvsubject = (TextView) convertView
.findViewById(R.id.tvsubject);
boolean match = api.checkMySubjects(username, data.get(position).getId());
Button addButton = (Button) convertView.findViewById(R.id.bAdd);
if(match){
addButton.setText("Delete");
}else{
addButton.setText("Add");
}
String content = data.get(position).getName();
viewHolder.tvsubject.setText(content);
}
return convertView;
}
private static class ViewHolder {
TextView tvsubject;
TextView tvauthor;
}
There I call the method checkMySubjects which calls again getMySubjects to compare.
public boolean checkMySubjects(String username, String id) {
List<Subject> mySubjects = getMySubjects(username);
boolean match = false;
for (Subject s1 : mySubjects) {
if (s1.getId().equals(id)) {
match = true;
}
}
return match;
}
But now the method getMySubjects doesn't arrive until "Response executed" and the Array lenght is 0. It only shows "Inside try".
Why? I'm calling the same method with the same URL but first time I get the 2 subjects in the array and the second time I get nothing because HttResponse doesn't execute.
Thank you!
It's hard to say what's happening, but I'd like to point out what I think it's wrong. First, let's state the fact thatgetMySubjects performs a network operation, now, the first time you call it, it is called from within an AsyncTask on a thread other than the UI thread. This is perfectly fine
Then you call printSubjects in onPostExecute which populates a ListView with the results...
private void printSubjects(List<Subject> subjects){
adapter = new SubjectAdapter(this,(ArrayList<Subject>)subjects, (String) getIntent().getExtras().get("username"));
setListAdapter(adapter);
adapter.notifyDataSetChanged();
}
Now, the problem is in your getView implementation of the adapter. More specifically here...
boolean match = api.checkMySubjects(username, data.get(position).getId());
this is terribly bad because you are making a network connection on the UI thread everytime you inflate a ListView item, so if you had ten items you will be making a network connection ten times (plus everytime you you scroll up and/or down the list).
Moreover, Android complains with a FATAL exception if you attempt to make a network connection on the UI thread. You're not even noticing because you are not doing anything with this exception...
try {
System.out.println("inside try");
HttpResponse response = httpClient.execute(new HttpGet(url));
System.out.println("response executed");
HttpEntity entity = response.getEntity();
Reader reader = new InputStreamReader(entity.getContent());
subjects = gson.fromJson(reader, arrayListType);
} catch (Exception e) {
}
the catch block is empty, if you print it to the LogCat you'll see the details
Suggestion
Don't make a network connection on the UI thread...you can't
On getView instead of making a network connection for every single iteration, eagerly load the data in memory before you set the ListView
Again, the offending line of code is...
boolean match = api.checkMySubjects(username, data.get(position).getId());
in getView
I have a ProgressDialog that retrieves in background data from database by executing php script.
I'm using gson Google library. php script is working well when executed from browser:
{"surveys":[{"id_survey":"1","question_survey":"Are you happy with the actual government?","answer_yes":"50","answer_no":"20"}],"success":1}
However, ProgressDialog background treatment is not working well:
#Override
protected Void doInBackground(Void... params) {
String url = "http://192.168.1.4/tn_surveys/get_all_surveys.php";
HttpGet getRequest = new HttpGet(url);
Log.d("GETREQUEST",getRequest.toString());
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
Log.d("URL1",url);
HttpResponse getResponse = httpClient.execute(getRequest);
Log.d("GETRESPONSE",getResponse.toString());
final int statusCode = getResponse.getStatusLine().getStatusCode();
Log.d("STATUSCODE",Integer.toString(statusCode));
Log.d("HTTPSTATUSOK",Integer.toString(HttpStatus.SC_OK));
if (statusCode != HttpStatus.SC_OK) {
Log.w(getClass().getSimpleName(), "Error " + statusCode + " for URL " + url);
return null;
}
HttpEntity getResponseEntity = getResponse.getEntity();
Log.d("RESPONSEENTITY",getResponseEntity.toString());
InputStream httpResponseStream = getResponseEntity.getContent();
Log.d("HTTPRESPONSESTREAM",httpResponseStream.toString());
Reader inputStreamReader = new InputStreamReader(httpResponseStream);
Gson gson = new Gson();
this.response = gson.fromJson(inputStreamReader, Response.class);
}
catch (IOException e) {
getRequest.abort();
Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Log.d("HELLO","HELLO");
StringBuilder builder = new StringBuilder();
Log.d("STRINGBUILDER","STRINGBUILDER");
for (Survey survey : this.response.data) {
String x= survey.getQuestion_survey();
Log.d("QUESTION",x);
builder.append(String.format("<br>ID Survey: <b>%s</b><br> <br>Question: <b>%s</b><br> <br>Answer YES: <b>%s</b><br> <br>Answer NO: <b>%s</b><br><br><br>", survey.getId_survey(), survey.getQuestion_survey(),survey.getAnswer_yes(),survey.getAnswer_no()));
}
Log.d("OUT FOR","OUT");
capitalTextView.setText(Html.fromHtml(builder.toString()));
progressDialog.cancel();
}
HELLO Log is displayed.
STRINGBUILDER Log is displayed.
QUESTION Log is NOT displayed.
OUT FOR Log is displayed.
Survey Class:
public class Survey {
int id_survey;
String question_survey;
int answer_yes;
int answer_no;
public Survey() {
this.id_survey = 0;
this.question_survey = "";
this.answer_yes=0;
this.answer_no=0;
}
public int getId_survey() {
return id_survey;
}
public String getQuestion_survey() {
return question_survey;
}
public int getAnswer_yes() {
return answer_yes;
}
public int getAnswer_no() {
return answer_no;
}
}
Response Class:
public class Response {
ArrayList<Survey> data;
public Response() {
data = new ArrayList<Survey>();
}
}
Any help please concerning WHY the FOR loop is not executed.
Thank you for helping.
Any help please concerning WHY the FOR loop is not executed.
Simply put: data is empty. (So there is nothing for the loop to iterate over...)
Try something like this, from GSON's documentation:
Type listType = new TypeToken<List<String>>() {}.getType();
List<String> target = new LinkedList<String>();
target.add("blah");
Gson gson = new Gson();
String json = gson.toJson(target, listType);
List<String> target2 = gson.fromJson(json, listType);
I haven't used GSON myself, but there are other examples of how to read lists:
Android gson deserialization into list
GSON : custom object deserialization
Your onPostExecute takes in a parameter called result. Your for loop iterates over the elements in an instance variable called response. Are they supposed to be the same?
I'm trying to add an animation to my ListView so text will fade into separate rows as results come in from an HTTP GET request. I know how to do the fade in effect and i already have a custom ListView adapter but the problem is that the ListView updates all the rows each time a result comes in, thus triggering the fade in effect each time for the entire list.
How would I be able to control a single row so the ListView won't animate every row on each data change?
This is the code i use to fill the ListView:
private class CustomAdapter extends ArrayAdapter<Row> {
public CustomAdapter() {
super(Results.this, R.layout.row, dataList);
}
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
RowHolder holder = null;
if (row == null) {
LayoutInflater inflater = getLayoutInflater();
row = inflater.inflate(R.layout.row, parent, false);
holder = new RowHolder(row);
row.setTag(holder);
} else {
holder = (RowHolder) row.getTag();
}
try {
holder.populateRow(dataList.get(position));
} catch (NullPointerException e) {
e.printStackTrace();
}
return row;
}
}
private class RowHolder {
private TextView label = null;
private TextView count = null;
private TextView result = null;
public RowHolder(View row) {
label = (TextView) row.findViewById(R.id.list_label);
count = (TextView) row.findViewById(R.id.list_count);
result = (TextView) row.findViewById(R.id.list_result);
}
public void populateRow(Row r) {
label.setText(r.getLabel());
count.setText(r.getCount());
result.setText(r.getResult());
label.startAnimation(fadeIn);
count.startAnimation(fadeIn);
result.startAnimation(fadeIn);
}
}
Any help is appreciated, thank you in advance!
Edit 1:
My AsyncTask:
private class CheckSource extends AsyncTask<String, Void, String> {
protected void onPreExecute() {
results.setUnixTime(getUnixTime());
results.setLabel(getString(R.string.label));
results.setCount(null);
results.setResult(null);
results.setResultLabel("");
results.setShowProgress(true);
results.setIconType(null);
results.setShowIcon(false);
results.setHasResults(false);
adapter.notifyDataSetChanged();
}
#Override
protected String doInBackground(String... params) {
String query = params[0];
String httpResults = null;
try {
httpResults = getResults(query, "source");
jsonObject = new JSONObject(httpResults);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
return httpResults;
}
protected void onPostExecute(String results) {
try {
parseJSON(results);
} catch (JSONException e) {
e.printStackTrace();
results.setResultLabel("<br />"
+ getString(R.string.source_not_available) + "<br />");
}
results.setShowProgress(false);
adapter.notifyDataSetChanged();
}
// Parse the retrieved json results
private void parseJSON(String jsonResults) throws JSONException {
if (jsonResults == null) {
results.setResult(null);
results.setHasResults(false);
results.setResultLabel("<br />"
+ getString(R.string.source_not_available) + "<br />");
return;
}
jsonObject = new JSONObject(jsonResults);
String result = null;
String resultLabel = null;
switch (jsonObject.getInt("count")) {
case -1:
results.setCount(null);
results.setHasResults(false);
resultLabel = getString(R.string.no_results);
break;
case 0:
results.setCount(null);
results.setHasResults(false);
resultLabel = getString(R.string.no_results);
break;
case 1:
results.setHasResults(true);
results.setCount(jsonObject.get("count").toString() + " "
+ getString(R.string.one_result));
result = jsonObject.get("url").toString();
resultLabel = getString(R.string.hyperlink_text);
break;
default:
results.setHasResults(true);
results.setCount(jsonObject.get("count").toString() + " "
+ getString(R.string.multiple_results));
result = jsonObject.get("url").toString();
resultLabel = getString(R.string.hyperlink_text);
break;
}
results.setResult(result);
results.setResultLabel("<br />" + resultLabel + "<br />");
}
}
The method that executes the HTTP request:
private String getResults(String query, String source)
throws IllegalStateException, IOException, URISyntaxException {
/* Method variables */
StringBuilder builder = new StringBuilder();
String URL = "url";
URI uri;
String phrase = "phrase";
List<NameValuePair> params = new ArrayList<NameValuePair>();
/* HTTP variables */
HttpGet httpGet;
DefaultHttpClient httpClient;
HttpResponse httpResponse;
HttpEntity httpEntity;
HttpParams httpParams;
int socketTimeout = 10000;
int connectionTimeout = 10000;
// Set the socket and connection timeout values
httpParams = new BasicHttpParams();
HttpConnectionParams
.setConnectionTimeout(httpParams, connectionTimeout);
HttpConnectionParams.setSoTimeout(httpParams, socketTimeout);
httpClient = new DefaultHttpClient(httpParams);
// Add parameters to the GET request
params.add(new BasicNameValuePair("query", query));
params.add(new BasicNameValuePair("type", source));
String paramString = URLEncodedUtils.format(params, "utf-8");
uri = new URI(URL + paramString);
httpGet = new HttpGet(uri);
// Execute the GET request
httpResponse = httpClient.execute(httpGet);
/* Read http response if http status = 200 */
if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
httpEntity = httpResponse.getEntity();
InputStream content = httpEntity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(
content));
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
}
return builder.toString();
}
As Romain Guy explained a while back during the Google I/O session, the most efficient way to only update one view in a list view is something like the following (this one update the whole view data):
ListView list = getListView();
int start = list.getFirstVisiblePosition();
for(int i=start, j=list.getLastVisiblePosition();i<=j;i++)
if(target==list.getItemAtPosition(i)){
View view = list.getChildAt(i-start);
list.getAdapter().getView(i, view, list);
break;
}
Assuming target is one item of the adapter.
This code retrieve the ListView, then browse the currently shown views, compare the target item you are looking for with each displayed view items, and if your target is among those, get the enclosing view and execute the adapter getView on that view to refresh the display.
As a side note invalidate doesn't work like some people expect and will not refresh the view like getView does, notifyDataSetChanged will rebuild the whole list and end up calling getview for every displayed items and invalidateViews will also affect a bunch.
One last thing, one can also get extra performance if he only needs to change a child of a row view and not the whole row like getView does. In that case, the following code can replace list.getAdapter().getView(i, view, list); (example to change a TextView text):
((TextView)view.findViewById(R.id.myid)).setText("some new text");
In code we trust.
Method notifyDataSetChanged force to call getView method to all visible elements of the ListView. If you want update only 1 specific item of the ListView you need to path this item to the AsynhTask.