首页 > 解决方案 > 主题更改后应用程序崩溃(显然是由片段引起的)

问题描述

我的主要活动有三个选项卡。每个选项卡都是一个片段。现在,如果您更改主题(白色和深色都可用),则会重新创建活动以使更改生效。但是应用程序崩溃了。

我如何处理碎片:

if (savedInstanceState == null) {
        pageadapter = new SectionsPageAdapter(getSupportFragmentManager());
        rFragMore = new RoomlistFragmentMore();
        rFragMyRooms = new RoomlistFragmentMyRooms();
        rFragFavs = new RoomlistFragmentFavorites();
    } else {
        rFragMyRooms = (RoomlistFragmentMyRooms)pageadapter.getItem(0);
        rFragFavs = (RoomlistFragmentFavorites)pageadapter.getItem(1);
        rFragMore = (RoomlistFragmentMore)pageadapter.getItem(2);
        pageadapter.clearAdapter();
        pageadapter = new SectionsPageAdapter(getSupportFragmentManager());
    }

我如何设置适配器:

private void setupViewPager(ViewPager viewPager) {
    pageadapter.addFragment(rFragMyRooms, getResources().getString(R.string.myrooms));
    pageadapter.addFragment(rFragFavs, getResources().getString(R.string.favorites));
    pageadapter.addFragment(rFragMore, getResources().getString(R.string.more));
    viewPager.setAdapter(pageadapter);
}

我的适配器:

public class SectionsPageAdapter extends FragmentPagerAdapter {

    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public void addFragment(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    public void clearAdapter() {
        mFragmentList.clear();
        mFragmentTitleList.clear();
    }

    public SectionsPageAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }
}

和错误日志:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.FileInputStream android.content.Context.openFileInput(java.lang.String)' on a null object reference
    at com.yannick.mychatapp.RoomlistFragmentMore.readFromFile(RoomlistFragmentMore.java:246)
    at com.yannick.mychatapp.RoomlistFragmentMore.addRoomToList(RoomlistFragmentMore.java:121)
    at com.yannick.mychatapp.RoomlistFragmentMore.access$000(RoomlistFragmentMore.java:46)
    at com.yannick.mychatapp.RoomlistFragmentMore$1.onDataChange(RoomlistFragmentMore.java:79)
    at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database@@16.0.4:75)
    at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database@@16.0.4:63)
    at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database@@16.0.4:55)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6669)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

编辑:RoomlistFragment的代码更多

public class RoomlistFragmentMore extends Fragment {

private ListView listView;
private List<HashMap<String, String>> listItems = new ArrayList<>();
private String raumname, theme;
private static String userID = "";
private SimpleAdapter adapter;
private DatabaseReference root = FirebaseDatabase.getInstance().getReference().getRoot().child("rooms");
private ArrayList<Room> raumliste = new ArrayList<>();
private TextView keinraumgefunden;
private String[] kat;
private static final String TAG = "RoomlistFragmentMore";

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.roomlist_fragment_more,container,false);

    listView = view.findViewById(R.id.listView);
    keinraumgefunden = view.findViewById(R.id.keinraumgefunden);

    kat = getResources().getStringArray(R.array.categories);
    theme = readFromFile("mychatapp_theme.txt");

    adapter = new SimpleAdapter(getActivity(), listItems, R.layout.listlayout,
            new String[]{"name", "kat", "lock", "newest"},
            new int[]{R.id.raumname, R.id.raumkat, R.id.raumlock, R.id.raumdatum});

    listView.setAdapter(adapter);

    root.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            addRoomToList(dataSnapshot);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            Toast.makeText(getActivity(), R.string.nodatabaseconnection, Toast.LENGTH_SHORT).show();
        }
    });

    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
            int position = listView.getPositionForView(view);
            String roomname = listItems.get(position).values().toArray()[0].toString();
            Room room = findRoom(raumliste, roomname);
            request_password(room, position);
        }
    });

    adapter.registerDataSetObserver(new DataSetObserver() {
        @Override
        public void onChanged() {
            if (raumliste.isEmpty()) {
                keinraumgefunden.setText(R.string.noroomfound);
            } else {
                keinraumgefunden.setText("");
            }
        }
    });

    return view;
}

