在获取 android.content.res.Resources$NotFoundException: Resource ID #0x0 时,如何确定发生崩溃的位置?

How do I figure out where the crash occurred when getting android.content.res.Resources$NotFoundException: Resource ID #0x0?

我正在为这个 android 项目使用带选项卡的 activity 模板,每个选项卡初始化一个不同的片段,其中大部分包含 ListViews,当点击一行时,会出现一个详细片段。当我按下其中一个选项卡时,出现以下错误:

    android.content.res.Resources$NotFoundException: Resource ID #0x0
        at android.content.res.Resources.getValue(Resources.java:1266)
        at android.content.res.Resources.loadXmlResourceParser(Resources.java:2649)
        at android.content.res.Resources.getLayout(Resources.java:1082)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:412)
        at android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.java:371)
        at android.widget.ArrayAdapter.getView(ArrayAdapter.java:362)
        at android.widget.AbsListView.obtainView(AbsListView.java:2347)
        at android.widget.ListView.makeAndAddView(ListView.java:1864)
        at android.widget.ListView.fillDown(ListView.java:698)
        at android.widget.ListView.fillFromTop(ListView.java:759)
        at android.widget.ListView.layoutChildren(ListView.java:1673)
        at android.widget.AbsListView.onLayout(AbsListView.java:2151)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
        at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1692)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1468)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1627)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.support.v7.internal.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:437)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2086)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1843)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
        at android.view.Choreographer.doCallbacks(Choreographer.java:580)
        at android.view.Choreographer.doFrame(Choreographer.java:550)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5257)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

这并没有告诉我代码中崩溃的地方或我的代码的哪一部分有问题。在几个函数的开头和结尾记录后,我知道崩溃不是在 onCreateView 或 onCreateOptionsMenu 中发生的。根据此崩溃报告,我认为问题出在我这里的自定义适配器中:

public class LinksAdapter extends ArrayAdapter<Link> {

public LinksAdapter(Context context, ArrayList<Link> values) {
    super(context, R.layout.rowlayout, values);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    G.LOGGER.log(Level.INFO, "getView");
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view;
    G.LOGGER.log(Level.INFO, "Creation of row started");
    if (convertView == null) {
        view = inflater.inflate(R.layout.rowlayout, parent, false);
    } else {
        view = convertView;
    }
    Link link = getItem(position);
    TextView titleTextview = (TextView) view.getRootView().findViewById(R.id.row_title);
    titleTextview.setText(link.getTitle());
    TextView subtitleTextview = (TextView) view.getRootView().findViewById(R.id.row_subtitle);
    subtitleTextview.setText(link.getUrl());
    G.LOGGER.log(Level.INFO, "Creation of row ended");
    return view;
}
}

A Link 是一个简单的 class,具有 2 个属性的 getter 和 setter:标题和 Url,均为字符串。我什至不确定问题出在这个适配器上。我想知道是否有办法找出应用程序崩溃的位置。如果需要更多代码,请告诉我。

编辑:这里是rowlayout.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/selector_rowlayout">

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/row_title"
    android:textSize="20sp"/>

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/row_subtitle"
    android:textSize="15sp"/>

</LinearLayout>

和@drawable/selector_rowlayout:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true" android:drawable="@color/gray_light" />
<item android:state_focused="true" android:drawable="@color/gray_light" />
<item android:drawable="@android:color/transparent" />
</selector>

以及 strings.xml 中 gray_light 的条目:

<color name="gray_light">#D8D8D8</color>

这里是LinksMasterFragment,它使用LinksAdapter:

