Android在fragment中使用listview导致界面闪退

新手上路,请多包涵

我写了一个Activity,
然后通过点击底部菜单切换三个fragment,
我在第一个fragment中使用了一个listview,
然后就会导致每次进到这个activity界面就会闪退,
去掉listview.setAdapter(adapter)的语句后
界面就不闪退了,代码如下:

主Activity

package com.example.mr4gon.uiapp;

import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;

import com.example.mr4gon.adapter.WorkAdapter;
import com.example.mr4gon.entity.Work;
import com.example.mr4gon.fragment.HomeFragment;
import com.example.mr4gon.fragment.InfoFragment;
import com.example.mr4gon.fragment.MineFragment;

import java.util.ArrayList;
import java.util.List;

public class HomeActivity extends AppCompatActivity  {

    private List<Work> workList=new ArrayList<>();

    protected HomeFragment homeFragment=new HomeFragment();
    protected MineFragment mineFragment=new MineFragment();
    protected InfoFragment infoFragment=new InfoFragment();

    private TextView mTextMessage;



    //底部菜单栏切换事件
    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {

        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()) {
                case R.id.navigation_home:
                    mTextMessage.setText("主页");
                    getSupportFragmentManager().beginTransaction().show(homeFragment)
                            .hide(mineFragment).hide(infoFragment).commit();
                    return true;
                case R.id.navigation_dashboard:
                    mTextMessage.setText("个人中心");
                    getSupportFragmentManager().beginTransaction().hide(homeFragment)
                            .show(mineFragment).hide(infoFragment).commit();
                    return true;
                case R.id.navigation_notifications:
                    mTextMessage.setText("通知");
                    getSupportFragmentManager().beginTransaction().hide(homeFragment)
                            .hide(mineFragment).show(infoFragment).commit();
                    return true;
            }
            return false;
        }

    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        //菜单栏切换
        mTextMessage = (TextView) findViewById(R.id.message);
        BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
        //fragment切换
        this.getSupportFragmentManager().beginTransaction()
                .add(R.id.main_content,homeFragment)
                .add(R.id.main_content,mineFragment).hide(mineFragment)
                .add(R.id.main_content,infoFragment).hide(infoFragment)
                .commit();
        //初始化伪数据
        initWork();
        //主页适配器
        WorkAdapter adapter=new WorkAdapter(HomeActivity.this,R.layout.work_item,workList);
       ListView listview=(ListView)findViewById(R.id.mylistview);
        listview.setAdapter(adapter);



    }

    //页面点击事件
    public void onClick(View v) {
        switch (v.getId()){
            //点击退出按钮
            case R.id.exit_btn:
                AlertDialog.Builder dialog =new AlertDialog.Builder(HomeActivity.this);
                dialog.setTitle("提示");
                dialog.setMessage("确认退出登录?");
                dialog.setCancelable(false);
                dialog.setPositiveButton("是", new DialogInterface.OnClickListener(){
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish();;
                    }
                });
                dialog.setNegativeButton("否",new DialogInterface.OnClickListener(){
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                });
                dialog.show();
                break;
            //点击修改资料
            case R.id.modify_btn:
                Intent intent =new Intent(HomeActivity.this,ModifyActivity.class);
                startActivity(intent);
                break;
            //点击我的作品
            case R.id.mywork_btn:
                Intent intent1=new Intent(HomeActivity.this,WorkActicity.class);
                intent1.putExtra("worktype","1");
                startActivity(intent1);
                break;
            //点击我的改编
            case R.id.myadapt_btn:
                Intent intent2=new Intent(HomeActivity.this,WorkActicity.class);
                intent2.putExtra("worktype","2");
                startActivity(intent2);
                break;
            //点击发表作品
            case R.id.publish_btn:
                Intent intent3=new Intent(HomeActivity.this,PublishActivity.class);
                startActivity(intent3);

            default:
                break;
        }
    }
    //循环制作伪数据
    private void initWork(){
        for (int i=0;i<2;i++){
            Work work=new Work(i,"番茄炒蛋", "无名氏",R.drawable.egg, "简单,美味", 9.0);
            workList.add(work);
        }
    }
}

Fragment类

package com.example.mr4gon.fragment;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;

import com.example.mr4gon.uiapp.R;

/**
 * Created by Mr4gon on 2017/9/15.
 */

public class HomeFragment extends Fragment {

    public View listview;

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

        View v = inflater.inflate(R.layout.home_fragment, container, false);

        listview = (ListView) v.findViewById(R.id.mylistview);

        return v;

    }


    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        Log.d("d1", "onActivityCreated: ");
        super.onActivityCreated(savedInstanceState);
    }

}

主Activity布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.mr4gon.uiapp.HomeActivity">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:background="@drawable/title"
        android:elevation="3dp">
        <TextView
            android:id="@+id/message"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="主页"
            android:layout_centerInParent="true"
            android:layout_centerHorizontal="true"
            android:textColor="#fff"
            android:textSize="18dp"/>
    </RelativeLayout>

    <FrameLayout
        android:id="@+id/main_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">
    </FrameLayout>

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="?android:attr/windowBackground"
        app:menu="@menu/navigation" />

</LinearLayout>

Fragment布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ListView
        android:id="@+id/mylistview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </ListView>
</RelativeLayout>

Adapter

package com.example.mr4gon.adapter;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.mr4gon.entity.Work;
import com.example.mr4gon.uiapp.R;

import java.util.List;

/**
 * Created by Mr4gon on 2017/9/15.
 */

public class WorkAdapter extends ArrayAdapter<Work> {
    private int resoutId;
    public WorkAdapter(Context context, int textViewResourceId, List<Work> objects){
        super(context,textViewResourceId,objects);
        resoutId=textViewResourceId;
    }

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


