java - 在创建 fragment 之前更改 fragment 时应用程序崩溃

标签 java android android-glide

我在主要 Activity 上有 2 个 fragment ,并用 2 个按钮替换它们。 第一个按钮 - 灯光 fragment 。 第二个按钮 - 车库 fragment 。 Lights fragment - 应用程序打开时创建的主要 fragment 。 此 fragment 包含 RecyclerView 以及使用 Glide 从 firebase 加载的图像。

问题是,当应用程序打开时,如果 LightsFragment 上的图像仍未加载,并且我更改为第二个 fragment (GarageFragment),因此当我返回 LightsFragment 时,应用程序崩溃 - 请参阅代码下面的日志。

灯光适配器:

import java.util.ArrayList;

public class LightsAdapter extends RecyclerView.Adapter<LightsAdapter.LightsViewHolder> {

    private Context context;
    private ArrayList<Light> lights;
    private OnLightImageTouchListener onLightImageTouchListener;
    private int selected = -1;
    private Light light;

    public LightsAdapter(Context context, ArrayList<Light> lights) {
        this.context = context;
        this.lights = lights;
    }

    public void updateData(ArrayList<Light> lights) {
        this.lights = lights;
        notifyDataSetChanged();
    }


    public interface OnLightImageTouchListener {
        void onLightImageTouch(int position, MotionEvent motionEvent, LightsViewHolder holder);
    }

    public void setOnLightImageTouchListener(OnLightImageTouchListener onLightImageTouchListener) {
        this.onLightImageTouchListener = onLightImageTouchListener;
    }

    @NonNull
    @Override
    public LightsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, final int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.lights_item, parent, false);
        return new LightsViewHolder(view);
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public void onBindViewHolder(@NonNull final LightsViewHolder holder, final int position) {
        light = lights.get(position);
        holder.rootItemView.setTag(position);

        **//Glide - image loader.
        Glide.with(context)
                .load(light.getLampImageUrl())
                .placeholder(R.drawable.ic_launcher_background)
                .override(200, 200)
                .into(holder.IVLightImage);**


        setLightColor(holder, position);

        //This method called from LightsFragment.
        holder.rootItemView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                int position = (int) view.getTag();
                selected = position;
                if (onLightImageTouchListener != null) {
                    onLightImageTouchListener.onLightImageTouch(position, motionEvent, holder);
                }
                return true;
            }
        });
    }

    @Override
    public int getItemCount() {
        return lights.size();
    }

    public class LightsViewHolder extends RecyclerView.ViewHolder {

        private ImageView IVLightImage;
        private CardView rootItemView;


        public LightsViewHolder(@NonNull View itemView) {
            super(itemView);
            IVLightImage = itemView.findViewById(R.id.lightImage);
            rootItemView = itemView.findViewById(R.id.rootItemView);
        }
    }

    //Open light information on bottom sheet dialog.
    public void openLightInfo(int position) {
        View modelBottomSheet = LayoutInflater.from(context).inflate(R.layout.lights_info_bottom_sheet, null);
        BottomSheetDialog dialog = new BottomSheetDialog(context);
        dialog.setContentView(modelBottomSheet);
        TextView TVlightTitle = dialog.findViewById(R.id.lightTitle);
        TextView TVLightDesc = dialog.findViewById(R.id.lightDesc);
        TextView TVLightType = dialog.findViewById(R.id.lightType);
        TVlightTitle.setText(lights.get(position).getLampTitle());
        TVLightDesc.setText(lights.get(position).getLampDesc());
        TVLightType.setText(String.valueOf(lights.get(position).getLampType()));
        dialog.show();
    }

    //Set light color according to warning priority (1-4)
    public void setLightColor(LightsViewHolder holder, int position) {
        switch (lights.get(position).getLampType()) {
            case 1:
                holder.IVLightImage.setColorFilter(Color.RED);
                break;
            case 2:
                holder.IVLightImage.setColorFilter(Color.YELLOW);
                break;
            case 3:
                holder.IVLightImage.setColorFilter(Color.GREEN);
                break;
            case 4:
                holder.IVLightImage.setColorFilter(Color.BLUE);
                break;
        }
    }
}

