【问题标题】:java.lang.String cannot be cast to com.example.expandablelistview.NewsItemjava.lang.String 不能转换为 com.example.expandablelistview.NewsItem
【发布时间】:2013-08-27 09:30:15
【问题描述】:

我正在尝试将 expandablelistview 子数据保存到 SharedPreferences。保存是有效的,但是当我尝试加载它时,我得到了错误。

问题:

当尝试加载设置并将其放入 HashMap 时,我收到以下错误(缩短为 3 行):

08-24 12:40:05.138: E/AndroidRuntime(807): FATAL EXCEPTION: main
08-24 12:40:05.138: E/AndroidRuntime(807): java.lang.ClassCastException: java.lang.String cannot be cast to com.example.expandablelistview.NewsItem
08-24 12:40:05.138: E/AndroidRuntime(807):  at com.example.expandablelistview.ExpandableListAdapter.getChildView(ExpandableListAdapter.java:62)

为了保存数据,我将使用以下代码:

    SharedPreferences pref = context.getSharedPreferences("myPrefs", MODE_PRIVATE);
    SharedPreferences.Editor editor= pref.edit();

    for( Entry<String, List<NewsItem>> entry : listDataChild.entrySet() )  {
          editor.putString( entry.getKey(), String.valueOf(entry.getValue())); // Save the values of listDataChild
    }

    editor.commit();

数据的输出是:

Yesterday: [[ headline=51.17346, 3.2252, Speed=2.10KM/H, Direction=158, date=18-8-2013 13:37:32]]
Older: [[ headline=51.74346, 3.23252, Speed=2.00KM/H, Direction=122, date=17-8-2013 11:40:30]]
Today: [[ headline=51.07346, 3.35252, Speed=0.00KM/H, Direction=122, date=19-8-2013 18:50:42]]

当尝试加载这些数据(此处发生错误)并将其放入 HashMap 时,我将使用它 (from here):

    for( Entry<String, ?> entry : pref.getAll().entrySet() ) {
        listDataChild.put( entry.getKey(), (List<NewsItem>) Arrays.asList(entry.getValue()) ); // Put it in listDataChild
    }

数据的初始化发生在这里:

static void prepareListData(final Context context) {
    listDataHeader = new ArrayList<String>();
    listDataChild = new HashMap<String, List<NewsItem>>();

    // Adding child data
    listDataHeader.add("Today");
    listDataHeader.add("Yesterday");
    listDataHeader.add("Older");
    List<NewsItem> today = new ArrayList<NewsItem>();
    NewsItem newsData = new NewsItem();
    newsData.setHeadline("51.07346, 3.35252");
    newsData.setSpeed("0.00KM/H");
    newsData.setDirection("122");
    newsData.setDate("19-8-2013 18:50:42");
    today.add(newsData);

    List<NewsItem> yesterday = new ArrayList<NewsItem>();
    newsData = new NewsItem();
    newsData.setHeadline("51.17346, 3.2252");
    newsData.setSpeed("2.10KM/H");
    newsData.setDirection("158");
    newsData.setDate("18-8-2013 13:37:32");
    yesterday.add(newsData);

    List<NewsItem> older = new ArrayList<NewsItem>();
    newsData = new NewsItem();
    newsData.setHeadline("51.74346, 3.23252");
    newsData.setSpeed("2.00KM/H");
    newsData.setDirection("122");
    newsData.setDate("17-8-2013 11:40:30");
    older.add(newsData);

    listDataChild.put(listDataHeader.get(0), today);
    listDataChild.put(listDataHeader.get(1), yesterday);
    listDataChild.put(listDataHeader.get(2), older);
}

尝试过:

我已尝试更改 listdataChild.put 以将数据加载到此:

listDataChild.put( entry.getKey(), new ArrayList<NewsItem>((Collection<? extends NewsItem>) Arrays.asList(entry.getValue())) );

还有这个:

listDataChild.put( entry.getKey(), (List<NewsItem>) new ArrayList(Arrays.asList(entry.getValue())) );

但没有任何结果。 (我有同样的错误)

问题:

是否可以将映射值转换为列表并将其放入 HashMap listDataChild 中?

或者我应该使用newsData.setHeadline("Value");newsData.setSpeed("Value"); 等? (我不知道如何获取SharedPreferences 列表中的具体值)

NewsItem.java的来源可以找到hereExpandableListAdapter.java的来源可以找到hereMainActivity.java的来源可以找到here

【问题讨论】:

  • 我很确定您链接到的ExpandableListAdapter 版本不是您正在使用的版本,因为NewsItem 的演员表发生在第 62 行,而不是第 66 行 :(
  • @JonSkeet Woops,我在上传之前删除了几行。现在确实在第 62 行。感谢您的通知。 :)
  • 您没有显示初始化ExpandableListAdapter 的位置也无济于事...
  • @JonSkeet Here 是完整的MainActivity.java。您还想要 XML 文件吗?
  • 还有一个简短而完整的程序演示了这个问题?应该不需要链接到其他地方的代码。

