上下文菜单无法从ListView行中删除文件项

时间:2017-10-30 19:29:29

标签: android listview contextmenu

我的上下文菜单无法从ListView行中删除文件项。 我的代码运行,Toast表示方法正在运行。 没有任何logcat错误。我的ListView工作正常。

我的问题是:我的代码出了什么问题? 请提供正确的代码来解决这个问题。

谢谢。

Java代码:class TestActivity

    public class TestActivity extends ListActivity {

                    private String root;
                    private List<String> item = null;
                    private ListView listview;

                    @Override
                    public void onCreate(Bundle savedInstanceState) {
                        super.onCreate(savedInstanceState);

                        setContentView(R.layout.activity_test);

                        registerForContextMenu(getListView());

                        root = Environment.getExternalStorageDirectory() + File.separator + "/ListTestFiles";
                        getDir(root);

// 01-Nov-2017 For reference added 6 lines of my existing Java code.
listview = getListView();
listview.setOnItemClickListener(new OnItemClickListener() {
                @Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
File file = new File(path.get(position));
String fullPath = new String(path.get(position));

                        } // End of onCreate code.


                    // 02-Nov-2017 For reference added 28 lines of my existing Java code.
                    private void getDir(String dirPath)
                    {
                        currentPath = dirPath;
                        item = new ArrayList<String>();
                        path = new ArrayList<String>();

                        File f = new File(dirPath);
                        File[] files = f.listFiles();

                        if(!dirPath.equals(root))
                        {
                            item.add(root);
                            path.add(root);
                            item.add("../");
                            path.add(f.getParent());
                        }

                        for(i2=0; i2 < files.length; i2++)
                        {
                            File file = files[i2];

                            if(!file.isHidden() && file.canRead()){
                                path.add(file.getPath());
                                if(file.isDirectory()) {
                                    item.add(file.getName() + "/");
                           }else {
                                    item.add(file.getName());
                                }
                            }
                        }

                        ArrayAdapter<String> fileList = new ArrayAdapter<String>(this, R.layout.layout_item_view, R.id.rowtext, item);
                        setListAdapter(fileList);

                    } // End of getDir method


                     @Override
                     public void onCreateContextMenu(ContextMenu menu, View v,
                                                     ContextMenu.ContextMenuInfo menuInfo) {
                         super.onCreateContextMenu(menu, v, menuInfo);
                             MenuInflater inflater = getMenuInflater();
                             inflater.inflate(R.menu.context_menu, menu);
                     }

                    @Override
                    public boolean onContextItemSelected(MenuItem item) {

                    final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();

                        switch (item.getItemId()) {
                            case R.id.context_menu_rename:
                                Toast.makeText(this, "Rename", Toast.LENGTH_SHORT).show();
                                return true;

                            case R.id.context_menu_delete:

                                // TEST #1 the line of code below runs but will Not delete the selected listview row item.
                                ArrayAdapter<String> adapter = new ArrayAdapter<String>(TouchActivity.this, R.layout.layout_item_view, R.id.rowtext);

                                // TEST #2 the line of code below runs but will Not delete the selected listview row item.
                                // ArrayAdapter<String> adapter = new ArrayAdapter<String>(TouchActivity.this, R.layout.layout_item_view);

// 01-Nov-2017 Added 2 New lines of code.
listview.setAdapter(adapter);
adapter.remove(String.valueOf(info.position));

// 01-Nov-2017 Commented out 2 lines of code.
// String index = valueOf(info.position);
// adapter.remove(index);

                                adapter.notifyDataSetChanged();

                                Toast.makeText(getApplicationContext(), "position = " + info.position, Toast.LENGTH_SHORT).show();

                                Toast.makeText(this, "Delete", Toast.LENGTH_SHORT).show();

                                return true;
                            default:
                                return super.onContextItemSelected(item);
                        }
                    }
                }

XML代码:layout_item_view.xml

            <?xml version="1.0" encoding="utf-8"?>
            <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:orientation="horizontal"
            android:background="#231f20">

            <TextView xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="@+id/rowtext"
                android:layout_width="fill_parent"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_height="60sp"
                android:textSize="18sp"
                android:layout_marginTop="10dp"/>

            </RelativeLayout>

XML代码:row.xml

        <?xml version="1.0" encoding="utf-8"?>

        <ListView
            android:id="@+id/rowtext"
            android:layout_width="fill_parent"
            android:layout_height="60sp"
            android:textSize="18sp"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="1dp"
            xmlns:android="http://schemas.android.com/apk/res/android" />

XML代码:activity_test.xml

        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:longClickable="true"
            android:clickable="true"
            android:orientation="vertical"
            android:layout_alignParentBottom="true"
            android:background="#231f20">
                <FrameLayout
                    android:layout_width="fill_parent"
                    android:layout_above="@+id/header"
                    android:layout_height="wrap_content" >

                    <ListView
                        android:id="@android:id/list"
                        android:layout_width="fill_parent" android:layout_height="wrap_content"
                        android:layout_weight="1" xmlns:android="http://schemas.android.com/apk/res/android"
                        android:fillViewport="true" />
                </FrameLayout>
        </LinearLayout>

Logcat输出:

// Test 3 I run the app with this code.
case R.id.context_menu_delete:
                fileList.remove(fileList.getItem(info.position));
                fileList.notifyDataSetChanged();
                return true;

// Test 4 I run the app with String.valueOf code because the adapter is an ArrayAdapter<String>
case R.id.context_menu_delete:
                fileList.remove(String.valueOf(fileList.getItem(info.position)));
                fileList.notifyDataSetChanged();
                return true;

// Logcat output is the same for both Test 3 and 4, the app crashes with the error below.

    --------- beginning of crash
11-03 17:40:02.840  18362-18362/com.testing.listapp E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.testing.listapp, PID: 18362
    java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.widget.ArrayAdapter.getItem(int)' on a null object reference
            at com.testing.listapp.TestActivity.onContextItemSelected(TestActivity.java:5413)
            at android.app.Activity.onMenuItemSelected(Activity.java:2905)
            at com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback.onMenuItemSelected(PhoneWindow.java:4701)
            at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:761)
            at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:152)
            at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:904)
            at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:894)
            at com.android.internal.view.menu.MenuDialogHelper.onClick(MenuDialogHelper.java:167)
            at com.android.internal.app.AlertController$AlertParams$3.onItemClick(AlertController.java:1082)
            at android.widget.AdapterView.performItemClick(AdapterView.java:305)
            at android.widget.AbsListView.performItemClick(AbsListView.java:1146)
            at android.widget.AbsListView$PerformClick.run(AbsListView.java:3053)
            at android.widget.AbsListView$3.run(AbsListView.java:3860)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5254)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