LightsView - 数据加载器:

public class LightsView {

    private ArrayList<Light> lights = new ArrayList<>();
    private Light light;
    private FirebaseDatabase db;
    private DatabaseReference allLights;
    private LightsPresenter lightsPresenter;

    public LightsView(ArrayList<Light> lights, Light light, LightsPresenter lightsPresenter) {
        this.lights = lights;
        this.light = light;
        this.lightsPresenter = lightsPresenter;
    }

    public void loadData() {
        db = FirebaseDatabase.getInstance();
        allLights = db.getReference("AllLights");
        allLights.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
                    light = dataSnapshot1.getValue(Light.class);
                    lights.add(light);
                    Log.i("LightsDataLoaded", "true " + light.getLampTitle());
                }
                lightsPresenter.setAdapter();
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {
                Log.i("LightsDataLoaded", "false ");
            }
        });
    }

}

MainActivity - 创建 LightsFragment 的 onCreate 方法:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initFunctions();
    }

    public void initFunctions() {
        showLightsFragment();
        showGreetings();
    }

    **public void showLightsFragment() {
        getSupportFragmentManager().beginTransaction().replace(R.id.main_fragment_container, this.lightsFragment)
                .commit();
    }**

灯光模型:

public class Light implements Comparable<Light> {

    private int lampType;
    private String lampTitle;
    private String lampDesc;
    private String lampImageUrl;

    public Light() {
    }

    public Light(int lampType, String lampTitle, String lampDesc, String lampImageUrl) {
        this.lampType = lampType;
        this.lampTitle = lampTitle;
        this.lampDesc = lampDesc;
        this.lampImageUrl = lampImageUrl;
    }

    public int getLampType() {
        return lampType;
    }

    public void setLampType(int lampType) {
        this.lampType = lampType;
    }

    public String getLampTitle() {
        return lampTitle;
    }

    public void setLampTitle(String lampTitle) {
        this.lampTitle = lampTitle;
    }

    public String getLampDesc() {
        return lampDesc;
    }

    public void setLampDesc(String lampDesc) {
        this.lampDesc = lampDesc;
    }

    public String getLampImageUrl() {
        return lampImageUrl;
    }

    public void setLampImageUrl(String lampImageUrl) {
        this.lampImageUrl = lampImageUrl;
    }

    @Override
    public int compareTo(Light o) {
        return Integer.compare(lampType, o.lampType);
    }
}

灯光 fragment :

public class LightsFragment extends Fragment implements LightsPresenter {

    private RecyclerView RVLights;
    private ArrayList<Light> lights = new ArrayList<>();
    private Light light;
    private LightsAdapter lightsAdapter;
    private LightsView presenter;
    private View view;
    private Animation animation;

    public LightsFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        if (view == null) {
            view = inflater.inflate(R.layout.fragment_lights, container, false);
            initView(view);
            if (getActivity() != null) {
                presenter = new LightsView(lights, light, this);
                presenter.loadData();
            }
        }
        return view;
    }

    //Setting adapter parameters.
    @Override
    public void setAdapter() {
        lightsAdapter = new LightsAdapter(getActivity(), lights);
        RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), 3);
        RVLights.setLayoutManager(layoutManager);
        RVLights.setAdapter(lightsAdapter);
        lightsAdapter.setOnLightImageTouchListener(new LightsAdapter.OnLightImageTouchListener() {
            @Override
            public void onLightImageTouch(final int position, MotionEvent event, LightsAdapter.LightsViewHolder holder) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        animation = AnimationUtils.loadAnimation(getActivity(), R.anim.fade_in);
                        holder.itemView.startAnimation(animation);
                        Log.d("IsTouched", "positionTouchedDown " + position);
                        MainActivity mainActivity = (MainActivity) getActivity();
                        mainActivity.removeSortFragment();
                        break;
                    case MotionEvent.ACTION_UP:
                        final Handler handler = new Handler();
                        handler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                lightsAdapter.openLightInfo(position);
                                lightsAdapter.notifyDataSetChanged();
                            }
                        }, 100);
                        Log.d("IsTouched", "positionTouchedUP" + position);
                        break;
                }
            }
        });
    }

    //Sorting adapter by warning color ( 1-4, red - blue )
    public void sortAdapter() {
        Collections.sort(lights);
        lightsAdapter.updateData(lights);
    }

    //Initializing views.
    public void initView(View view) {
        RVLights = view.findViewById(R.id.RVLights);
    }
}

