我的上下文菜单无法从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)
答案 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
适配器成为Activity
或Fragment
托管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
指南