【问题标题】:Can't update android listview in onPostExecute无法在 onPostExecute 中更新 android listview
【发布时间】:2014-02-09 12:04:07
【问题描述】:

我的 onCreate 方法中有这个:

String[] myStringArray = {"a","b","c","a","b","c","a","b","c","a","b","c","a","b","c","a","b","c"};
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_top_jokes);        

    new loadJson().execute();

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

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

}

上面的代码用myStringArray的内容填充了一个listView,现在一切正常。当我调用new loadJson().execute(); 时,问题就来了,它执行得很好,这里是方法的代码:

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://website.com/content/showContent.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) {
    JSONArray jsonArray = new JSONArray();
    try {
        jsonArray = new JSONArray(buffer);
    } catch (JSONException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println("JSONarray: " + jsonArray);
    String[] newArray = null;
    for (int i = 0; i < jsonArray.length(); i++) {
        try {

        newArray[i] = jsonArray.getJSONObject(i).toString();
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
    myStringArray = newArray;
 }

}

如您所见,我正在使用提取到newArray 的新值更新myStringArray 的硬编码内容。现在我无法看到新内容。我知道它在那里,但我如何告诉当前活动:“嘿,我更新了你的数组,请显示!” ?

我知道我遗漏了一些非常小的东西,但作为初学者,我无法发现它。

【问题讨论】:

  • 你在哪里打电话adapter.notifyDataSetChanged();
  • 我无法加入adapter 内部的onPostExecute
  • 为什么你不能访问只需将适配器实例声明为全局并在 onCreate 方法中初始化,然后你就可以访问整个类,包括内部类
  • 我做不到:(

标签: java android android-asynctask android-activity


【解决方案1】:

我找到了这个问题的答案,因为我自己也在寻找答案。 这里有一些接近的答案,但它们遗漏了永远无法让您找到答案的部分。

首先在你的 AsyncTask 类中添加两个成员变量:

private ListView listView;
private Activity activity;

接下来,为你的 AsyncTask 类添加一个构造函数,它接受一个 Activity:

  public loadJson(Activity activity) {
        this.activity = activity;
    }

现在,当您新建 AsyncTask 类并调用 execute() 时,您将添加对调用它的 Activity 的引用(构造 AsyncTask 类时传入的 this 值)。

new loadJson(this).execute(param);

最后,回到您的 AsyncTask,您将为您的 postExecute() 编写代码,如下所示:

protected void onPostExecute(String output) {
        listView = (ListView) activity.findViewById(R.id.targetListView);
        ArrayAdapter<String> adapter = (ArrayAdapter<String>)listView.getAdapter();
        adapter.add(output);
        adapter.notifyDataSetChanged();
    }

您必须拥有对 Activity 的引用,以便调用 findViewById。 请注意,targetListView 是您原始 Activity 上的 ListView 的 id。

我们已将该 Activity 发送到 AsyncTask 的构造函数中,因此它可用。 现在您可以获取适配器并将您的值添加到您并调用 notifyDataSetChanged() 以便它会在您的 UI 上更新。

我在我的解决方案中使用了这段代码,效果很好。

【讨论】:

    【解决方案2】:

    你切换了数组的引用,你应该做的是在适配器实例上使用clearaddAll(将适配器实例传递给你的AsyncTask来访问它)。

    【讨论】:

    • 但我无法访问onPostExecute 内部的adapter
    • 如果您正在编写代码,则没有“我不能”,只需在创建任务时将其作为参数传递
    • 我喜欢这种精神,但我在安卓世界里无能为力。感谢您的帮助!
    【解决方案3】:

    在您的 onPostExecute 中,您可以尝试以下操作:

    ListView listView = (ListView) findViewById(R.id.topJokesList);
    listView.getAdapter().notifyDataSetChanged();
    

    【讨论】:

    • 我运气不好 :(
    • 我认为还有另一个问题:你没有初始化你的 newArray 吗?例如行 String[] newArray = null;后面应该跟 newArray = new String[jsonArray.length()];
    【解决方案4】:
    protected void onPostExecute(String buffer) {
    JSONArray jsonArray = new JSONArray();
    try {
        jsonArray = new JSONArray(buffer);
    } catch (JSONException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println("JSONarray: " + jsonArray);
    String[] newArray = null;
    for (int i = 0; i < jsonArray.length(); i++) {
        try {
    
        newArray[i] = jsonArray.getJSONObject(i).toString();
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
    myStringArray = newArray;
    

    }

    在您上面的代码中,您使用的是一些实际位于工作线程(doInBackgroud()) 方法中的代码,因此剪切此代码并粘贴到 doInBackgound 方法中。 然后将此代码保留在 onPostExecute 方法中,并在 oncreate 方法之前声明 listview 和 arrayadapter,即 Global

    listView = (ListView) findViewById(R.id.topJokesList);
    listView.getAdapter().notifyDataSetChanged();
    

    希望对你有帮助……

    【讨论】:

    • 如何使它们全局化?我已经尽一切努力让它工作。 :(
    【解决方案5】:

    在更新数组列表内容后,您可以从数组切换到 ArrayList 并调用 adapter.notifyDataSetChanged(但不要创建新的 ArrayList 实例,更新必须与提供给 ArrayAdapter 的引用相同)。

    或在您的 AsyncTask.onPostExecute 中重复以下代码(来自 onCreate):

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, 
            android.R.layout.simple_list_item_1, newArray);
    listView.setAdapter(adapter);
    

    【讨论】:

    • 当我把它放在onPostExecute 时,我得到了这个错误:The constructor ArrayAdapter&lt;String&gt;(TopJokes.loadJson, int, String[]) is undefined
    • this更改为MyActivity.this
    • 我的应用在更改后刚刚崩溃:(
    • 查看logcat,你也没有分配newArray,你也将结果存储在newJokes中
    • 日志猫抛出了一个地狱般的错误,newArray 是固定的,但它仍然是一样的。我认为我已经完成了android。感谢您尝试帮助我!
    【解决方案6】:

    您需要: A. 使用 Strings.xml 文件 B. 将字符串从一个更改为另一个 - 例如

    <string name="example1">hi</string>
    <string name="example2">hello</string>
    

    在 strings.xml 文件中 然后在 Main 类中:

    label.setText("@string/example2");
    

    当字符串为 example1 时。 如果这没有帮助,我不知道会怎样......

    【讨论】:

      【解决方案7】:

      您可以在 asynctask 构造函数中添加适配器:

      在你的活动中:

          LoadJson lj = new Json(adapter);
          lj.execute();
      

      可以在LoadJson中声明:

      private  ArrayAdapter<String> mAdapter;
      

      在构造函数中,您从活动中获取适配器:

      public LoadJson(ArrayAdapter<String> adapter){
            mAdapter = adapter;
      }
      

      所以在您的 postExecute 中,您可以更新适配器。 希望能帮助到你!

      【讨论】:

        【解决方案8】:

        将“loadJson”类作为您的 ListActivity 类(或 Activity 或您使用的任何活动)的子类

        【讨论】:

        • 这实际上是一个糟糕的建议。您必须防止活动“增长”
        【解决方案9】:

        只需将 Adapter 的引用添加到您的 AsyncTask 中即可:

        public class loadJson extends AsyncTask<Void, Integer, String>{
        
            ArrayAdapter<String> adapter;
        
            public loadJson(ArrayAdapter<String> adapter) {
                this.adapter = adapter;
            }
        
            //...
        
            protected void onPostExecute(String buffer) {
                if (this.adapter != null) {
                    // update adapter
                }
            }
        
        }
        

        然后

        new loadJson(adapter).execute();  
        

        现在您可以在onPostExecute 中更新您的Adapter

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-04-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-06-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多