来自 logcat 的日志:

2019-11-12 15:51:57.939 6889-6889/com.enjoyapp.carhelper E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.enjoyapp.carhelper, PID: 6889
    java.lang.NullPointerException: You cannot start a load on a not yet attached View or a Fragment where getActivity() returns null (which usually occurs when getActivity() is called before the Fragment is attached or after the Fragment is destroyed).
        at com.bumptech.glide.util.Preconditions.checkNotNull(Preconditions.java:31)
        at com.bumptech.glide.Glide.getRetriever(Glide.java:684)
        at com.bumptech.glide.Glide.with(Glide.java:716)
        at com.enjoyapp.carhelper.Adapters.LightsAdapter.onBindViewHolder(LightsAdapter.java:67)
        at com.enjoyapp.carhelper.Adapters.LightsAdapter.onBindViewHolder(LightsAdapter.java:26)
        at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6781)
        at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6823)
        at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5752)
        at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6019)
        at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5858)
        at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5854)
        at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2230)
        at androidx.recyclerview.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:557)
        at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1517)
        at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:612)
        at androidx.recyclerview.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:171)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3924)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3641)
        at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4194)
        at android.view.View.layout(View.java:20726)
        at android.view.ViewGroup.layout(ViewGroup.java:6198)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
        at android.view.View.layout(View.java:20726)
        at android.view.ViewGroup.layout(ViewGroup.java:6198)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
        at android.view.View.layout(View.java:20726)
        at android.view.ViewGroup.layout(ViewGroup.java:6198)
        at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1083)
        at android.view.View.layout(View.java:20726)
        at android.view.ViewGroup.layout(ViewGroup.java:6198)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
        at android.view.View.layout(View.java:20726)
        at android.view.ViewGroup.layout(ViewGroup.java:6198)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
        at android.view.View.layout(View.java:20726)
        at android.view.ViewGroup.layout(ViewGroup.java:6198)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
        at android.view.View.layout(View.java:20726)
        at android.view.ViewGroup.layout(ViewGroup.java:6198)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
        at android.view.View.layout(View.java:20726)
        at android.view.ViewGroup.layout(ViewGroup.java:6198)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:261)

最佳答案

尝试重写 LightsFragment 内和该方法调用内的“onViewCreated”方法

initView(view);

然后重写方法“onAttach”并在其中写入

presenter = new LightsView(lights, light, this);
presenter.loadData();

请注意,因为 fragment 是 View 而不是演示者。在本例中,演示者是您的 LightsView。演示者采用 View 的所有逻辑,而 View 则显示演示者告诉它执行的操作。所以,你必须在LightsView中实现“LightsPresenter”。

关于java - 在创建 fragment 之前更改 fragment 时应用程序崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58820262/

相关文章:

android - Glide 4.7.1版本添加RequestListener时无法加载Gif到ImageView

java - 使用 ASM 字节码转换时 java.lang.instrument 中出现堆栈溢出错误

java - 关于servlet多线程环境的问题

java - 当 Fragment.instantiate 优于 MyFragment.newInstance 或 new MyFragment()

android - Kotlin 导航 fragment 中的 searchview.setonquerytextlistener() 类型不匹配

android - 谷歌地图 Android API : SupportMapFragment vs MapFragment

Android内存泄漏与Glide

java - StringBuilder 在转换为 String 时丢失数据

java - 想要检索给定 WebElement 的 Xpath

android - Glide 4.3.1 覆盖和占位符功能不起作用