【发布时间】:2014-07-11 06:28:39
【问题描述】:
我已经尝试了一段时间了,但我的经验不足已经让我变得最好了。任何关于我应该如何处理该问题的指示或建议将不胜感激。
我有一个自定义 ListView,每个项目都包含两个字符串。 ListView 中的一个特定项目正在更改操作模式。我想要实现的是:
- 单击此 ListView 项目时,打开一个对话框,其中包含附加到单选按钮的列表。
- 选择 Dialog 项目之一后,关闭 Dialog 并更改该项目中的两个 ListView 字符串之一以反映该模式选择。
我的问题是:如何在单击对话框按钮时更新我的 ListView 项目?
我可以很好地创建 ListView 和 Dialog,但事实证明更新 ListView 很困难。可以设置初始值,但不会更新。我知道我需要调用 .notifyDataSetChanged,但是由于我希望在对话框的 onItemClick 中发生这种情况,我收到错误消息,类似于“无法引用在不同方法中定义的内部类中的非最终变量” ",我的变量不能是最终的。
我尝试过的:
- 在对话框关闭前立即通知数据更改。出现“非最终变量”错误。
- 实现模型-视图-控制器设置并尝试创建一个类似于“onVariableChangeListener”的方法,但我放弃了这个想法,因为它似乎有点离题而且我不太了解它。
- 创建一种方法来调出 Dialog 和另一种方法来更新 ListView 数据。问题是 Update 方法没有等待 Dialog 项目被点击。即使更改并重新打开对话框选择,ListView 也不会更新。
- 创建一个方法,其操作类似于 onCreateView,只要单击项目就会调用该方法。它应该创建并扩展一个新的 ListView。由于它是在 onItemClick 中调用的,因此它没有“非最终变量”错误,尽管它需要我创建 onCreateView 参数的最终实例。我不确定这会产生什么影响。这是一种有效的方法吗?
下面的代码是后两种想法的混合。 Dialog和update分别有方法,虽然update不等待dialog,进入update方法的参数是final的。
我希望解决方案简单明了,但我相信存在多个错误。我知道 SO 喜欢提出可以适用于稍后可能会阅读本文的其他人的问题,所以如果这对我的情况有点特殊,我深表歉意。任何帮助表示赞赏!
CalibrationFragment.java
public class CalibrationFragment extends Fragment{
private Context mContext;
private ArrayList<DataItem> data = new ArrayList<DataItem>(); // DataItem is a class that sets two strings
private ArrayList<DataItem> currentData = new ArrayList<DataItem>(); // Two records kept to identify changes
ListView myList;
int checkedItem1 = 0; // For the dialog boxes.
@Override
public void onCreate (Bundle savedInstanceState){
super.onCreate(savedInstanceState);
mContext = getActivity(); // Get the context of the Activity and therefore the fragment
myList = new ListView (mContext); // Create a ListView
// Set initial values
calibrationData readData = new calibrationData(); // readData will contain all ListView values
// ... other items...
readData.setMode(checkedItem1, mContext); // Set to 0, 1 or 2 indicating different modes
// ... other items...
// Create elements to be added to the list
// ...
DataItem calibration4 = new DataItem(getResources().getString(R.string.mode_calibration), readData.getMode());
// readData.getMode() returns different strings depending on int input
// ...
// Add elements to the list
// ...
data.add(calibration4);
// ...
currentData = data; // Initialise both as the same
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Inflate the view
View rootView = inflater.inflate(R.layout.fragment_list, container, false);
myList=(ListView) rootView.findViewById(android.R.id.list);
// Create and set the customised adapter to take data (ArrayList<DataItem>) and format
// each element as defined in list_row.xml
CustomAdapter adapter = new CustomAdapter(mContext, R.layout.list_row, data);
myList.setAdapter(adapter);
// The above adapter is the one I need to notify
// For the sake of letting my code compile in onItemClick. Unsure if this causes further issues.
final LayoutInflater finalInflater = inflater;
final ViewGroup finalContainer = container;
final Bundle finalSavedInstanceState = savedInstanceState;
// CustomAdapter adapter cannot be used in setOnItemClickListener because it is non-final
myList.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView<?> parentAdapter, View view, int position, long id)
{
switch((int)id){
// [Different cases here]
case 3: // Clicks of Mode item
// Creates Dialog
showDialog((int)id, checkedItem1);
// updateData executes as Dialog is generated, not clicked or closed. Do not want this.
updateData(finalInflater, finalContainer, finalSavedInstanceState);
break;
// [Rest of the cases and default statement here]
}
}
});
return rootView; // onCreateView must return a View variable if displaying a UI.
}
public void showDialog(int id, int checkedItem)
{
// In case I want to have other dialogs later, ensure this is for Mode selection.
if(id == 3){
final CharSequence[] modeItems = {
"Mode 1", "Mode 2", "Mode 3"
}; // For Dialog
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setTitle(getResources().getString(R.string.mode_calibration));
builder.setSingleChoiceItems(modeItems, checkedItem, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
checkedItem1 = item; // Change checkedItem1 to the index selected in the dialog
calibrationData readData = new calibrationData();
readData.setMode(checkedItem1, mContext); // Set Mode depending on checkedItem
// Create DataItem representing new mode
DataItem newMode = new DataItem(getResources().getString(R.string.mode_calibration), readData.getMode());
currentData.set(3, newMode); // Set new mode into currentData.
// Eventual comparison with var 'data' will indicate a change
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
alert.show();
}
public View updateData(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
// Inflate the new view
View rootView = inflater.inflate(R.layout.fragment_list, container, false);
myList=(ListView) rootView.findViewById(android.R.id.list);
// Create and set the customised adapter to take data (ArrayList<DataItem>) and format
// each element as defined in list_row.xml
CustomAdapter adapter = new CustomAdapter(mContext, R.layout.list_row, data);
myList.setAdapter(adapter);
// As this is only called in onClick, I can work with data assuming something has changed and been clicked.
int i = 0;
// Compare each element inside data and currentData.
for(i = 0; i < data.size(); i++){
if(data.get(i) != currentData.get(i)) data = currentData;
if(i==5) Toast.makeText(mContext, "Iterating to end", Toast.LENGTH_SHORT).show(); // debug purposes
}
adapter.notifyDataSetChanged(); // Update list
return rootView;
}
【问题讨论】:
标签: android listview dialog fragment onitemclicklistener