Java &引用;变量是从内部类中访问的,需要声明为final;自定义适配器中出现错误
我正试图实现一个带有复选框的多选列表视图,并定义了一个自定义适配器类,如下所示:Java &引用;变量是从内部类中访问的,需要声明为final;自定义适配器中出现错误,java,android,custom-adapter,Java,Android,Custom Adapter,我正试图实现一个带有复选框的多选列表视图,并定义了一个自定义适配器类,如下所示: package com.ameer.easycooking; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.w
package com.ameer.easycooking;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class CategoryAdapter extends ArrayAdapter<String> {
private List<String> categoryList;
private Context context;
private List<String> selected = new ArrayList<>();
public CategoryAdapter(List<String> categoryList, Context context) {
super(context, R.layout.category_list_item, categoryList);
this.categoryList = categoryList;
this.context = context;
}
public static class CategoryHolder {
private CheckBox checkBox;
private TextView categoryName;
public CategoryHolder(CheckBox checkBox, TextView categoryName) {
this.checkBox = checkBox;
this.categoryName = categoryName;
}
public CheckBox getCheckBox() {
return checkBox;
}
public void setCheckBox(CheckBox checkBox) {
this.checkBox = checkBox;
}
public TextView getCategoryName() {
return categoryName;
}
public void setCategoryName(TextView categoryName) {
this.categoryName = categoryName;
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
CategoryHolder holder = new CategoryHolder((CheckBox) v.findViewById(R.id.checkBox), (TextView) v.findViewById(R.id.name));
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.category_list_item, null);
holder.getCheckBox().setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
selected.add(holder.getCheckBox().getText().toString());
}else{
selected.remove(holder.getCheckBox().getText().toString());
}
}
});
v.setTag(holder);
} else {
holder = (CategoryHolder) v.getTag();
}
String category = categoryList.get(position);
holder.categoryName.setText(category);
holder.checkBox.setTag(category);
return v;
}
public List<String> getSelected() {
return selected;
}
}
package com.ameer.easycooking;
导入android.content.Context;
导入android.view.LayoutInflater;
导入android.view.view;
导入android.view.ViewGroup;
导入android.widget.ArrayAdapter;
导入android.widget.CheckBox;
导入android.widget.CompoundButton;
导入android.widget.TextView;
导入java.util.ArrayList;
导入java.util.List;
公共类CategoryAdapter扩展了ArrayAdapter{
私有列表分类列表;
私人语境;
所选私有列表=新建ArrayList();
公共类别适配器(列表类别列表、上下文){
super(上下文、R.layout.category\u list\u项、categoryList);
this.categoryList=categoryList;
this.context=上下文;
}
公共静态类类别文件夹{
私有复选框;
私有TextView类别名称;
公共类别文件夹(文本视图类别名称复选框){
this.checkBox=复选框;
this.categoryName=categoryName;
}
公共复选框getCheckBox(){
返回复选框;
}
公共无效设置复选框(复选框){
this.checkBox=复选框;
}
公共文本视图getCategoryName(){
返回类别名称;
}
公共无效setCategoryName(TextView categoryName){
this.categoryName=categoryName;
}
}
@凌驾
公共视图getView(int位置、视图转换视图、视图组父视图){
视图v=转换视图;
CategoryHolder holder=新的CategoryHolder((复选框)v.findViewById(R.id.CheckBox),(文本视图)v.findViewById(R.id.name));
if(convertView==null){
LayoutFlater充气器=(LayoutFlater)context.getSystemService(context.LAYOUT\u充气器\u服务);
v=充气机充气(R.layout.category\u list\u项,空);
holder.getCheckBox().setOnCheckedChangeListener(新建CompoundButton.OnCheckedChangeListener()){
@凌驾
检查更改后的公共无效(复合按钮视图,布尔值已检查){
如果(已检查){
添加(holder.getCheckBox().getText().toString());
}否则{
选中.remove(holder.getCheckBox().getText().toString());
}
}
});
v、 setTag(支架);
}否则{
holder=(CategoryHolder)v.getTag();
}
String category=categoryList.get(位置);
holder.categoryName.setText(类别);
holder.checkBox.setTag(类别);
返回v;
}
公共列表getSelected(){
返回选中的;
}
}
我想将选中的项存储在选中的列表中,然后在类末尾使用getter检索它们,但它告诉我需要将“holder”声明为final,如果我将其声明为final,我就不能再使用holder=(CategoryHolder)v.getTag()为其赋值代码>所以解决一个问题就是创建另一个问题:(我如何解决这两个问题
提前感谢。您可以从选中的更改侦听器的参数中获得必要的信息:按钮视图是选中的元素。因此,您只需执行以下操作:
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
CheckBox checkbox;
if (buttonView instanceof CheckBox )
{
checkbox = (CheckBox)buttonView;
}
else return;
if (isChecked) {
selected.add(checkbox.getText().toString());
}else{
selected.remove(checkbox.getText().toString());
}
}
若您将对象用于内部类,则应该声明它final
。
这里解释如下:
因此,您可以将该变量设为final:
final CategoryHolder holder = convertView != null ?
(CategoryHolder) v.getTag() :
new CategoryHolder((CheckBox) v.findViewById(R.id.checkBox), (TextView) v.findViewById(R.id.name));
您的holder是一个内部类。您需要将其声明为全局变量,然后在需要时对其进行初始化。我按照您的建议更改了代码,但现在在CategoryHolder holder=new CategoryHolder((CheckBox)v.findViewById(R.id.CheckBox),(TextView)v.findViewById(R.id.name))处出现空指针异常
为什么?@user3501779-很高兴听到我的回答让你更进一步:至少现在它正在运行…不知何故;-)你得到了一个NPE,因为convertView
有时可能是null
。因此,如果将null
分配给v
,则v.findViewById()
会导致NPE。根据此信息,我将上行移到if(convertView==null)
条件中,它现在正在工作并在ListView中显示项目。但是,我总是在所选的中得到一个空字符串。getText()
方法是否返回复选框文本或文本视图文本?我想这就是问题所在,因为我没有给复选框文本分配任何内容,而是给相应的文本视图。解决了它。我应该在复选框中使用setText()
,而不是setTag()
,因此现在我还可以完全忽略适配器中的文本视图。非常感谢你@user3501779-不客气:)请记住,通过使用View.getTag(),您也可以从复选框中检索类别(即使不强制转换)。toString()
标记有时非常方便