public class LinksMasterFragment extends MyFragment implements AdapterView.OnItemClickListener {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_links_master, container, false);
    LinksAdapter adapter = new LinksAdapter(this.getContext(), getUser().getLinks());
    ListView listView = (ListView) view.getRootView().findViewById(R.id.links_master_listview);
    G.LOGGER.log(Level.INFO, "links: " + getUser().getLinks());
    listView.setAdapter(adapter);
    listView.setOnItemClickListener(this);
    setHasOptionsMenu(true);
    G.LOGGER.log(Level.INFO, "created");
    return view;
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.menu_links, menu);
    super.onCreateOptionsMenu(menu, inflater);
    G.LOGGER.log(Level.INFO, "options menu created");
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == R.id.action_links_restoredefaults) {
        ArrayList<Link> defaultLinks = new ArrayList<>();
        defaultLinks.add(new Link("St. Matthew's Facebook", "http://www.facebook.com/StMatthewSchoolCCSD"));
        defaultLinks.add(new Link("St. Matthew's Twitter", "http://twitter.com/StMatthew_CCSD"));
        defaultLinks.add(new Link("English Dictionary", "http://dictionary.reference.com"));
        defaultLinks.add(new Link("Bescherelle", "http://conjugaison.com"));
        defaultLinks.add(new Link("French-English Dictionary", "http://mobile-dictionary.reverso.net/english-french/"));
        defaultLinks.add(new Link("Google Translate", "http://translate.google.com"));
        getUser().setLinks(defaultLinks);
        G.LOGGER.log(Level.INFO, "Links: " + (getUser().getLinks() == defaultLinks));
        ListView listView = (ListView)getView().getRootView().findViewById(R.id.links_master_listview);
        listView.setAdapter(new LinksAdapter(getContext(), getUser().getLinks()));
    }
    return false;
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    // push to detail with selected homework
    G.Links.index = position;
    LinksDetailFragment fragment = new LinksDetailFragment();
    fragment.setSchedule(getSchedule());
    fragment.setUser(getUser());
    getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.links_detail_container, fragment).commit();
}
}

关联的 xml 文件是 fragment_links_master:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fffbe14d">

<ListView
    android:layout_width="200dp"
    android:layout_height="match_parent"
    android:id="@+id/links_master_listview">

</ListView>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/links_detail_container">
</FrameLayout>

</LinearLayout>

这里是MyFragment,LinksMasterFragment的superclass.

public class MyFragment extends Fragment {

private User user;

public MyFragment() {}

public Context getContext() {
    return getActivity().getBaseContext();
}

public User getUser() {
    if (user != null) {
        return user;
    }
    return new User(getContext(), "");
}
}

和用户 class,访问所有永久用户数据。

public class User extends DatabaseHelper {

public User(Context context, String id) {
    super(context);
    this.id = id;
    Cursor res = db.query(TABLE_USERS, new String[] {"Name"}, "ID = ?", new String[] {id}, null, null, null);
    G.LOGGER.log(Level.INFO, "Count: " + res.getCount());
    if (res.getCount() == 0) {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues contentValues = new ContentValues();
        contentValues.put("Name", "");
        contentValues.put("Links", "");
        db.insert(TABLE_USERS, null, contentValues);
        setLinks(new ArrayList<Link>() {
        });
    }
    res.close();
}

public ArrayList<Link> getLinks() {
    ArrayList<Link> emptyArray= new ArrayList<>();
    Cursor cursor = db.query(TABLE_USERS, new String[]{COL_LINKS}, "ID = ?", new String[]{id}, null, null, null);
    cursor.moveToFirst();
    if (cursor.getCount() == 0) {
        return emptyArray;
    }
    String string = cursor.getString(0);
    cursor.close();
    Type type = new TypeToken<ArrayList<Link>>(){}.getType();
    ArrayList<Link> finalArray = new Gson().fromJson(string, type);
    G.LOGGER.log(Level.INFO, "Links: " + finalArray);
    if (finalArray != null && finalArray.size() != 0) {
        return finalArray;
    } else {
        return emptyArray;
    }
}
}

P.S。我实际上是 Android 的新手,因为我主要是一名 iOS 开发人员,所以如果有我不遵守的约定,请告诉我。

用这个替换你的getView方法,告诉我它是怎么回事。

  @Override
  public View getView(int position, View convertView, ViewGroup parent)
  {

    if (convertView == null)
    {
      convertView = LayoutInflater.from(getContext()).inflate(R.layout.rowlayout, parent, false);
    }

    Link link = getItem(position);
    TextView titleTextview = (TextView) convertView.findViewById(R.id.row_title);
    titleTextview.setText(link.getTitle());
    TextView subtitleTextview = (TextView) convertView.findViewById(R.id.row_subtitle);
    subtitleTextview.setText(link.getUrl());
    return convertView;
  }

我通过将 getView() 方法添加到不同的行布局 class 解决了这个问题。不确定它为什么起作用,但确实起作用了。