无法在onPostExecute内更新/重绘listView

时间:2014-02-10 18:32:24

标签: java android android-asynctask android-activity

我有这段代码:

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();

         }

    }
}

我正在尝试使用以下代码更新listView内的onPostExecute(也可以在上面的代码块中找到)

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

            //listView.invalidateViews();

注释的行是我尝试过的没有任何成功的事情。

我注意到代码运行正常,但listView没有更新。如果我按下后面的按钮然后再次打开相同的活动,我可以看到正确的结果myStringArray,但是如果asyncTask完成后如何更新listView?应该有办法做到这一点。我知道我错过了一些非常小的东西,但作为一个初学者,我无法发现它。请给我一个线索

修改

添加

catlog异常

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)

4 个答案:

答案 0 :(得分:5)

执行以下操作:

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

如果低于API 11:

执行以下操作:

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

当你打电话时

  globals.setMyStringArray(myStringArray);

你是更改数组全局字符串数组指向但不是一个适配器指向。

假设A和B分别是前后的数组。 最初:

全局数组-------&gt; A

创建适配器时:

适配器-------------&gt;一种

但是当你再次调用setMyStringArray时,你会这样做:

全局数组------&gt; B

修改

变化:

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

为:

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

答案 1 :(得分:1)

你已经调用的

adapter.notifyDataSetChanged();将为你做无效(等等)所以没有必要,你似乎忽略的是事先将新数据设置到适配器中。像adapter.addAll(globals);之类的东西或者在你正在改变的数据上注册一个观察者(当你创建适配器时)

答案 2 :(得分:0)

为了完成你的工作,我可以建议一个溶剂,将其从中删除并粘贴/代替此行。

 listView.setAdapter(adapter);
 listView.notifyDataSetChanged;

对于ArrayAdapter,只有在适配器上使用add,insert,remove和clear函数时,notifyDataSetChanged才有效。根据此链接notifyDataSetChanged example

修改

  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();

    }

}
 }

答案 3 :(得分:0)

确保使用一种支持方法clear()和add()在ArrayAdapter上的数组列表初始化ArrayAdapter,如果用String []初始化它不会!

要解决此问题,请执行以下操作:

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);