chility
chility

Reputation: 744

Can't update/redraw listView inside of onPostExecute

I have this code:

package com.gs.britishjokes;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

import org.json.JSONArray;
import org.json.JSONException;

import android.app.Activity;
import android.app.Application;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;


public class TopJokes extends Activity {

    public static class Globals extends Application{
           String[] myStringArray = {"a","b","c","a","b","c","a","b","c","a","b","c","a","b","c","a","b","c"};

        public String[] getMyStringArray() {
            return myStringArray;
        }

        public void setMyStringArray(String[] myStringArray) {
            this.myStringArray = myStringArray;
        }

    }

    public static ArrayAdapter<String> adapter;
    public static ListView listView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_top_jokes);        

        Globals globals = (Globals)getApplication();

        new loadJson().execute();

        adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, globals.getMyStringArray());

        listView = (ListView) findViewById(R.id.topJokesList);
        listView.setAdapter(adapter);

        listView.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                // When clicked, show a toast with the TextView text
                Toast.makeText(getApplicationContext(),
                ((TextView) view).getText(), Toast.LENGTH_SHORT).show();
            }
        });

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.top_jokes, menu);
        return true;
    }

    public class loadJson extends AsyncTask<Void, Integer, String>{
        @Override
        protected String doInBackground(Void... params) {
            URL u;
            StringBuffer buffer = new StringBuffer();
            try {
                u = new URL("https://site.com/android/britishJokes/showJokes.php");
                URLConnection conn = u.openConnection();
                BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));

                String inputLine;
                while ((inputLine = in.readLine()) != null) 
                    buffer.append(inputLine);
                in.close();         
            }catch(Exception e){
                e.printStackTrace();
            }
            return buffer.toString();
        }

        protected void onPostExecute(String buffer) {
            Globals globals = (Globals)getApplication();
            JSONArray jsonArray = new JSONArray();
            String[] newJokes = {};
            String[] myStringArray = {"co","ao","bo","co","ao","bo","co","ao","bo","co"};
            try {
                jsonArray = new JSONArray(buffer);
            } catch (JSONException e) {
                e.printStackTrace();
            }

            for (int i = 0; i < jsonArray.length(); i++) {
                try {                   
                    newJokes[i] = jsonArray.getJSONObject(i).toString();
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
            globals.setMyStringArray(myStringArray);
            System.out.println("GLOBAL ARRAY: " + globals.getMyStringArray());

            adapter.notifyDataSetChanged();
//          listView.invalidate();
//          listView.destroyDrawingCache();
//          listView.setVisibility(ListView.INVISIBLE);
//          listView.setVisibility(ListView.VISIBLE);

            //listView.invalidateViews();

         }

    }
}

I'm trying to update my listView inside of onPostExecute with the code below(also can be found in the above code block)

adapter.notifyDataSetChanged();
//          listView.invalidate();
//          listView.destroyDrawingCache();
//          listView.setVisibility(ListView.INVISIBLE);
//          listView.setVisibility(ListView.VISIBLE);

            //listView.invalidateViews();

The commented lines are things that I have tried without any success.

What I have noticed is that the code is running correctly, but the listView is not getting updated. If I press the back butoon and then open the same activity again, I can see the correct results myStringArray, but how can I update the listView once the asyncTask is complete? There should be a way to do it. I know that I'm missing something really small, but as a total beginner, I'm unable to spot it. Please, give me a clue

EDIT:

catlog exceptions after adding

adapter.clear();
adapter.addAll(myStringArray);

02-10 13:50:09.594: E/AndroidRuntime(1460): FATAL EXCEPTION: main
02-10 13:50:09.594: E/AndroidRuntime(1460): Process: com.gs.britishjokes, PID: 1460
02-10 13:50:09.594: E/AndroidRuntime(1460): java.lang.UnsupportedOperationException
02-10 13:50:09.594: E/AndroidRuntime(1460):     at java.util.AbstractList.remove(AbstractList.java:638)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at java.util.AbstractList$SimpleListIterator.remove(AbstractList.java:75)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at java.util.AbstractList.removeRange(AbstractList.java:658)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at java.util.AbstractList.clear(AbstractList.java:466)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at android.widget.ArrayAdapter.clear(ArrayAdapter.java:258)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at com.gs.britishjokes.TopJokes$loadJson.onPostExecute(TopJokes.java:114)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at com.gs.britishjokes.TopJokes$loadJson.onPostExecute(TopJokes.java:1)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at android.os.AsyncTask.finish(AsyncTask.java:632)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at android.os.AsyncTask.access$600(AsyncTask.java:177)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at android.os.Handler.dispatchMessage(Handler.java:102)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at android.os.Looper.loop(Looper.java:137)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at android.app.ActivityThread.main(ActivityThread.java:4998)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at java.lang.reflect.Method.invokeNative(Native Method)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at java.lang.reflect.Method.invoke(Method.java:515)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
02-10 13:50:09.594: E/AndroidRuntime(1460):     at dalvik.system.NativeStart.main(Native Method)

Upvotes: 2

Views: 1250

Answers (4)

TouchBoarder
TouchBoarder

Reputation: 6492