1 个答案:

答案 0 :(得分:0)

  

现在,当我长按ListView的Row项,然后在上下文菜单上按Delete时,所有ListView Rows都将从视图中删除。

让我们看看onContextItemSelected()中的一些行:

以下行为您提供全新的ArrayAdapter。它的getCount()将返回0,因为您没有向其传递任何数据列表:

`ArrayAdapter<String> adapter = new ArrayAdapter<String>(TouchActivity.this, R.layout.layout_item_view, R.id.rowtext);`

现在你设置这个&#34;空&#34;适配器作为ListView适配器:

listview.setAdapter(adapter);

旧适配器将被丢弃。当前的数据列表为空。所以现在ListView是空的。

由于当前适配器为&#34;为空&#34;,以下行无效:

adapter.remove(String.valueOf(info.position));

  

我重新启动活动,并显示ListView,所有行仍然存在。没有任何东西被永久删除。

这是因为您使用原始适配器重新初始化ListView

修改

如何删除所选项目?

您需要做的第一件事是让原始ListView适配器成为ActivityFragment托管ListView的字段:

private ArrayAdapter<String> fileList;

然后,在初始化数据列表后,将其实例化并将其设置为ListView的适配器,例如在getDir()

的末尾
//...
fileList = new ArrayAdapter<String>(this, R.layout.layout_item_view, R.id.rowtext, item);
setListAdapter(fileList);

数据将像以前一样显示。现在,您可以在Activity上访问此适配器,例如onContextItemSelected()

@Override
public boolean onContextItemSelected(MenuItem item) {
    final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();

    switch (item.getItemId()) {
        case R.id.context_menu_rename:
            Toast.makeText(this, "Rename", Toast.LENGTH_SHORT).show();
            return true;
        case R.id.context_menu_delete:
            fileList.remove(fileList.getItem(info.position));
            fileList.notifyDataSetChanged();
            return true;
        default:
            return super.onContextItemSelected(item);
     }
}

请注意,fileList.getItem(info.position)必须是唯一值,因为在ArrayAdapter#remove()下,List#remove()表示List,因此第一个匹配的item.remove(info.position)条目将被删除,不要介意其索引。如果您想绝对确定删除了正确的条目,那么您必须将数据列表设为一个字段,并通过调用ListView删除索引info.position中的条目

如何使更改永久化?

我们现在取得的成就是用户可以从数据列表中删除一个条目,ListView将通过不再显示已删除的条目来反映这一点。如果您离开应用程序并在一段时间后返回应用程序,onCreate() /适配器将保留其状态,例如按下&#34; HOME&#34;按钮。

但是如果您倾斜设备并因此导致方向更改(从纵向到横向,反之亦然),则将执行{{1}}并且将删除已删除的数据。如果用户按下&#34; BACK&#34;然后点击启动器图标。

因此,如果你想永久改变,你必须以某种方式坚持下去。 (但我认为这超出了这个问题的范围。)例如参见Storage Options

指南