        Work work=getItem(position);
        View view= LayoutInflater.from(getContext()).inflate(resoutId,parent,false);

        ImageView w_picture=(ImageView)view.findViewById(R.id.w_picture);
        TextView w_name=(TextView)view.findViewById(R.id.w_name);
        TextView w_author=(TextView)view.findViewById(R.id.w_author);
        TextView keywords=(TextView)view.findViewById(R.id.keywords);
        TextView rate=(TextView)view.findViewById(R.id.rate);
        w_picture.setImageResource(work.getW_picture());
        w_name.setText(work.getW_name());
        w_author.setText(work.getW_author());
        keywords.setText(work.getKeywords());
        rate.setText(""+work.getRate());
        return  view;
    }
}

Workitem

<?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="wrap_content"
    android:layout_margin="20dp">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="10dp"
        android:layout_margin="15dp">
        <ImageView
            android:id="@+id/w_picture"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:layout_weight="4" />
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="5"
            android:orientation="vertical"
            android:layout_marginLeft="20dp">
            <TextView
                android:id="@+id/w_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="作品名"
                android:layout_weight="1"
                android:textSize="20dp"/>
            <TextView
                android:id="@+id/w_author"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="作者名"
                android:layout_weight="1"/>
            <TextView
                android:id="@+id/keywords"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="关键字"
                android:layout_weight="1"/>
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:layout_weight="1">
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="评分:"
                    android:textSize="18dp"/>
                <TextView
                    android:id="@+id/rate"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="9.7"
                    android:textColor="#ff0000"
                    android:textSize="18dp"/>
            </LinearLayout>
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

报错信息

09-23 19:45:36.208 4220-4220/com.example.mr4gon.uiapp E/AndroidRuntime: FATAL EXCEPTION: main
                                                                        Process: com.example.mr4gon.uiapp, PID: 4220
                                                                        java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.mr4gon.uiapp/com.example.mr4gon.uiapp.HomeActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference
                                                                            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2733)
                                                                            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2807)
                                                                            at android.app.ActivityThread.access$900(ActivityThread.java:192)
                                                                            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1629)
                                                                            at android.os.Handler.dispatchMessage(Handler.java:111)
                                                                            at android.os.Looper.loop(Looper.java:192)
                                                                            at android.app.ActivityThread.main(ActivityThread.java:5917)
                                                                            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:1099)
                                                                            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:865)
                                                                         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.example.mr4gon.uiapp.HomeActivity.onCreate(HomeActivity.java:83)
                                                                            at android.app.Activity.performCreate(Activity.java:6200)
                                                                            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
                                                                            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2680)
                                                                            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2807) 
                                                                            at android.app.ActivityThread.access$900(ActivityThread.java:192) 
                                                                            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1629) 
                                                                            at android.os.Handler.dispatchMessage(Handler.java:111) 
                                                                            at android.os.Looper.loop(Looper.java:192) 
                                                                            at android.app.ActivityThread.main(ActivityThread.java:5917) 
                                                                            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:1099) 
                                                                            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:865) 
09-23 19:45:36.233 4220-4220/com.example.mr4gon.uiapp I/Process: Sending signal. PID: 4220 SIG: 9
阅读 6.5k
3 个回答
新手上路,请多包涵

//主页适配器

    WorkAdapter adapter=new WorkAdapter(HomeActivity.this,R.layout.work_item,workList);
   ListView listview=(ListView)findViewById(R.id.mylistview);
   这里的findviewbyid是在homeActivity的布局xml文件里find的,而该布局文件很明显没有这个view啦
   这段代码(包括adapter的实例化)应该放在fragment里才比较规范...
//fragment切换
this.getSupportFragmentManager().beginTransaction()
    .add(R.id.main_content,homeFragment)
    .add(R.id.main_content,mineFragment).hide(mineFragment)
    .add(R.id.main_content,infoFragment).hide(infoFragment)
    .commit();

这一段加载fragment的代码,并不是执行以后,fragment就被加载到Activity了。FragmentManager commit一个事务是异步执行的。

ListView listview=(ListView)findViewById(R.id.mylistview);

当你在执行以上代码时:
findViewById是从Activity的布局去find,但是find的目标是还没有加载进来的mylistview。所以这个View找不到,所以listview等于null。最终导致空指针发生。

考虑以下步骤:

  • 你可以把findViewById放在postDely中延迟几秒执行,来验证bug产生的原因。
  • 单一职责:将ListView的管理,放在对应的Fragment的onCreateView中。

补充一些知识点:

  • 界面正在显示的时候,存在一个Window对象,Window对象中存在一个最顶级的View叫做DecorView。

    /** @hide */
    public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks
  • 一个Activity和它加载的Fragment处在同一个Window中。
  • ActivityfindViewById方法实际上是调用了getWindow().findViewById(id);而这个getWindow()实际上是一个PhoneWindow对象。而Window中的findViewById实际上是调用了getDecorView().findViewById(id);最终,也就是说,Activity寻找View的时候,是调用了最顶层的一个ViewGroup(DecorView)的findViewById。

补充说明的结论是:在Activity中可以找到其已经加载出来的Fragment的View,即使这个View没有定义在Activity的layout中。

结论的结论:遇到问题去跟踪源码,是一个非常有效的从本质上理解问题的手段。

ListView listview=(ListView)findViewById(R.id.mylistview); 问题出在这里 findviewbyid 在mainactivity中执行 这时去找主Activity布局.xml中的mylistview,但是主Activity布局.xml中并不存在mylistview,此时findviewbyid方法返回view被listview变量接收,此时的值未null ,然后下一句listview.xxxx会造成指针错误 然后crash。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题