2016-03-23 14 views
0

Ich habe eine FragmentActivity, die zwei Fragments hostet, die über eine MenuItem Schaltfläche dynamisch ausgeschalten werden. Wenn auf die Aktivität zum ersten Mal zugegriffen wird, wird das Fragment 1 angezeigt. Dann kann der Benutzer den Knopf drücken, um Fragment 2 (PresetsFragment) anzuzeigen. Fragment 2 ist ein ListView, dem der Benutzer Elemente hinzufügen/löschen kann. Dies funktioniert alles gut, bis der Bildschirm gedreht wird. Nach der Rotation wird die Listenansicht von Fragment 2 korrekt angezeigt, aber wenn der Benutzer versucht, ein Element hinzuzufügen oder zu löschen, wird eine NPE geworfen. Ich denke, obwohl die Listview im neuen Fragment korrekt angezeigt wird, verwendet sie die Daten des alten Fragments 2, die nach der Änderung der Ausrichtung irgendwie nicht für den Zugriff gültig sind. Ich werde versuchen, den entsprechenden Code zu posten.

Aktivität:NPE in Fragment nach Orientierungsänderung

public class LiveVideoActivity extends FragmentActivity implements 
    AddPresetDialogFragment.AddPresetDialogListener, 
    DeletePresetDialogFragment.DeletePresetDialogListener{ 

private PresetsFragment currentPresetsFragment; 

public LiveVideoActivity() { 
    Log.d(TAG, "CONSTRUCTOR called."); 
    m_backPressed = false; 
    m_instanceStateSaved = false; 

    m_viewCtrl = LiveVideoViewControlSingleton.getInstance(); 
    m_viewCtrl.setParentActivity(this); 

    m_layoutMgr = LayoutManagerSingleton.getInstance(); 

    m_devCfgCtrl = DeviceCfgControllerSingleton.getInstance(); 
    m_devCfgCtrl.setParentActivity(this); 

    m_recMgr = RecordingManagerSingleton.getInstance(); 
    m_recMgr.setParentActivity(this); 
    m_recMgr.addViewCtrlCallback(m_viewCtrl); 

    m_localStorageManager = new LocalStorageManager(); 
} 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

     if (orientation == Configuration.ORIENTATION_PORTRAIT) { 
      setContentView(R.layout.live_video_activity); 

      if(savedInstanceState == null){ 
       final Fragment deviceControls = new DeviceControlsFragment(); 
       FragmentTransaction transaction = getFragmentManager().beginTransaction(); 
       transaction.replace(R.id.framelayout_live_video_fragment_container, deviceControls);    
       transaction.commit(); 
      } 

     } 
    else { // Landscape orientation 

      setContentView(R.layout.live_video_activity_land); 

      if(savedInstanceState == null) { 
       final Fragment deviceControls = new DeviceControlsFragment(); 
       FragmentTransaction transaction = getFragmentManager().beginTransaction(); 
       transaction.replace(R.id.framelayout_live_video_fragment_container, deviceControls); 
       currentFrameLayoutSelection = "Device"; 
       transaction.commit(); 
      } 
     } 
    } 

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 

    final Bundle bundle = new Bundle(); 
    final Intent serverSetupScreen = new Intent(getApplicationContext(), ConfigurationViewPagerActivity.class); 
    final Intent RecordingsScreen = new Intent(getApplicationContext(), RecordingsViewPagerActivity.class); 
    final Fragment deviceControls = new DeviceControlsFragment(); 
    final Fragment addPresetDialog = new AddPresetDialogFragment(); 
    final FragmentTransaction transaction = getFragmentManager().beginTransaction(); 

    switch (item.getItemId()) { 

     case R.id.actionItem_takeSnapshot: 
      Toast toast = Toast.makeText(getApplicationContext(), "take snapshot", Toast.LENGTH_SHORT); 
      toast.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 0); 
      toast.show(); 
      return true; 


     case R.id.dropdown_arrow_for_overlay_live_video: 
      if (layout.getVisibility() == View.VISIBLE) { 
       layout.setVisibility(View.GONE); 
       overlayArrowLiveVideo.setIcon(R.drawable.ic_arrow_drop_up_white_36dp); 
       isOverlayVisible = false; 
       Log.e("for LV","GONE"); 
      } else { 
       layout.setVisibility(View.VISIBLE); 
       overlayArrowLiveVideo.setIcon(R.drawable.ic_arrow_drop_down_white_36dp); 
       isOverlayVisible = true; 
       Log.e("for LV", "VISIBLE"); 
      } 
      return true; 


     case R.id.presets_overflow_live_video: 
      if (currentPresetsFragment == null){ 
       currentPresetsFragment = new PresetsFragment(); 
      } 

      currentFrameLayoutSelection = "Presets"; 
      isLiveVideo = false; //set boolean to read in onPrepareOptionsMenu() to set correct menu resource 

      invalidateOptionsMenu(); 

      ab.setTitle("Presets"); 
      actionbarTitle = "Presets"; 

      if (orientation == Configuration.ORIENTATION_PORTRAIT) { 
       recLocalBtn.setVisibility(View.INVISIBLE); 
       recRemoteBtn.setVisibility(View.INVISIBLE); 
      } 

      transaction.replace(R.id.framelayout_live_video_fragment_container, currentPresetsFragment); 
      transaction.addToBackStack("Presets").commit(); 
      return true; 


     case R.id.done_with_presets_action: 
      ab.setTitle("Live Video"); 
      actionbarTitle = "Live Video"; 

      currentFrameLayoutSelection = "Live Video"; 
      isLiveVideo = true; //set boolean to read in onPrepareOptionsMenu() to set correct menu resource 
      if (orientation == Configuration.ORIENTATION_PORTRAIT) { 
       recLocalBtn.setVisibility(View.VISIBLE); 
       recRemoteBtn.setVisibility(View.VISIBLE); 
      } 
      transaction.replace(R.id.framelayout_live_video_fragment_container, deviceControls); 
      transaction.addToBackStack("DeviceControls").commit(); 


      invalidateOptionsMenu(); 
      return true; 


     case R.id.add_preset_action: 
      Toast toast1 = Toast.makeText(getApplicationContext(), "Add Preset", Toast.LENGTH_SHORT); 
      toast1.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 0); 
      toast1.show(); 

      transaction.add(addPresetDialog, "Add Preset"); 
      transaction.addToBackStack(null).commit(); 

      return true; 


     case R.id.device_setup_overflow_live_video: 
      bundle.putInt("Starting Position", 0); 
      serverSetupScreen.putExtras(bundle); 
      serverSetupScreen.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
      getApplicationContext().startActivity(serverSetupScreen); 
      return true; 

     case R.id.server_config_overflow_live_video: 
      bundle.putInt("Starting Position", 1); 
      serverSetupScreen.putExtras(bundle); 
      serverSetupScreen.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
      getApplicationContext().startActivity(serverSetupScreen); 
      return true; 

     case R.id.scheduler_overflow_live_video: 
      bundle.putInt("Starting Position", 2); 
      serverSetupScreen.putExtras(bundle); 
      serverSetupScreen.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
      getApplicationContext().startActivity(serverSetupScreen); 
      return true; 

     case R.id.videos_overflow_live_video: 
      bundle.putInt("Starting Position", 2); 
      bundle.putInt("Calling Screen", 1); 
      RecordingsScreen.putExtras(bundle); 
      RecordingsScreen.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
      getApplicationContext().startActivity(RecordingsScreen); 
      return true; 


     case R.id.snapshots_overflow_live_video: 
      bundle.putInt("Starting Position", 3); 
      bundle.putInt("Calling Screen", 1); 
      RecordingsScreen.putExtras(bundle); 
      RecordingsScreen.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
      getApplicationContext().startActivity(RecordingsScreen); 
      return true; 

     case R.id.status_overflow_live_video: 
      ServerStatusDialogFragment statusDialog = new ServerStatusDialogFragment(); 
      FragmentManager fm = getFragmentManager(); 
      statusDialog.show(fm, "statusDialog"); 
      return true; 

     default: 
      return true; 
    } 
} 

