gpt4 book ai didi

android - 如何在主线程中将 ListView、ArrayList、ArrayAdapter 和 notifyDataSetChanged 与可运行对象和消息处理程序一起使用

转载 作者:太空宇宙 更新时间:2023-11-03 10:41:13 26 4
gpt4 key购买 nike

我研究了 6 个其他 SO 问题线程以及一些具有相同问题的博客文章错误信息,一切都无济于事。

我正在将文件目录加载到 ArrayList 中,然后加载到 ListView 中使用 ArrayAdapter。代码实际工作 - 目录显示并响应点击事件 - 但程序随后以此错误结束,通常在我显示目录一次、几次或几次之后,然后运行程序的另一部分将 loadUrl 加载到 WebView 中:

适配器的内容已更改但 ListView 未收到通知。确保你的适配器的内容没有被修改后台线程,但仅来自 UI 线程。确保你的适配器在其内容更改时调用 notifyDataSetChanged()。

我见过的所有简单示例都没有使用 notifyDataSetChanged 或单独的线程。我想知道我是否需要使用这些以及如何使用它们正确。我对 ArrayAdapterArrayList 感到困惑,关于哪些只需要在主线程中修改。 ArrayList 中的数据仅在请求新目录列表时更改,然后清除并加载新数据。

我的问题是:在这种情况下我需要 notifyDataSetChanged 吗? [我很我确定我没有],我如何安排主要部分之间的各个部分和后台/可运行线程?

我通过交替运行 directoryList 和displayFtpHelp [使用 WebView/loadUrl()] 部分 - 但我必须运行这对多次到多次崩溃。

LogCat不包括程序最后执行的语句,因此很难确定实际的触发因素;而是这样:

android.widget.ListView.layoutChildren(ListView.java:1555)

将 displayFtpHelp 部分的 loadUrl() 放入 WebView 中。我想知道这是怎么回事最终触发错误。好像这个程序实际上不是发生错误时对 ArrayList/ArrayAdapter 进行操作。这好像是程序结构错误,而不是技术或逻辑错误。

我所做的是,首先定义两个 ListViews 和 ArrayList。一ListView 用于本地设备文件,另一个用于远程 Ftp 站点。

static ListView filesListLocal, filesListRemote;
static ArrayList<HashMap<String,String>> directoryEntries = new ArrayList<>();

我将展示 Ftp 目录的代码。本地目录的代码是除了使用 file.getAbsolutePath() 而不是ftp.list(),以及对 lookForFilesAndDirs() 的技术更改,即本地目录处理的递归。

然后我使用 Runnable 将 Ftp 目录读入一个数组。我是此处省略错误检查和其他细节;这是使用 Ftp4j图书馆:

Runnable r = new Runnable() {
public void run() {
Message msg = mHandler.obtainMessage();
try {
FTPFile[] fileAndDirs = ftp.list();
dirName = ftp.currentDirectory();
} catch (Various Exceptions e) {
result = "The operation failed\n" + e.toString();
}
Bundle bundle = new Bundle();
bundle.putString("mickKey", result);
msg.setData(bundle);
mHandler.sendMessage(msg);
}
};
Thread t = new Thread(r);
t.start();

在消息处理程序中,我将数据从数组复制到 ArrayList 并使用 Adapter 将其显示在 ListView 中。我原来有这个 Runnable 中的代码,然后将其移动到 main 中的消息处理程序 我第一次收到错误消息时的线程,但这没有帮助。 我猜测 notifyDataSetChanged 调用,但它也没有 区别:

dirName = ftp.currentDirectory();
sa.notifyDataSetChanged();
directoryEntries.clear();
lookForFilesAndDirs(fileAndDirs); // load ArrayList
SimpleAdapter saFtp = new SimpleAdapter(myContext, directoryEntries,
R.layout.my_two_lines, new String[] {"path", "filename"},
new int[] {R.id.path, R.id.filename});
filesListRemote.setAdapter(saFtp);
sa.notifyDataSetChanged();

...在这里省略更多细节