标签: java android hashmap sharedpreferences expandablelistview


【解决方案1】:

正如其他人已经指出的那样,简单地使用 Arrays.asList() 并投射到您的数据列表的期望是不正确的,并且不会起作用。当您使用SharedPreferences.Editor.putString() 时,您将在代表List.toString() 返回的字符串的首选项中插入一个String(这将在方括号中打印其所有子项(使用toString()))。当您从首选项中获取此字符串时,您需要将其构建为ListNewsItems。一种方法如下:

for (Entry<String, ?> entry : pref.getAll().entrySet()) {
                    List<NewsItem> rowItems = new ArrayList<NewsItem>();
                    // the string from the preferences as it was saved
                    String prefContent = (String) entry.getValue();
                    // break against possible multiple NewsItems(I'm assuming that's 
                    // why you use a List of NewsItems) for the same
                    // key (every NewsItem starts with * so we split after
                    // that(see the NewsItems.toString method))
                    String[] newsItems = prefContent.split("\\*");
                    for (String item : newsItems) {
                        // an item which doesn't have at least 50 characters
                        // isn't a valid NewsItem string representation(based on
                        // its toString() method)
                        if (item.length() > 50) {
                            // ; is the delimiter for the NewsItem's data
                            String[] components = item.split(";");
                            NewsItem ni = new NewsItem();
                            // for each of the four data components we split
                            // after = and then use the second value obtained as
                            // that will be the value for that component
                            ni.setHeadline((components[0].split("="))[1]);
                            ni.setSpeed((components[1].split("="))[1]);
                            ni.setDirection((components[2].split("="))[1]);
                            ni.setDate((components[3].split("="))[1]);
                            rowItems.add(ni);
                        }
                    }
                    listDataChild.put(entry.getKey(), rowItems);
                }

上面的代码需要更改NewsItem 类的toString() 方法:

@Override
public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("*headline=");
    sb.append(headline);
    sb.append(";");
    sb.append("speed=");
    sb.append(speed);
    sb.append(";");
    sb.append("direction=");
    sb.append(direction);
    sb.append(";");
    sb.append("date=");
    sb.append(date);
    return sb.toString();
}

【讨论】:

  • 谢谢!当我看到Date 字符串之后的列表时,只有一件事会显示,,如果它是列表中的最后一项,则它是]。我该如何解决这个问题?
  • @GerritHoekstra 如果您在toString() 方法中添加sb.append(";"); 行会发生什么情况:...sb.append("date="); sb.append(date);sb.append(";"); return sb.toString();?
  • @GerritHoekstra sb.append(";"); 应该可以工作。额外的,] 来自List 将在[] 之间打印其项目,并用, 分隔项目。因此,在; 之后进行拆分时,最后一个组件(日期)将为最后一个元素获得,]。但是在 toString() 方法中的日期之后插入 ; 会在 ; 之后进行拆分,以将额外的 ,] 移动到另一个 components 索引中。
  • @GerritHoekstra 我不确定我是否理解你想要做什么。如果您打算将其他 NewsItems(简单对象或来自另一个项目列表)添加到属于某个键的列表,那么您不能使用 HashMap.put(key, newData) 但您可以使用 `List list = HashMap.get(key) ;'然后将新数据添加到此列表中。如果您计划有一个指向多个 NewsItems 列表的键,那么使用该多映射可能是一个好主意。
  • @GerritHoekstra 我假设您可以在将新的NewsItem 添加到list list.add(0, object) 时使用索引0。
【解决方案2】:

您需要以某种方式将从SharedPreferences 返回的String 转换为NewsItem 的列表。单独的演员不会这样做。

【讨论】:

    【解决方案3】:

    此异常意味着您正在尝试将 String 对象分配给 com.example.expandablelistview.NewsItem 引用变量

    我知道这没有多大帮助,但无论如何

    【讨论】:

      【解决方案4】:

      我不确定-

      是否可以将地图值转换为列表并将其放入 HashMap listDataChild?

      当您正在寻找将 POJO 数据保存在共享首选项中时。您可以使用 JSON 格式来序列化您的 NewsItemList 及其包含的对象,然后将其作为字符串存储到 SharedPreferences 中。 Google-JSON 是一个很好的 api。

      当您想要取回数据时,检索字符串并使用 JSONArray 检索每个对象并将其添加到新的 NewsItemList。

      否则,请尝试将您的对象序列化私有文件。这将帮助您超越 SharedPreferences 的 putString()、putFloat()、putLong()、putInt() 和 putBoolean()。 谢谢。

      【讨论】:

        猜你喜欢
        • 2018-02-10
        • 2015-05-18
        • 2011-10-27
        • 2019-10-19
        • 2018-01-23
        • 2011-05-09
        • 2014-06-24
        • 1970-01-01
        • 2018-05-17
        相关资源
        最近更新 更多