Make sure to initialize the ArrayAdapter with a type of array list that supports the method clear() and add() on the ArrayAdapter, if you initialize it with a String[] it will not!

to fix this do the following:

String[] stringArray = {"item_1","Item_2"}
//IMPORTANT!
List<String> listArray = new ArrayList<String>(Arrays.asList(stringArray));
//Then initialize the ArrayAdapter with the List array
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,listArray);
listView.setAdapter(adapter);

Upvotes: 0

Manmohan Badaya
Manmohan Badaya

Reputation: 2336

For your work done, i can suggest a soln in which remove it from and paste with/instead of this line.

 listView.setAdapter(adapter);
 listView.notifyDataSetChanged;

For an ArrayAdapter, notifyDataSetChanged only works if you use the add, insert, remove, and clear functions on the Adapter. as per this link notifyDataSetChanged example

Edit

  package com.example.testandroid;

  import java.io.BufferedReader;
  import java.io.InputStreamReader;
  import java.net.URL;
  import java.net.URLConnection;

  import org.json.JSONArray;
  import org.json.JSONException;

  import android.os.AsyncTask;
  import android.os.Bundle;
  import android.provider.ContactsContract;
  import android.app.Activity;
  import android.app.Application;
  import android.content.res.Resources;
  import android.database.Cursor;
  import android.view.Menu;
  import android.view.View;
  import android.widget.AdapterView;
  import android.widget.AdapterView.OnItemClickListener;
  import android.widget.ArrayAdapter;
  import android.widget.ImageButton;
  import android.widget.ImageView.ScaleType;
  import android.widget.LinearLayout;
  import android.widget.ListView;
  import android.widget.Toast;

  public class MainActivity extends Activity {

public static class Globals {
    String[] myStringArray = { "a", "b", "c", "a", "b", "c", "a", "b", "c",
            "a", "b", "c", "a", "b", "c", "a", "b", "c" };

    public String[] getMyStringArray() {
        return myStringArray;
    }

    public void setMyStringArray(String[] myStringArray) {
        this.myStringArray = myStringArray;
    }

}

public static ArrayAdapter<String> adapter;
public static ListView listView;
Globals globals;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    globals = new Globals();
    new loadJson().execute();

    listView = (ListView) findViewById(R.id.mylist);
    adapter = new ArrayAdapter<String>(MainActivity.this,
            android.R.layout.simple_list_item_1, globals.getMyStringArray());

    listView.setAdapter(adapter);
    listView.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) {
            // When clicked, show a toast with the TextView text
            Toast.makeText(getApplicationContext(), view + "",
                    Toast.LENGTH_SHORT).show();
        }
    });

}

public class loadJson extends AsyncTask<Void, Integer, String> {
    @Override
    protected String doInBackground(Void... params) {
        URL u;
        StringBuffer buffer = new StringBuffer();
        try {
            u = new URL(
                    "https://gelasoft.com/android/britishJokes/showJokes.php");
            URLConnection conn = u.openConnection();
            BufferedReader in = new BufferedReader(new InputStreamReader(
                    conn.getInputStream()));

            String inputLine;
            while ((inputLine = in.readLine()) != null)
                buffer.append(inputLine);
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return buffer.toString();
    }

    protected void onPostExecute(String buffer) {

        String[] myStringArray = { "co", "ao", "bo", "co", "ao", "bo",
                "co", "ao", "bo", "co" };

        globals.setMyStringArray(myStringArray);
        System.out.println("GLOBAL ARRAY: " + globals.getMyStringArray());

        adapter = new ArrayAdapter<String>(MainActivity.this,
                android.R.layout.simple_list_item_1,
                globals.getMyStringArray());
        adapter.notifyDataSetChanged();
        listView.setAdapter(adapter);
        // listView.invalidate();
        // listView.destroyDrawingCache();
        // listView.setVisibility(ListView.INVISIBLE);
        // listView.setVisibility(ListView.VISIBLE);

        // listView.invalidateViews();

    }

}
 }

Upvotes: 0

vipul mittal
vipul mittal

Reputation: 17401

do the following:

 adapter.clear();
 adapter.addAll(myStringArray);

if below API 11:

do following:

 adapter.clear();
 for(String s:myStringArray){
     adapter.add(s);
 }
 adapter.notifyDataSetChanged();

the thing is when you call

  globals.setMyStringArray(myStringArray);

you are change the array globals string array is pointing at but not the one adapter is pointing at.

lets say A and B are the array before and after respectively. initially:

globals array------->A

when you create adapter:

adapter------------->A

but when you call setMyStringArray again you do:

globals array------>B

EDIT

change:

adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, globals.getMyStringArray());

to:

 adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new ArrayList<String>());
 adapter.clear();
 adapter.addAll(globals.getMyStringArray());

Upvotes: 5

Nick Cardoso
Nick Cardoso

Reputation: 21753

adapter.notifyDataSetChanged(); which you've already called will do the invalidate (etc.) for you so it is not necessary, what you seem to have neglected is to set the new data into the adapter beforehand. Something like adapter.addAll(globals); or register an observer on the data you are changing (when you create the adapter)

Upvotes: 1

Related Questions