How to use ListView, ArrayList, ArrayAdapter and notifyDataSetChanged together with runnable and message handler in main stream

I worked through 6 other questions about SO, plus some blog posts with the same mesage error, all to no avail.

I upload the file directory to ArrayListand then to ListView using ArrayAdapter. The code really works - the directory is displayed and responds to click events - but then the program ends with this error, usually after I show the directory one, several or several times, and then run the other part of the program that does loadUrl in the WebView:

The contents of the adapter changed, but the ListView did not receive a notification. Verify that the contents of the adapter are not modified. background thread, but only from the user interface thread. Make sure the adapter calls notifyDataSetChanged () when its contents change.

None of the simple examples I saw used notifyDataSetChangedor a separate thread. I am wondering if I need to use them and how to use them correctly. I am confused between ArrayAdapterand ArrayList, which should only be changed in the main thread. Data in ArrayListchanges only when a new directory is requested, then it is cleared and loaded with new data.

My questions: do I need notifyDataSetChanged? [I don’t know at all], and how can I organize the various parts between the main and the background / runnable thread?

, List 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(), .

Ftp Runnable. ; 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   , ListView.   Runnable,   , .   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)
+4
1

:

  • , ListView s.

    • List<HashMap<String,String>> directoryEntriesLocal = new ArrayList<>();
    • List<HashMap<String,String>> directoryEntriesRemote = new ArrayList<>();
  • sa saFtp onCreate() . directoryEntriesLocal directoryEntriesRemote .

  • Handler , , notifyDataSetChanged() . , , , . Handler. . .
  • , Handler Thread. AsyncTask. Android.
+1

Source: https://habr.com/ru/post/1611811/


All Articles