@Override 
public void onSaveInstanceState(Bundle outState) { 
    super.onSaveInstanceState(outState); 
    outState.putBoolean("isLiveVideo", isLiveVideo); 
    outState.putString("currentFrameLayoutSelection", currentFrameLayoutSelection); 
    outState.putString("actionbarTitle", actionbarTitle); 
    m_instanceStateSaved = true; 
} 


@Override 
public void onAddPresetDialogPositiveClick(String preset_name, String preset_description) { 
    currentPresetsFragment.onAddPresetDialogPositiveClick(preset_name, preset_description); 
} 

@Override 
public void onDeletePresetDialogPositiveClick(int position) { 
    currentPresetsFragment.onDeletePresetDialogPositiveClick(position); 
} 
} 



Fragment # 2:

public class PresetsFragment extends Fragment implements 
    AddPresetDialogFragment.AddPresetDialogListener, 
    DeletePresetDialogFragment.DeletePresetDialogListener{ 

private List<PresetItem> items = new ArrayList<>(); 
ListView presetListview; 
private PresetsListviewAdapter listAdapter; 

private Context mContext; 

@Override 
public void onActivityCreated(Bundle savedInstanceState) { 
    super.onActivityCreated(savedInstanceState); 
} 

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    mContext = getActivity(); 

    View rootView = inflater.inflate(R.layout.presets_fragment, container, false); 

    String fileName = "Preset List"; 

    String line = null; 

    try { 
     InputStream inputStream = getActivity().openFileInput(fileName); 

     if (inputStream != null) { 
      InputStreamReader inputStreamReader = new InputStreamReader(inputStream); 
      BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 

      while ((line = bufferedReader.readLine()) != null) { 
       try { 
        PresetItem presetItem = new PresetItem(line); 
        items.add(presetItem); 
       } catch (JSONException je) { 
        je.printStackTrace(); 
       } 
      } 

      inputStream.close(); 

     } 

    } catch (FileNotFoundException e) { 
     Log.e("preset frag", "File not found: " + e.toString()); 
    } catch (IOException e) { 
     Log.e("preset frag", "Can not read file: " + e.toString()); 
    } 

    File f = new File(getActivity().getFilesDir().getPath()); 
    File file[] = f.listFiles(); 
    Log.d("Files", "Size: " + file.length); 
    for (int i = 0; i < file.length; i++) { 
     Log.d("Files", "FileName:" + file[i].getName()); 
    } 

    presetListview = (ListView) rootView.findViewById(R.id.listview_presets); 
    listAdapter = new PresetsListviewAdapter(getActivity(), R.layout.preset_row_layout, items); 
    presetListview.setAdapter(listAdapter); 

    return rootView; 
} 

