列表视图片段不会显示

List View Fragment Won't Display

我正在尝试使用 ListFragment 在我的主 activity 中显示一个列表。该列表由使用自定义对象的自定义 ArrayAdapter 填充。我无法在应用程序中显示此列表。当我调试时,它没有显示任何错误,但应用程序立即崩溃。

这是我的片段

编辑:我尝试了几种响应,并将问题缩小到 ListViewFragment 中的 momentObjectListView.setAdapter(momentObjectAdapter)。我找不到 momentObjectAdapter 为 null 的原因,所以它必须是 momentObjectListView 但是我找不到问题的根源。任何帮助将非常感激。我的 activity_main.xml、片段、主要 activity 和适配器代码都包含在内。

public class ListViewFragment extends ListFragment {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {


    Activity myAct = getActivity();
    View view = inflater.inflate(R.layout.activity_main, container, false);
    ListView momentObjectListView = (ListView)view.findViewById(R.id.list_item);
    //ListView momentObjectListView = getListView();

    MomentObjectAdapter momentObjectAdapter = new MomentObjectAdapter(myAct, R.layout.moment_object_list_item);

    //momentObjectListView.setAdapter(momentObjectAdapter);

    List<MomentObject> myMoments = getMoments();
    for(final MomentObject entry : myMoments) {
        momentObjectAdapter.add(entry);
    }

    //ListViewFragment.this.setListAdapter(momentObjectAdapter);
    momentObjectListView.setAdapter(momentObjectAdapter);

    return view;
}

private List<MomentObject> getMoments() {

    // Let's setup some test data.
    // Normally this would come from some asynchronous fetch into a data source
    // such as a sqlite database, or an HTTP request

    final List<MomentObject> entries = new ArrayList<MomentObject>();

    for(int i = 1; i < 50; i++) {
        entries.add(
                new MomentObject(
                        "Test Entry " + i,
                        "Anonymous Author",
                        new GregorianCalendar(2011, 11, i).getTime(),
                        R.drawable.photoicon
                )
        );
    }

    return entries;
}

}

这是我的 activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"
android:background="#ffffffff">

<fragment android:name="com.malatras.moment2.ListViewFragment"
    android:id="@+id/list"
    android:layout_weight="1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
/>

如果我需要提供什么来解决这个问题,请告诉我。

LogCat:

    e02-24 18:54:29.119    2325-2325/com.malatras.moment2 I/art﹕ Not late-enabling -Xcheck:jni (already on)
02-24 18:54:29.191    2325-2325/com.malatras.moment2 D/AndroidRuntime﹕ Shutting down VM
02-24 18:54:29.191    2325-2325/com.malatras.moment2 E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.malatras.moment2, PID: 2325
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.malatras.moment2/com.malatras.moment2.MainActivity}: android.view.InflateException: Binary XML file line #9: Error inflating class fragment
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2298)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
            at android.app.ActivityThread.access0(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            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:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
     Caused by: android.view.InflateException: Binary XML file line #9: Error inflating class fragment
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:763)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:365)
            at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:377)
            at android.app.Activity.setContentView(Activity.java:2144)
            at com.malatras.moment2.MainActivity.onCreate(MainActivity.java:11)
            at android.app.Activity.performCreate(Activity.java:5933)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
            at android.app.ActivityThread.access0(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            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:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference
            at com.malatras.moment2.ListViewFragment.onCreateView(ListViewFragment.java:34)
            at android.app.Fragment.performCreateView(Fragment.java:2053)
            at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:870)
            at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1045)
            at android.app.FragmentManagerImpl.addFragment(FragmentManager.java:1147)
            at android.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2116)
            at android.app.Activity.onCreateView(Activity.java:5282)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:733)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:365)
            at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:377)
            at android.app.Activity.setContentView(Activity.java:2144)
            at com.malatras.moment2.MainActivity.onCreate(MainActivity.java:11)
            at android.app.Activity.performCreate(Activity.java:5933)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
            at android.app.ActivityThread.access0(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            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:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

主要活动:

public class MainActivity extends ListActivity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

MomentObjectAdapter:

    public final class MomentObjectAdapter extends ArrayAdapter<MomentObject> {

    private final int momentObjectLayoutResource;

    public MomentObjectAdapter(final Context context, final int momentObjectLayoutResource) {
        super(context, 0);
        this.momentObjectLayoutResource = momentObjectLayoutResource;
    }

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

        // We need to get the best view (re-used if possible) and then
        // retrieve its corresponding ViewHolder, which optimizes lookup efficiency
        final View view = getWorkingView(convertView);
        final ViewHolder viewHolder = getViewHolder(view);
        final MomentObject entry = getItem(position);

        // Setting the title view is straightforward
        viewHolder.titleView.setText(entry.getTitle());

        // Setting the subTitle view requires a tiny bit of formatting
        final String formattedSubTitle = String.format("By %s on %s",
                entry.getAuthor(),
                DateFormat.getDateInstance(DateFormat.SHORT).format(entry.getPostDate())
        );

        viewHolder.subTitleView.setText(formattedSubTitle);

        // Setting image view is also simple
        viewHolder.imageView.setImageResource(entry.getIcon());

        return view;
    }

    private View getWorkingView(final View convertView) {
        // The workingView is basically just the convertView re-used if possible
        // or inflated new if not possible
        View workingView = null;

        if(null == convertView) {
            final Context context = getContext();
            final LayoutInflater inflater = (LayoutInflater)context.getSystemService
                    (Context.LAYOUT_INFLATER_SERVICE);

            workingView = inflater.inflate(momentObjectLayoutResource, null);
        } else {
            workingView = convertView;
        }

        return workingView;
    }

    private ViewHolder getViewHolder(final View workingView) {
        // The viewHolder allows us to avoid re-looking up view references
        // Since views are recycled, these references will never change
        final Object tag = workingView.getTag();
        ViewHolder viewHolder = null;


        if(null == tag || !(tag instanceof ViewHolder)) {
            viewHolder = new ViewHolder();

            viewHolder.titleView = (TextView) workingView.findViewById(R.id.moment_object_title);
            viewHolder.subTitleView = (TextView) workingView.findViewById(R.id.moment_object_subtitle);
            viewHolder.imageView = (ImageView) workingView.findViewById(R.id.moment_object_icon);

            workingView.setTag(viewHolder);

        } else {
            viewHolder = (ViewHolder) tag;
        }

        return viewHolder;
    }

    /**
     * ViewHolder allows us to avoid re-looking up view references
     * Since views are recycled, these references will never change
     */
    private static class ViewHolder {
        public TextView titleView;
        public TextView subTitleView;
        public ImageView imageView;
    }


}

