阅读更多

今天在学习 Android Adapter 中遇到一个奇怪的问题,

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

 

   主布局文件

 

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

   列表项Code

  

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

   要自定义 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> mData;    private int mResource;    private int mDropDownResource;    private LayoutInflater mInflater;    private SimpleFilter mFilter;    private ArrayList> 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> 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> mData;private int mResource;private LayoutInflater mInflater;public MyAdapter(Context context, List<? extends Map> 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);}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn mData.size();}@Overridepublic Object getItem(int position) {return mData.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic 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> data;static String[] from;static int[] to;static {data = new ArrayList>();Map map = new HashMap();map.put("pic", R.drawable.p1);map.put("name", "移动");map.put("price", 10086);data.add(map);map = new HashMap();map.put("pic", R.drawable.p2);map.put("name", "联通");map.put("price", "10010");data.add(map);map = new HashMap();map.put("pic", R.drawable.p3);map.put("name", "电信");map.put("price", "0000");data.add(map);map = new HashMap();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 };}@Overrideprotected 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> data;

 

   value 放入什么都没关系的

 

   解决方案

   1.修改 map.put("price","10086");

 

   2.在之前的 SimpleAdapter 的用法有提过,同样的数据 在 SimpleAdapter  测试中不出错

   这是why?

 

   

public class SimpleAdapterDemo extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//ListView listView = new ListView(this);//List> data = new ArrayList>();Map map = new HashMap();map.put("pic", R.drawable.p1);map.put("name", "移动");map.put("phone", 10086);data.add(map );map = new HashMap();map.put("pic", R.drawable.p2);map.put("name", "联通");map.put("phone", 10010);data.add(map );map = new HashMap();map.put("pic", R.drawable.p3);map.put("name", "电信");map.put("phone", 0000);data.add(map );map = new HashMap();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() {@Overridepublic 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();}});//listViewlistView.setOnItemSelectedListener(new OnItemSelectedListener() {@Overridepublic 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();}@Overridepublic void onNothingSelected(AdapterView<?> parent) {}});}}

   程序能运行起来,为什么能运行起来?

 

 

  List> data = new ArrayList>();

   

  如果把它改成这样  List> data = new ArrayList>(); 问题不就好办了

  但是我们不可能都是String 类型的数据吧 如:map.put("pic", R.drawable.p1);

  SimpleAdapter 如何做到的

  

public SimpleAdapter(Context context, List<? extends Map> 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> 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 ? "" : 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  方法时,的确写得。。。

 

 

 

  • 描述: LogCat 异常信息
  • 大小: 23.3 KB
  • 大小: 5.6 KB
  • 大小: 3.6 KB
  • 大小: 9.5 KB
  • 大小: 22.7 KB
  • 大小: 3.1 KB
  • 查看图片附件

更多相关文章

  1. android studio 编译后 app-debug.apk 和 app-release.apk 的区
  2. C4droid – a C compiler for Android
  3. 如何制作Jar包并在android中调用jar包
  4. Android(安卓)Message源码阅读
  5. Android(安卓)JNI(实现自己的JNI_OnLoad函数)
  6. Android开源框架源码鉴赏:Okhttp
  7. android 4.0 内核(3.0)编译方法
  8. Android动态设置edittext的hint属性显示的提示文字大小
  9. android 开发之电子钢琴 源码

随机推荐

  1. 如何将树路径转换为json对象
  2. java基础中一些值得聊的话题(内存篇)
  3. 为可执行文件夹提供自定义图像
  4. java解析xml问题:如何获得一级标签下全部
  5. spring框架中一个跟String的trim方法一样
  6. java中的Unicode到String但很棘手
  7. hbase中出现的java.net.BindException-Pr
  8. 处理“您确定您想要离开这个页面”Msg在S
  9. javascript 操作流——回调的回调
  10. Java中字符流和字节流到底有什么区别!!!