@Override 
public void onPause(){ 
    super.onPause(); 
    listAdapter.clear(); 
} 

@Override 
public void onSaveInstanceState(Bundle outState) { 
    super.onSaveInstanceState(outState); 
} 


@Override 
public void onAddPresetDialogPositiveClick(String preset_name, String preset_description) { 
    PresetItem newPresetItem = new PresetItem(preset_name, preset_description); 
    listAdapter.add(newPresetItem); 

    try { 
     FileUtil.write("Preset List", newPresetItem.toJson(), getActivity()); 
    } catch (JSONException je) { 
     je.printStackTrace(); 
    } 
} 

@Override 
public void onDeletePresetDialogPositiveClick(int position) { 
    listAdapter = new PresetsListviewAdapter(mContext, R.layout.preset_row_layout, items); 

    PresetItem deletePresetItem = listAdapter.getItem(position); 

    String dir = getActivity().getFilesDir().getAbsolutePath(); 

    String originalFileName = "Preset List"; // The name of the original file to open. 
    String tempFileName = "Temp Preset List"; // Name of the temp file to hold original file contents 

    File originalFile = new File(dir, originalFileName); 
    if (!originalFile.canRead()) { 
     Log.e("Original File", "cannot be read."); 
    } 

    File tempFile = new File(dir, tempFileName); 
    try { 
     if (!tempFile.exists()) { 
      tempFile.createNewFile(); 
     } 
    } catch (IOException ie) { 
     ie.printStackTrace(); 
    } 
    if (!tempFile.canRead()) { 
     Log.e("Temp File", "cannot be read."); 
    } 

    String line = null; // This will reference one line at a time 

    try { 
     InputStream inputStream = getActivity().openFileInput(originalFileName); 

     if (inputStream != null) { 
      InputStreamReader inputStreamReader = new InputStreamReader(inputStream); 
      BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 

      while ((line = bufferedReader.readLine()) != null) { 
       Log.e("In onDelete", line); 
       String strDeletePresetItem = deletePresetItem.toJson(); 
       Log.e("strDeletePresetItem", strDeletePresetItem); 
       Log.e("line", line); 

       if (!line.trim().equals(strDeletePresetItem)) { 
        Log.e("In file write", ""); 
        FileUtil.write(tempFileName, line, getActivity()); 
       } 
      } 

      inputStream.close(); 


      Boolean TF = getActivity().deleteFile(originalFileName); 
      Log.e("Original File Deleted", TF.toString()); 

      Boolean tempFileRename = tempFile.renameTo(originalFile); 
      Log.e("tempFile renamed", tempFileRename.toString()); 

      File f = new File(getActivity().getFilesDir().getPath()); 

      if (!f.canRead()) { 
       System.out.println("File cannot be read."); 
      } 

      File file[] = f.listFiles(); 
      Log.d("Files", "Size: " + file.length); 
      for (int i = 0; i < file.length; i++) { 
       Log.d("Files", "FileName:" + file[i].getName()); 
      } 

     } else { 
      System.out.println("inputStream is null"); 
     } 

    } catch (FileNotFoundException e) { 
     Log.e("In SF onDelete", "File not found: " + e.toString()); 
    } catch (IOException e) { 
     Log.e("In SF onDelete", "Can not read file: " + e.toString()); 
    } catch (JSONException je) { 
     je.printStackTrace(); 
    } 

    listAdapter.remove(deletePresetItem); 
} 
} 



