2016-04-07 2 views
1

Ich habe eine Aktivität A mit einem Fragment frag2. Innerhalb des Fragments habe ich einen RecyclerView und einen Adapter, um eine Liste von benutzerdefinierten Klassenobjekten anzuzeigen. Das Hinzufügen von Objekten zu dem Adapter wird programmgesteuert behandelt. Ich habe einen Button in TwoFragment, der einen FragmentDialog öffnet. Ich möchte ein Objekt zu meinem Adapter hinzufügen, indem ich dieses Dialogfeld bestätige, aber es scheint, dass der Adapter null ist, wenn er vom FragmentDialog aufgerufen wird.Wie aktualisiert man das benutzerdefinierte RecyclerView von FragmentDialog?

Der gleiche Adapter ist nicht null, und funktioniert, wenn ich es aus dem Fragment OnClick aufrufen.

Darüber hinaus ist der Adapter nur nach der Drehung des Bildschirms Null, es funktioniert gut vor dem Drehen.

zwischen den beiden Fragmente zu kommunizieren I

Aktivität A

public void respond(String type) { 
     frag2.addSupport(type); 
    } 

frag2

public RecyclerView rv; 
public ArrayList<support> supports; 
public myAdapter adapter; 

@Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     supports = new ArrayList<>(); 
     adapter = new myAdapter(supports); 
    } 

@Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
          Bundle savedInstanceState) { 
     View layout = inflater.inflate(R.layout.fragment_two, container, false); 
     layout.setId(R.id.frag2); 


     if (savedInstanceState!=null) 
     { 
      supports = savedInstanceState.getParcelableArrayList("supports"); 
     } 

     rv = (RecyclerView) layout.findViewById(R.id.rv); 
     adapter = new myAdapter(supports); 
     rv.setAdapter(myAdapter); 
     rv.setLayoutManager(new LinearLayoutManager(getActivity())); 
     rv.setItemAnimator(new DefaultItemAnimator()); 

@Override 
    public void onClick(View v) { 
     int id = v.getId(); 
     switch (id){ 
      case R.id.button1: 
       addSupport(type); // THIS WORKS ALWAYS, even after screen rotate 
       break; 

      case R.id.button2: 
       showDialog(); 
       break; 
     } 

    } 

public void showDialog(){ 

     FragmentManager manager = getFragmentManager(); 
     myDialog dialog = new myDialog(); 
     dialog.show(manager, "dialog"); 
    } 

public void addSupport(String type){ 

    adapter.addItem(new support(type)); // this line gives null pointer on adapter, but only if called after screen rotate and only if called from the dialog 
      } 

Dialog

einen Kommunikator Klasse in Aktivität A. implementieren
communicator comm; 

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


     View view = inflater.inflate(R.layout.dialog, null); 
     comm = (myCommunicator) getActivity(); 
     create = (Button) view.findViewById(R.id.button_ok); 
     create.setOnClickListener(this); 

     return view; 
    } 



@Override 
    public void onClick(View v) { 

     if(v.getId()==R.id.button_ok) 
     { 
      // some controls to set type 
      comm.respond(type) 
      dismiss(); 
     } 
     else { 

      dismiss(); 
     } 

myAdapter

public class myAdapter extends RecyclerView.Adapter<myAdapter.VH> { 
    private LayoutInflater inflater; 
    private ArrayList<support> data = new ArrayList<>(); 

// settings for viewholder 

public myAdapter (ArrayList<support> data) 
    { 
     this.data=data; 
    } 

    public void addItem(support dataObj) { 

     data.add(dataObj); 
     notifyItemInserted(data.size()); 
    } 

} 

logcat

FATAL EXCEPTION: main 
java.lang.NullPointerException: Attempt to invoke virtual method 'myAdapter.addItem(myObject)' on a null object reference 

Ich hoffe, es gibt keine Fehler, verkürzte ich den Code für ein besseres Verständnis. Denken Sie daran, dass alles funktioniert, wenn ich den Bildschirm nie drehe.

Ich bin ein Anfänger mit Android und ich bin seit einigen Tagen mit diesem fest. Bitte, helfen Sie.

Antwort

0

das Problem zu verstehen, ist es, wie Sie sagen:

.. everything works if I never rotate the screen

Also erstens zu verstehen, was bei einer Drehung geschieht, dann ist dies ein Zitat aus dem Android Developer website:

Caution: Your activity will be destroyed and recreated each time the user rotates the screen. When the screen changes orientation, the system destroys and recreates the foreground activity because the screen configuration has changed and your activity might need to load alternative resources (such as the layout).

Ok, jetzt zu verstehen, der Fehler:

FATAL EXCEPTION: main 
java.lang.NullPointerException: Attempt to invoke virtual method 'myAdapter.addItem(myObject)' on a null object reference

Im Wesentlichen in Ihrem dialog Klasse, haben Sie eine starke Abhängigkeit, indem er erklärt erstellt:

comm = (myCommunicator) getActivity();

weil comm Referenzen Objekte, die auf Rotation zerstört gewesen wäre, daher die NullPointerException.

Um Laufzeitänderungen, wie z. B. Orientierungsänderungen, besser zu verstehen, würde ich empfehlen, Handling Runtime Changes durchzugehen.

aktualisieren

Thank you for your answer, what would you recommend instead of comm = (myCommunicator) getActivity(); ?

Die Lösung in 3 Teilen kommt:

  1. Sicherstellen, dass die onCreate von Activity A hat die folgenden:


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

     // find the retained fragment on activity restarts 
     FragmentManager fm = getFragmentManager(); 
     frag2 = (Frag2) fm.findFragmentByTag(“frag2”); 

     // create frag2 only for the first time 
     if (frag2 == null) { 
      // add the fragment 
      frag2 = new Frag2(); 
      fm.beginTransaction().add(frag2 , “frag2”).commit(); 
     } 
     ...... 

    } 

  1. Hinzufügen setRetainInstance(true) zu onCreate von frag2.

  2. Entfernen Sie das implizite Referenzieren, d. H. comm = (myCommunicator) getActivity();, und implementieren Sie etwas loser gekoppelt für dialog.

Dialog



    public interface Communicator { 

     void respond(String type); 
    } 

    Communicator comm; 

    .... 

    public void addCommunicator(Communicator communicator) { 

     comm = communicator; 
    } 

    public void removeCommunicator() { 

     comm = null; 
    } 

    @Override 
    public void onClick(View v) { 
     if((v.getId()==R.id.button_ok) && (comm!=null)) 
     { 
      // some controls to set type 
      comm.respond(type); 
     } 
     // Regardless of what button is pressed, the dialog will dismiss 
     dismiss(); 
    } 

Auf diese Weise können Sie die folgenden in frag2 (oder jede andere Klasse für diese Angelegenheit) tun:

frag2

<pre><code> 
public class Frag2 extends Fragment implements dialog.Communicator { 

    ........ 

    public void showDialog() { 

     FragmentManager manager = getFragmentManager(); 
     myDialog dialog = new myDialog(); 
     dialog.addCommunicator(this); 
     dialog.show(manager, "dialog"); 
    } 

    @Override 
    public void respond(String type){  

     adapter.addItem(new support(type)); 
    } 

} 

+0

Vielen Dank für Ihre Antwort, was würden Sie anstelle von comm = (myCommunicator) empfehlen getActivity(); ? – Helike

Verwandte Themen