今天在学习 Android Adapter 中遇到一个奇怪的问题,
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
主布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="#06a" android:padding="10dip" > <TextView android:id="@+id/tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="myadapter" /> <ListView android:id="@+id/lv_ad" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView> <Button android:id="@+id/btn_buy" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="提交" /> </LinearLayout>
列表项Code
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <ImageView android:id="@+id/goods_pic" android:layout_width="40dip" android:layout_height="40dip" android:layout_marginLeft="20dip" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="50dp" android:orientation="vertical" > <TextView android:id="@+id/people_name" android:layout_width="50dp" android:layout_height="wrap_content" android:layout_marginLeft="20dip" android:textSize="20sp" /> <TextView android:id="@+id/goods_price" android:layout_width="50dp" android:layout_height="wrap_content" android:layout_marginLeft="20dip" android:textSize="18sp" /> </LinearLayout> <CheckBox android:id="@+id/cb" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dip" /> <Button android:id="@+id/btn_deal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="查看" /> </LinearLayout>
要自定义 Adapter 就必须继承 Android基础类之BaseAdapter
在实现 MyAdpter 之前 参照以前所学的 SimpleAdapter 用法
最为关键的一句
SimpleAdapter adapter = new SimpleAdapter(this, data, R.layout.list_item, from, to);
SimpleAdapter 源码
public class SimpleAdapter extends BaseAdapter implements Filterable { private int[] mTo; private String[] mFrom; private ViewBinder mViewBinder; private List<? extends Map<String, ?>> mData; private int mResource; private int mDropDownResource; private LayoutInflater mInflater; private SimpleFilter mFilter; private ArrayList<Map<String, ?>> mUnfilteredData; /** * Constructor * * @param context The context where the View associated with this SimpleAdapter is running * @param data A List of Maps. Each entry in the List corresponds to one row in the list. The * Maps contain the data for each row, and should include all the entries specified in * "from" * @param resource Resource identifier of a view layout that defines the views for this list * item. The layout file should include at least those named views defined in "to" * @param from A list of column names that will be added to the Map associated with each * item. * @param to The views that should display column in the "from" parameter. These should all be * TextViews. The first N views in this list are given the values of the first N columns * in the from parameter. */ public SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) { mData = data; mResource = mDropDownResource = resource; mFrom = from; mTo = to; mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } /** * @see android.widget.Adapter#getCount() */ public int getCount() { return mData.size(); } /** * @see android.widget.Adapter#getItem(int) */ public Object getItem(int position) { return mData.get(position); } /** * @see android.widget.Adapter#getItemId(int) */ public long getItemId(int position) { return position; } /** * @see android.widget.Adapter#getView(int, View, ViewGroup) */ public View getView(int position, View convertView, ViewGroup parent) { return createViewFromResource(position, convertView, parent, mResource); }
接下来:
MyAdapter.java
public class MyAdapter extends BaseAdapter { private int[] mTo; private String[] mFrom; private List<? extends Map<String, ?>> mData; private int mResource; private LayoutInflater mInflater; public MyAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) { mData = data; mResource = resource; mFrom = from; mTo = to;//LayoutInflater inflater = LayoutInflater.from(context); // 其实现原理就是下面这句 mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getCount() { // TODO Auto-generated method stub return mData.size(); } @Override public Object getItem(int position) { return mData.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // View view = mInflater.inflate(mResource, null); //填充组件 for (int i = 0; i < mFrom.length; i++) { View v = view.findViewById(mTo[i]); Object content = mData.get(position).get(mFrom[i]); if (v instanceof ImageView) { ImageView iv = (ImageView) v; iv.setBackgroundResource((Integer)content); } else if (v instanceof TextView) { TextView tv = (TextView)v; tv.setText( (String)content); //tv.setText(content.toString()); } } } return view; } }
LayoutInflater inflater = LayoutInflater.from(context); 源码
/** * Obtains the LayoutInflater from the given context. */ public static LayoutInflater from(Context context) { LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (LayoutInflater == null) { throw new AssertionError("LayoutInflater not found."); } return LayoutInflater; }
TestAdapter
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.heart.listviewdemo.R; import android.app.Activity; import android.os.Bundle; import android.widget.ListView; public class TestAdapter extends Activity { private ListView listVIew; private static List<Map<String, Object>> data; static String[] from; static int[] to; static { data = new ArrayList<Map<String, Object>>(); Map<String, Object> map = new HashMap<String, Object>(); map.put("pic", R.drawable.p1); map.put("name", "移动"); map.put("price", 10086); data.add(map); map = new HashMap<String, Object>(); map.put("pic", R.drawable.p2); map.put("name", "联通"); map.put("price", "10010"); data.add(map); map = new HashMap<String, Object>(); map.put("pic", R.drawable.p3); map.put("name", "电信"); map.put("price", "0000"); data.add(map); map = new HashMap<String, Object>(); map.put("pic", R.drawable.p7); map.put("name", "Me"); map.put("price", "1353"); data.add(map); from = new String[] { "pic", "name", "price" }; to = new int[] { R.id.goods_pic, R.id.people_name, R.id.goods_price }; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.adapter_ly); // MyAdapter adapter = new MyAdapter(getApplicationContext(), data, R.layout.myadapter, from, to); listVIew = (ListView) findViewById(R.id.lv_ad); listVIew.setAdapter(adapter); } }
开始测试程序,结果是
仔细查看代码流程并没有错,那好 dedug 一下程序,结果发现
content 值为Integer
所以发生了:java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.CharSequence
content 值是由下面这句获得的
Object content = mData.get(position).get(mFrom[i]);
由此推断:在数据方面出错了
map.put("price", 10086); map.put("price", "10010");
原来一不小心放了 整型 由于定义了 private static List<Map<String, Object>> data;
value 放入什么都没关系的
解决方案
1.修改 map.put("price","10086");
2.在之前的 SimpleAdapter 的用法有提过,同样的数据 在 SimpleAdapter 测试中不出错
这是why?
public class SimpleAdapterDemo extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ListView listView = new ListView(this); // List<Map<String, Object>> data = new ArrayList<Map<String,Object>>(); Map<String, Object> map = new HashMap<String, Object>(); map.put("pic", R.drawable.p1); map.put("name", "移动"); map.put("phone", 10086); data.add(map ); map = new HashMap<String, Object>(); map.put("pic", R.drawable.p2); map.put("name", "联通"); map.put("phone", 10010); data.add(map ); map = new HashMap<String, Object>(); map.put("pic", R.drawable.p3); map.put("name", "电信"); map.put("phone", 0000); data.add(map ); map = new HashMap<String, Object>(); map.put("pic", R.drawable.p7); map.put("name", "Me"); map.put("phone", "13532605287"); data.add(map ); String[] from = new String [] { "pic", "name", "phone" }; int[] to = new int [] { R.id.people_pic, R.id.people_name, R.id.people_num }; SimpleAdapter adapter = new SimpleAdapter(this, data, R.layout.list_item, from, to); // listView.setAdapter(adapter); // setContentView(listView); // listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Log.d("TAG", String.valueOf(position)); Toast.makeText(SimpleAdapterDemo.this, "onItemClick " + position, Toast.LENGTH_LONG).show(); } }); //listView listView.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { Log.d("TAG", String.valueOf(position)); Toast.makeText(SimpleAdapterDemo.this, "OnItemSelectedListener " + position, Toast.LENGTH_LONG).show(); } @Override public void onNothingSelected(AdapterView<?> parent) { } }); } }
程序能运行起来,为什么能运行起来?
List<Map<String, Object>> data = new ArrayList<Map<String,Object>>();
如果把它改成这样 List<Map<String, String>> data = new ArrayList<Map<String,String>>(); 问题不就好办了
但是我们不可能都是String 类型的数据吧 如:map.put("pic", R.drawable.p1);
SimpleAdapter 如何做到的
public SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) { mData = data; mResource = mDropDownResource = resource; mFrom = from; mTo = to; mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); }
List<? extends Map<String, ?>> data 有 Java 基础的人都知道泛型
public View getView(int position, View convertView, ViewGroup parent) //这个方法很重要,关键是它如何得到一个 View 对象的
/** * @see android.widget.Adapter#getView(int, View, ViewGroup) */ public View getView(int position, View convertView, ViewGroup parent) { return createViewFromResource(position, convertView, parent, mResource); } private View createViewFromResource(int position, View convertView, ViewGroup parent, int resource) { View v; if (convertView == null) { v = mInflater.inflate(resource, parent, false); } else { v = convertView; } bindView(position, v); return v; }
终于:
private void bindView(int position, View view) { final Map dataSet = mData.get(position); if (dataSet == null) { return; } final ViewBinder binder = mViewBinder; final String[] from = mFrom; final int[] to = mTo; final int count = to.length; for (int i = 0; i < count; i++) { final View v = view.findViewById(to[i]); if (v != null) { final Object data = dataSet.get(from[i]); String text = data == null ? "" : data.toString(); if (text == null) { text = ""; } boolean bound = false; if (binder != null) { bound = binder.setViewValue(v, data, text); } if (!bound) { if (v instanceof Checkable) { if (data instanceof Boolean) { ((Checkable) v).setChecked((Boolean) data); } else if (v instanceof TextView) { // Note: keep the instanceof TextView check at the bottom of these // ifs since a lot of views are TextViews (e.g. CheckBoxes). setViewText((TextView) v, text); } else { throw new IllegalStateException(v.getClass().getName() + " should be bound to a Boolean, not a " + (data == null ? "<unknown type>" : data.getClass())); } } else if (v instanceof TextView) { // Note: keep the instanceof TextView check at the bottom of these // ifs since a lot of views are TextViews (e.g. CheckBoxes). setViewText((TextView) v, text); } else if (v instanceof ImageView) { if (data instanceof Integer) { setViewImage((ImageView) v, (Integer) data); } else { setViewImage((ImageView) v, text); } } else { throw new IllegalStateException(v.getClass().getName() + " is not a " + " view that can be bounds by this SimpleAdapter"); } } } } }
关键是:data.toString();
String text = data == null ? "" : data.toString(); if (text == null) { text = ""; } // Note: keep the instanceof TextView check at the bottom of these // ifs since a lot of views are TextViews (e.g. CheckBoxes). setViewText((TextView) v, text);
data 不是 Object 类型么? toString(); 不是打印哈希值么?
经过长时间的研究发现 Object 的toString() 方法 并不返回 Object 的哈希值
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
那只好调试程序了,调程序时,竟然发现 jdk 源码无法进入去,只好折腾一番,大家可以参考 这篇文章
接下来终于可以调试,jdk 源码了,为了更好的理解运行流程
public class TestToString { public static void main(String[] args) { @SuppressWarnings("unused") Object obj = 1; //String s = (String) obj; //报错 String s = obj.toString(); //通过 new TestToString().test(); } public void test(){ Object obj = 1; System.out.println(obj instanceof Integer); System.out.println(obj == Integer.valueOf(1)); System.out.println(obj.getClass()); obj = obj.toString(); System.out.println(obj.getClass()); System.out.println(obj instanceof String); System.out.println(obj); obj = new Integer(1); } }
在 Object obj = 1; 打个断点
发现 obj = Integer (我想到了 Java 自动装箱与拆箱(Autoboxing and unboxing) )
Integer 类重写了 Object 父类的 toString() 方法,这在我们平时写 JavaBean 时也提供一个 toString() 便于测试,但它 的toString() 如何返回 String 的
原来这句 return new String(buf, true); 返回了对象,上图能看见 buf 值需要重新编译 jdk 部分源码
原因:这是由于Oracle公司打包jdk时,为缩减体积,去除了二进制文件里的一些东西,所以看不到;目前的解决方案是,把jdk的源码导入到eclipse中,重新编译,然后打包,把jdk路径下的rj.jar替换掉。
重新编译 jdk 比较繁琐,大家可以参考 JDK源码重新编译——支持eclipse调试JDK源码--转载 或
解决Debug JDK source 无法查看局部变量的问题方案
修改 Object obj = ”1“; 再调试,只不过 obj=String 了 调用的是 String类的toString(); 返回本身
/** * This object (which is already a string!) is itself returned. * * @return the string itself. */ public String toString() { return this; }
总结:
TextView 的 setText(CharSequence text) 方法 参数是CharSequence 可读可写序列
然而我们通常这样做 tv.setText((CharSequence) content); //也许因为 IDE 提示功能,我们习惯性地强转 了。tv.setText( content.toString()); 有 java 的自动装箱拆箱,动态编译 支持。使用 toString(); 神马都能返回 String 字符串。虽然在程序上 TextView 显示的绝对是 String 类型的字符串,而不是什么 Integer ,Double 等包装类,数据流转的困难(大家都懂的 Java 是强类型的语言),大家在放数据的 一般情况下页面是放的都是 String 类型,这没什么好担心的,不过 使用 toString() 方法不是很完美么,再说 SimpleAdapter 都是这样做的, 外国人写那个 SimpleAdapter 方法时,的确写得。。。
相关推荐
以上就是关于“Android自定义adapter的listview”的主要知识点。自定义Adapter是Android开发中的核心技能之一,掌握好这一技巧,能帮助我们实现各种复杂的界面效果。通过不断实践和优化,我们可以在保证性能的同时,...
总之,自定义Adapter是Android开发中的一个重要技能,它允许开发者灵活地控制数据的显示方式,同时提高了应用的可扩展性和可维护性。通过实践和研究这个自定义Adapter的代码,你将能更好地掌握这一核心技术。
当我们需要显示的数据不满足默认Adapter提供的功能时,自定义Adapter就显得尤为重要。本篇将深入探讨如何为GridView创建自定义Adapter,以实现更灵活、个性化的数据展示。 首先,了解Adapter的基本概念。Adapter是...
总结起来,自定义Adapter在Android开发中扮演了至关重要的角色,它允许开发者根据需求定制ListView的每一个元素,提供更灵活的界面设计和交互体验。通过创建自定义Adapter并实现相关方法,我们可以实现更复杂的列表...
总结起来,自定义Adapter是Android开发中实现ListView个性化和功能扩展的重要手段。通过自定义Adapter,开发者可以根据需求创建复杂的数据视图,并处理各种用户交互事件,从而提高应用的用户体验和功能多样性。
总之,自定义Adapter是Android开发中不可或缺的一部分,它帮助开发者将数据模型与界面元素紧密结合起来,实现高度定制化的用户体验。理解并掌握自定义Adapter的原理和实践,对于提升Android应用的开发能力具有重要...
本篇将详细讲解如何在ListView中使用自定义Adapter来实现数据的及时更新。 首先,我们需要理解ListView的工作原理。ListView通过Adapter来与数据源进行交互,Adapter是连接数据集和视图的桥梁。它负责从数据集中...
本篇文章将详细介绍如何在Android中自定义Spinner的下拉列表,包括使用ArrayAdapter和自定义Adapter两种方法。 ### 一、使用ArrayAdapter ArrayAdapter是Android提供的基础适配器,它可以方便地将数组数据与...
在Android应用开发中,我们经常需要处理数据的展示和交互,这时自定义Adapter就显得尤为重要。本案例"android studio 自定义adapter开发闹钟小案例"将带你深入理解如何在Android Studio中利用Adapter来构建一个实用...
在Android开发中,创建一个带有图标的文件资源管理器通常涉及到自定义Adapter的实现。Adapter是连接数据源和UI视图的关键组件,它允许我们把数据转化为可显示的视图元素。下面将详细介绍如何在Android中制作这样一个...
在Android开发中,Adapter是一个非常重要的组件,它起到了数据源与UI展示之间的桥梁作用。当我们需要将数据集合...自定义Adapter是Android开发中的核心技能之一,掌握它能帮助我们更好地构建用户界面和处理数据展示。
本文将深入探讨如何使用自定义Adapter来创建一个功能丰富的Android ListView好友列表。 首先,我们需要理解ListView的工作原理。ListView依赖于Adapter来提供数据和视图之间的桥梁。Adapter是连接数据源(如...
在Android应用开发中,自定义控件是提升用户体验和界面个性化的重要手段。本文将深入探讨如何实现一个自定义的...不断学习和实践,将帮助你更好地理解和掌握Android自定义控件的精髓,为你的应用带来更丰富的用户体验。
以上就是关于Android自定义Spinner样式的详细说明。通过这些方法,你可以打造出与应用主题相符、用户体验良好的Spinner组件。记住,良好的UI设计能够提升用户对应用的满意度,因此花时间在自定义控件样式上是值得的...
"可重用的自定义adapter"是Android开发中的一个核心概念,允许开发者根据需求定制ListView、GridView等控件的数据展示方式。本项目基于Android Studio,对于使用Eclipse的开发者可能需要进行一些转换。 自定义...
总之,Android中的ListView结合自定义Adapter和Button控件可以创建出丰富的用户界面,用户不仅可以查看列表数据,还能直接在列表项内进行交互。通过理解并实践这些概念,开发者能够更灵活地构建Android应用程序的UI...
"自定义Adapter"这个主题主要关注如何正确地创建和使用自定义的Adapter,以及解决在使用过程中可能出现的问题,如程序闪退或崩溃。 首先,我们来理解Adapter的基本原理。Adapter是一个接口,它定义了如何将数据集...
自定义Adapter填充ExpandableListView是Android UI设计中的一个重要技能,它允许开发者根据需求定制列表的显示样式和交互方式。 首先,我们需要了解Adapter的概念。Adapter是连接数据源与UI组件的桥梁,它负责将...