löschen Dialog:

public class DeletePresetDialogFragment extends DialogFragment { 

private DeletePresetDialogListener mListener; 

// Override the Fragment.onAttach() method to instantiate the DeletePresetDialogListener 
@Override 
public void onAttach(Activity activity) { 
    super.onAttach(activity); 
    // Verify that the host activity implements the callback interface 
    try { 
     // Instantiate the DeletePresetDialogListener so we can send events to the host 
     mListener = (DeletePresetDialogListener) activity; 

    } catch (ClassCastException e) { 
     // The activity doesn't implement the interface, throw exception 
     throw new ClassCastException(activity.toString() 
       + " must implement DeletePresetDialogListener"); 
    } 
} 

@Override 
public Dialog onCreateDialog(final Bundle savedInstanceState) { 
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 

    builder.setTitle("Delete Preset"); 

    LayoutInflater inflater = getActivity().getLayoutInflater(); 
    final View dialogView = inflater.inflate(R.layout.delete_preset_dialog, null); 

    builder.setView(dialogView) 
      .setPositiveButton("Delete", new DialogInterface.OnClickListener() { 
       @Override 
       public void onClick(DialogInterface dialog, int id) { 

        Bundle b = getArguments(); 

        //***** ERROR HERE BUT I THINK IT'S JUST COMING THROUGH THE INTERFACE *****// 
        mListener.onDeletePresetDialogPositiveClick(b.getInt("position")); 
       } 


      }) 
      .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { 
       public void onClick(DialogInterface dialog, int id) { 
        DeletePresetDialogFragment.this.getDialog().cancel(); 
       } 
      }); 
    return builder.create(); 


} 

public interface DeletePresetDialogListener { 
    void onDeletePresetDialogPositiveClick(int position); 
} 
} 

Der Fehler in der IDE ist am mListener in der Mitte die Delete Dialog, aber ich bin mir ziemlich sicher, dass das ist e Die Methode onDeletePresetDialogPositiveClick wird für ein Nullfragment aufgerufen. Was ich nicht verstehe, ist, warum die UI (listview) im Fragment korrekt gerendert wird, aber beim Versuch, auf ihre Daten/Methoden zuzugreifen, ist sie vermutlich null. Gibt es etwas, was ich mache, das verhindert, dass die Aktivität wiederverwendet oder ein neues Fragment erstellt wird, dass ich dann auf eine gültige listview und Delete/Add-Methoden zugreifen kann?