public static void lookForFilesAndDirs(FTPFile[] fileAndDirs) {
for (FTPFile fileOrDir : fileAndDirs) {
String fileOrDirName = fileOrDir.getName();
int entryType = fileOrDir.getType();
if (entryType == 1) { // entry is a directory
HashMap<String,String> listEntry = new HashMap<>();
listEntry.put("path", fileOrDirName);
listEntry.put("filename", null);
directoryEntries.add(listEntry);
} else { // entry is a file
HashMap<String,String> listEntry = new HashMap<>();
listEntry.put("path", dirName);
listEntry.put("filename", fileOrDirName);
directoryEntries.add(listEntry);
}
}

LogCat:

10-14 19:47:29.403 3006-3006/com.webs.mdawdy.htmlspyii I/Mick: onMenuItemClick
10-14 19:47:29.403 3006-3006/com.webs.mdawdy.htmlspyii I/Mick: ftpPrintFilesList
10-14 19:47:30.235 3006-3006/com.webs.mdawdy.htmlspyii I/Mick: handleMessage
10-14 19:47:32.339 3006-3006/com.webs.mdawdy.htmlspyii W/EGL_genymotion: eglSurfaceAttrib not implemented
10-14 19:47:34.627 3006-3006/com.webs.mdawdy.htmlspyii I/Mick: onMenuItemClick
10-14 19:47:34.627 3006-3006/com.webs.mdawdy.htmlspyii I/Mick: displayFtpHelp Begin
10-14 19:47:34.627 3006-3006/com.webs.mdawdy.htmlspyii I/Mick: displayFtpHelp end
10-14 19:47:34.819 3006-3006/com.webs.mdawdy.htmlspyii D/AndroidRuntime: Shutting down VM
10-14 19:47:34.819 3006-3006/com.webs.mdawdy.htmlspyii W/dalvikvm: threadid=1:
thread exiting with uncaught exception (group=0xa4d2db20)
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: FATAL EXCEPTION: main
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: Process: com.webs.mdawdy.htmlspyii, PID: 3006
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime:
java.lang.IllegalStateException: The content of the adapter has changed but
ListView did not receive a notification. Make sure the content of your
adapter is not modified from a background thread, but only from the UI thread.
Make sure your adapter calls notifyDataSetChanged() when its content changes.
[in ListView(2131427419, class android.widget.ListView) with
Adapter(class android.widget.SimpleAdapter)]
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at android.widget.ListView.layoutChildren(ListView.java:1555)
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at android.widget.ListView.setSelectionInt(ListView.java:1980)
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at android.widget.AbsListView.resurrectSelection(AbsListView.java:5376)
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at android.widget.AbsListView.onWindowFocusChanged(AbsListView.java:2822)
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at android.view.View.dispatchWindowFocusChanged(View.java:7900)
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at android.view.ViewGroup.dispatchWindowFocusChanged(ViewGroup.java:968)
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at android.view.ViewGroup.dispatchWindowFocusChanged(ViewGroup.java:972)
[6 more lines identical to the one above]
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:3133)
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:102)
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at android.os.Looper.loop(Looper.java:136)
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5001)
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at java.lang.reflect.Method.invokeNative(Native Method)
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:515)
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
10-14 19:47:34.823 3006-3006/com.webs.mdawdy.htmlspyii E/AndroidRuntime: at dalvik.system.NativeStart.main(Native Method)

最佳答案

一些建议:

  1. 使用单独的目录条目列表来存储支持两个 ListView 的数据

    • List<HashMap<String,String>> directoryEntriesLocal = new ArrayList<>();
    • List<HashMap<String,String>> directoryEntriesRemote = new ArrayList<>();
  2. 设置适配器 sasaFtponCreate() 中的相应 ListView Activity 的方法。现阶段均directoryEntriesLocaldirectoryEntriesRemote可以为空。

  3. Handler对于主线程,只需更改需要更新的目录条目列表的数据然后调用 notifyDataSetChanged() 相应适配器的。如果声明两个处理程序会更好,一个用于更新远程列表,另一个用于本地列表。或者您可以在一个 Handler 中完成这两项操作.这个选择留给你。无需在此处实例化和分配新的适配器。
  4. 请不要直接使用 HandlerThread类。使用 AsyncTask反而。它将使您作为 Android 程序员的生活变得更加轻松。

关于android - 如何在主线程中将 ListView、ArrayList、ArrayAdapter 和 notifyDataSetChanged 与可运行对象和消息处理程序一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33152390/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com