moment_object_list_item:

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

<!-- Layout for individual news entries in a list -->
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">

    <!-- Icon shown next to the title/subtitle -->
        <ImageView
            android:id="@+id/moment_object_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_alignParentLeft="true"
            android:padding="3dp" />

    <!-- Title of the news entry -->
        <TextView
            android:id="@+id/moment_object_title"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@id/moment_object_icon"
            android:layout_alignTop="@id/moment_object_icon"
            android:layout_margin="5dp"
            android:textSize="14sp"
            android:textStyle="bold" />

    <!-- Subtitle contains author and date -->
        <TextView
            android:id="@+id/moment_object_subtitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@id/moment_object_title"
            android:layout_below="@id/moment_object_title"
            android:textSize="12sp" />

    </RelativeLayout>

在您的 XML 文件中更改此行:android:id="@+id/list"

至:

android:id="@id/android:list

并在 ListViewFragment 中更改为:ListView momentObjectListView =(ListView)view.findViewById(R.id.list)

对此:

ListView momentObjectListView = (ListView)view.findViewById(android.R.id.list);

在你的 Logcat 文件中,它说

android.view.InflateException: Binary XML file line #9: Error inflating class fragment

这意味着 xml 文件不正确。在日志中也更深入,

The code MainActivity.onCreate(MainActivity.java:11) ...

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference at com.malatras.moment2.ListViewFragment.onCreateView(ListViewFragment.java:34) ...

ListViewFragment.onCreateView(ListViewFragment.java:34)

也需要加载文件 ListViewFragment.java。为了节省时间,也许post个文件。

另一个可能好的代码更改是修改 ListViewFragment 定义:

public class ListViewFragment extends ListFragment {

至:

public class ListViewFragment extends Fragment implements AbsListView.OnItemClickListener {

OnItemClickListener 是可选的。

我之所以这样说是因为 MainActivity 已经通过 ListActivity 承载了 ListView 对象。另一个原因是,Android Studio 向导会生成 "to" 建议代码。这对我来说听起来不错。

另一种方法是将 ListActivity 从 MainActivity 中删除为仅 Activity,原因相同。

然而,所有这些建议都可以被视为代码风格。

我不喜欢并且与您的方法 getMoments 不兼容的这段代码是:

for(final MomentObject entry : getMoments()) {
        momentObjectAdapter.add(entry);
    }

现在试试这个快速示例修复:

List<MomentObject> myMoments = getMoments();
for(final MomentObject entry : myMoments) {

原因是 for 循环中的 getMoments() 是动态求值的。我认为是这样,即使你用 final 声明了它。

在日志中,

Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference

我认为对象 momentObjectListView 为空。我在 fragment_list_view.xml 中找不到 UI。但是在 activity_main.xml 中。示例代码:

View view = inflater.inflate(R.layout.activity_main, container, false);
ListView momentObjectListView = (ListView)view.findViewById(R.id.list);

activity_main:

中 ListFragment 的示例布局元素
 <fragment android:name="com.malatras.moment2.ListViewFragment"
 android:id="@+id/list"
 ...>

了解基础知识需要一个解释布局的好网页@ Layouts