+0

Ich habe Ihren Code nicht vollständig verstanden - vielleicht könnten Sie es einfacher machen, indem Sie ein minimales Stück Code erstellen, das den Fehler anzeigt und den Rest der Details weglässt. Aber ich machte zwei Beobachtungen: 1. Sie führen einen Teil Ihrer Initialisierung Ihrer Aktivität nicht in onCreate, sondern einen Konstruktor. Obwohl dies nicht ausdrücklich verboten ist, ist dies zumindest ungewöhnlich. Irgendwelche besonderen Gründe dafür? 2. onSaveInstanceState speichert currentPresetsFragment nicht. Nach dem Drehen des Geräts ist dies also null, bis es möglicherweise in onOptionsItemSelected gesetzt wird. – TAM

+0

@TAM Der Konstruktor wurde von jemandem mit viel C Hintergrund geschrieben, der das erklären könnte.Jetzt haben Sie mich neugierig auf onSaveInstanceState. 1) Ich hatte den Eindruck, dass Android die Lebenszyklen von Fragmenten verwalten und speichern/wiederherstellen soll. Tatsächlich mache ich fast genau dasselbe wie das, was Sie hier in einem anderen Teil meiner App sehen, und ich muss die Fragmente nicht selbst verwalten. 2) ABER, ich bin bereit, sie selbst zu verwalten. Wie speichere ich ein Fragment in onSavedInstanceState, ich habe das gesucht, konnte aber nichts finden. – shoota

Antwort

0

Ich habe es mit @youzking 's Hilfe herausgefunden. Natürlich ist currentPresetsFragment null nach der Änderung der Ausrichtung, da es nur beim Klicken auf die Menüelementschaltfläche initialisiert wird und die Aktivität bei einer Orientierungsänderung neu erstellt wird. Also habe ich in diesem onItemClick ein Tag für das Fragment hinzugefügt und dann überprüft, ob currentPresetsFragment in onDeletePresetDialogPositiveClick in der Aktivität null ist. Wenn es sich dann um einen Suchvorgang handelt, wird der aktuelle ACTIVE-Parameter mithilfe des Tags voreingestellt. Ich bin diesem Beitrag gefolgt. get currently displayed fragment

0

i in Ihrem LiveVideoActivity ‚s onCreate Methode eine fehlende schließende Klammer bemerkt, haben Sie den if (serverItem != null) { Block geschlossen, aber nicht die onCreate Methode. Wie konntest du die App kompilieren?

ein anderer denken (ich ging nicht tief, ich will Ihnen nur helfen, sich zu erinnern) ist die onDeletePresetDialogPositiveClick Methode. Sowohl das PresetsFragment (Fragment2) als auch das LiveVideoActivity implementieren das DeletePresetDialogFragment.DeletePresetDialogListener und natürlich das Verfahren onDeletePresetDialogPositiveClick. Ich denke, Sie erwarten, dass die Haupt (LiveVideoActivity) ausgeführt wird, während die PresetsFragment ausgeführt wird und Sie ein Null-Objekt darin manipulieren. (ich bin mir Ihrer Erwartung nicht sicher, weil ich nicht so tief in Ihren Code gegangen bin, nehme ich nur an).

+0

Ja, all das ist richtig, nehmen Sie dies als mehr von Pseudo-Code. Ich habe versucht zu strippen, was nicht notwendig war, also war es nicht so ausführlich. – shoota

+0

ok, dachte ich mir. Ich bemerkte Ihren Test: 'if (serverItem! = Null)', Sie setzen keine contentView im else-Block, bedeutet dies, wenn das 'serverItem' null ist, so dass nichts angezeigt wird? –

+0

Ich habe dieses Zeug gerade überarbeitet, klar, es ist verwirrend und nicht relevant für die Frage. – shoota

Verwandte Themen