private void addRoomToList(DataSnapshot dataSnapshot) {
    HashMap<String, String> raeume = new HashMap<>();
    raumliste.clear();

    for(DataSnapshot uniqueKeySnapshot : dataSnapshot.getChildren()){
        String name = uniqueKeySnapshot.getKey();
        for(DataSnapshot roomSnapshot : uniqueKeySnapshot.getChildren()){
            Room room = roomSnapshot.getValue(Room.class);
            room.setRaumname(name);
            if (!room.getPasswd().equals(readFromFile("mychatapp_raum_" + name + ".txt"))) {
                raeume.put(name, kat[Integer.parseInt(room.getCaty())]+"/"+"\uD83D\uDD12"+"/");
                raumliste.add(room);
            }
            break;
        }
    }

    listItems.clear();

    Iterator it = raeume.entrySet().iterator();
    while (it.hasNext()){
        HashMap<String, String> resultsMap = new HashMap<>();
        Map.Entry pair = (Map.Entry)it.next();
        resultsMap.put("name", pair.getKey().toString());
        String daten = pair.getValue().toString();
        String caty = daten.substring(0, daten.indexOf("/"));
        String lock = daten.substring(daten.indexOf("/")+1, daten.lastIndexOf("/"));
        String time = daten.substring(daten.lastIndexOf("/")+1, daten.length());
        String newestTime = "";
        int index = 0;
        resultsMap.put("kat", caty);
        resultsMap.put("lock", lock);
        resultsMap.put("newest", newestTime);
        if (time.equals("")) {
            listItems.add(resultsMap);
        } else {
            listItems.add(index, resultsMap);
        }
    }

    adapter.notifyDataSetChanged();
}

private void request_password(final Room room, final int position) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.enter_room, null);
    raumname = room.getRaumname();
    userID = readFromFile("mychatapp_userid.txt");
    final EditText input_field = view.findViewById(R.id.room_password);
    AlertDialog.Builder builder;
    if (theme.equals(getResources().getStringArray(R.array.themes)[1])) {
        builder = new AlertDialog.Builder(new ContextThemeWrapper(getActivity(), R.style.AlertDialogDark));
    } else {
        builder = new AlertDialog.Builder(getActivity());
    }
    builder.setTitle(R.string.pleaseenterpassword);
    builder.setView(view);
    builder.setCancelable(false);
    builder.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {

        }
    });
    builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            View view = ((AlertDialog) dialogInterface).getCurrentFocus();
            if (view != null) {
                InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
            }
            dialogInterface.cancel();
        }
    });

    final AlertDialog alert = builder.create();
    alert.setOnShowListener(new DialogInterface.OnShowListener() {

        @Override
        public void onShow(DialogInterface dialog) {

            Button b = alert.getButton(AlertDialog.BUTTON_POSITIVE);
            b.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View view) {
                    if (input_field.getText().toString().trim().equals(room.getPasswd())) {
                        Intent tabIntent = new Intent("tab");
                        LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(tabIntent);
                        Intent intent = new Intent(getActivity(), ChatActivity.class);
                        intent.putExtra("room_name", room.getRaumname());
                        intent.putExtra("user_id",userID);
                        updateRoomList(position);
                        writeToFile(room.getPasswd(),"mychatapp_raum_" + raumname + ".txt");
                        alert.cancel();
                        startActivity(intent);
                    } else {
                        Toast.makeText(getActivity(), R.string.wrongpassword, Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    });

    alert.show();
}

public Room findRoom(ArrayList<Room> raumliste, String raumname) {
    for (Room room : raumliste) {
        if (room.getRaumname().equals(raumname)) {
            return room;
        }
    }
    return null;
}

public void writeToFile(String text, String datei) {
    Context context = getActivity();
    try {
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(context.openFileOutput(datei, Context.MODE_PRIVATE));
        outputStreamWriter.write(text);
        outputStreamWriter.close();
    }
    catch (IOException e) {
        Log.e("Exception", "File write failed: " + e.toString());
    }
}

public String readFromFile(String datei) {
    Context context = getActivity();
    String erg = "";

    try {
        InputStream inputStream = context.openFileInput(datei);

        if ( inputStream != null ) {
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String receiveString = "";
            StringBuilder stringBuilder = new StringBuilder();

            while ( (receiveString = bufferedReader.readLine()) != null ) {
                stringBuilder.append(receiveString);
            }

            inputStream.close();
            erg = stringBuilder.toString();
        }
    }
    catch (FileNotFoundException e) {
        Log.e("login activity", "File not found: " + e.toString());
    } catch (IOException e) {
        Log.e("login activity", "Can not read file: " + e.toString());
    }

    return erg;
}

private void updateRoomList(int position) {
    listItems.remove(position);
    adapter.notifyDataSetChanged();
}

}

标签: javaandroid

解决方案


执行NullPointerException时发生的时间onDataChange()(您可以通过阅读堆栈跟踪来看到这一点)。更具体地说,readFromFile()需要一个有效Context的文件才能打开。

由于您的应用程序崩溃了,我们知道它getActivity()确实返回了 null。这怎么可能发生?你添加ValueEventListenerin onCreateView()。在这个时间点,Fragment有一个有效的Context(请参阅文档以获取生命周期的解释),所以目前一切都很好。

但是由于您没有删除ValueEventListener,因此即使由于用户滑动到下一页而Fragment暂时未附加到,它也会继续触发。不会被垃圾收集,因为您将其保存在列表中并重复使用它ActivityFragment

如果您实施空检查以避免在它们不存在时访问一般来说,Activity这种方法基本上是Context可以的。View当然,您可以考虑按照本应用程序架构指南中View的建议对数据和层进行更强的分离


推荐阅读