2016-06-14 1 views
0

NOTE:Android RuntimeException: Parcelle: incapable de rassembler la valeur

The code shown below may be a bit hard to read, but i hope it can help. Sorry for that.

Je reçois cette erreur chaque fois que j'appuyez sur la touche HOME et mon application s'en va arrière-plan.

java.lang.RuntimeException: Parcel: unable to marshal value [email protected]

Je suis nouveau à la programmation Android et je voudrais créer une classe qui peut me proposer toutes les fonctions sans les mettre en œuvre chaque fois.

J'ai fait une classe My_Activity:

package elektro_fr.my_android; 

import android.os.Bundle; 
import android.support.v4.app.FragmentTransaction; 
import android.support.v4.view.GestureDetectorCompat; 
import android.support.v7.app.AppCompatActivity; 
import android.view.GestureDetector; 
import android.view.Menu; 
import android.view.MenuItem; 
import android.view.MotionEvent; 
import android.view.WindowManager; 
import java.util.HashMap; 
import java.util.LinkedList; 
import java.util.List; 

public abstract class My_Activity extends AppCompatActivity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener{ 

    private int myLayout; 

    protected Bundle mySettings; 

    private boolean gesturesEnabled=false; 
    private GestureDetectorCompat myGestureDetector; 

    private boolean canStart=false; 

    private boolean menuEnabled=false; 
    private HashMap<String,Action> menuEntries; 

    protected List<My_Fragment> fragmentsList=new LinkedList<>(); 

    protected void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 

     myGestureDetector = new GestureDetectorCompat(this,this); 

     if (savedInstanceState==null){ 

      canStart=true; 
     } 

     init(); 
     setContentView(myLayout); 
    } 

    @Override 
    public void onSaveInstanceState(Bundle outState) { 

     super.onSaveInstanceState(outState); 

     outState.putSerializable("LIST",menuEntries); 

     for (int counter=0;counter<fragmentsList.size();counter++){ 

      getSupportFragmentManager().putFragment(outState,"FRAGMENT_SETTINGS_"+counter,fragmentsList.get(counter)); 
     } 
    } 

    @Override 
    protected void onStart() { 

     super.onStart(); 
     if (canStart) setGraphics(); 
     canStart=false; 
    } 

    protected abstract void init(); 
    protected abstract void setGraphics(); 

    @Override 
    protected void onRestoreInstanceState(Bundle savedInstanceState) { 

     super.onRestoreInstanceState(savedInstanceState); 

     if (savedInstanceState!=null){ 

      menuEntries=(HashMap<String, Action>) savedInstanceState.getSerializable("LIST"); 
      int size=getSupportFragmentManager().getFragments().size(); 

      for (int counter=0;counter<size;counter++){ 

       fragmentsList.add(counter,(My_Fragment)getSupportFragmentManager().getFragment(savedInstanceState,"FRAGMENT_SETTINGS_"+counter)); 
      } 
     } 

     refreshState(); 
    } 

    abstract protected void refreshState(); 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 

     return menuEnabled; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 

     super.onOptionsItemSelected(item); 

     if (menuEntries.get(item.getTitle())!=null){ 

      menuEntries.get(item.getTitle()).doAction(); 
     } 

     return menuEnabled; 
    } 

    @Override 
    public boolean onPrepareOptionsMenu(Menu menu) { 

     super.onPrepareOptionsMenu(menu); 

     if (menuEnabled){ 

      if (menuEntries.size()!=0){ 

       menu.clear(); 
       int counter=0; 

       for (String s: menuEntries.keySet()){ 

        menu.add(Menu.NONE,counter,Menu.NONE,s); 
        counter++; 
       } 
      } 
     } 

     return menuEnabled; 
    } 

    protected void setGestures(boolean enabled){ 

     gesturesEnabled=enabled; 
    } 

    protected void setMenu(boolean enabled){ 

     menuEnabled=enabled; 
     menuEntries=new HashMap<>(); 
    } 

    protected HashMap<String, Action> getMenuEntries(){ 

     return menuEntries; 
    } 

    public My_Fragment addFragment(Class<? extends My_Fragment> fragmentClass, int fragmentContainer, int fragmentID, Bundle fragmentArgs){ 

     My_Fragment fragment = null; 

     try { 

      fragment = fragmentClass.newInstance(); 

     } 
     catch (InstantiationException e){ 

     } 
     catch (IllegalAccessException e){ 

      e.printStackTrace(); 
     } 

     fragment.setArguments(fragmentArgs); 
     getSupportFragmentManager().beginTransaction().add(fragmentContainer, fragment).commit(); 

     fragmentsList.add(fragment); 

     return fragment; 
    } 

    protected My_Fragment getFragment(Class<? extends My_Fragment> fragmentClass){ 

     for (My_Fragment f: fragmentsList){ 

      if (fragmentClass.isInstance(f)){ 

       return f; 
      } 
     } 
     return null; 
    } 

    public void removeFragment(My_Fragment fragment,boolean addToBackStack){ 

     if (fragment.isAdded()){ 

      FragmentTransaction transaction=getSupportFragmentManager().beginTransaction(); 
      if (addToBackStack)transaction.addToBackStack(null); 
      transaction.remove(fragment); 
      transaction.commit(); 
      getSupportFragmentManager().executePendingTransactions(); 
      if (!addToBackStack)fragmentsList.remove(fragment); 
     } 
    } 

    protected void setFullScreen(boolean fullScreen){ 

     WindowManager.LayoutParams attrs = getWindow().getAttributes(); 

     if (fullScreen) { 

      attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN; 
     } 
     else { 

      attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN; 
     } 

     getWindow().setAttributes(attrs); 
    } 

    protected void hideActionBar(boolean hidden){ 

     if (hidden){ 

      getSupportActionBar().hide(); 
     } 
     else getSupportActionBar().show(); 
    } 

    protected void setLayout(int layoutID){ 

     myLayout=layoutID; 
    } 

    public boolean onTouchEvent(MotionEvent event) { 

     if (gesturesEnabled){ 

      this.myGestureDetector.onTouchEvent(event); 
     } 

     return true; 
    } 

    public boolean onSingleTapConfirmed(MotionEvent e) { 

     My_AndroidTools.KeyboardTools.closeInputKeyboard(getCurrentFocus()); 
     return true; 
    } 

    public boolean onDoubleTap(MotionEvent e) { 

     return true; 
    } 

    public boolean onDoubleTapEvent(MotionEvent e) { 

     return true; 
    } 

    public boolean onDown(MotionEvent e) { 

     return true; 
    } 

    public void onShowPress(MotionEvent e) { 

    } 

    public boolean onSingleTapUp(MotionEvent e) { 

     return true; 
    } 

    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 

     return true; 
    } 

    public void onLongPress(MotionEvent e) { 

    } 

    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 

     return false; 
    } 
} 

C'est FragmentsActivity, qui étend et met en œuvre My_Activity:

package elektro_fr.newapplication; 

import android.os.Bundle; 
import android.util.Log; 
import android.widget.RelativeLayout; 

import elektro_fr.my_android.Action; 
import elektro_fr.my_android.My_Activity; 
import elektro_fr.my_android.My_Fragment; 
import elektro_fr.newapplication.R; 

public class FragmentsActivity extends My_Activity implements My_Fragment.fragmentOperations { 

    private MyTopFragment topFragment; 
    private MyBottomFragment bottomFragment; 

    @Override 
    protected void init() { 

     setLayout(R.layout.fragments); 
     setGestures(true); 
     setMenu(true); 
    } 

    @Override 
    protected void setGraphics() { 

     Bundle args=new Bundle(); 
     args.putInt(MyTopFragment.LAYOUT_ID,R.layout.ts_fragment); 
     args.putInt(My_Fragment.CENTER_HORIZONTAL,RelativeLayout.CENTER_HORIZONTAL); 

     topFragment = (MyTopFragment) addFragment(MyTopFragment.class,R.id.MainLayout,R.layout.ts_fragment,args); 

     Bundle args2=new Bundle(); 

     args2.putInt(My_Fragment.LAYOUT_ID,R.layout.bs_fragment); 

     args2.putInt(My_Fragment.LAYOUT_WIDTH,RelativeLayout.LayoutParams.MATCH_PARENT); 
     args2.putInt(My_Fragment.LAYOUT_HEIGHT,RelativeLayout.LayoutParams.WRAP_CONTENT); 

     args2.putInt(My_Fragment.BELOW, R.id.ts); 
     args2.putInt(My_Fragment.CENTER_HORIZONTAL,RelativeLayout.CENTER_HORIZONTAL); 

     bottomFragment = (MyBottomFragment) addFragment(MyBottomFragment.class,R.id.MainLayout,R.layout.bs_fragment,args2); 

     getMenuEntries().put("Menu Item #1", new Action() { 

      @Override 
      public void doAction() { 

       Log.i("Ciccio","you pressed 1"); 
      } 
     }); 

     getMenuEntries().put("Menu Item #2", new Action() { 

      @Override 
      public void doAction() { 

       Log.i("Ciccio","you pressed 2"); 
      } 
     }); 

     getMenuEntries().put("Menu Item #3", new Action() { 
      @Override 
      public void doAction() { 

       Log.i("Ciccio","you pressed 3"); 
      } 
     }); 
    } 

    protected void refreshState(){ 

     topFragment = (MyTopFragment) getFragment(MyTopFragment.class); 
     bottomFragment = (MyBottomFragment) getFragment(MyBottomFragment.class); 
    } 

    @Override 
    public void ClickButtonOperation(Object[] arguments) { 

     switch((Integer)arguments[0]){ 

      case 0: 

       bottomFragment.setText((String)arguments[1],(String)arguments[2]); 
      break; 
     } 
    } 
} 

C'est classe My_Fragment:

package elektro_fr.my_android; 

import android.content.Context; 
import android.os.Bundle; 
import android.support.annotation.Nullable; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentManager; 
import android.text.Layout; 
import android.util.Log; 
import android.util.TypedValue; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.RelativeLayout; 

public abstract class My_Fragment extends Fragment { 

    public final static String LAYOUT_ID="layout_id"; 
    public final static String LAYOUT_WIDTH="layout_width"; 
    public final static String LAYOUT_HEIGHT="layout_height"; 

    public final static String BELOW="layout_below"; 
    public final static String ABOVE="layout_above"; 

    public final static String ALIGN_PARENT_BOTTOM="align_parent_bottom"; 
    public final static String CENTER_HORIZONTAL="center_horizontal"; 

    private String[] params={ 

      LAYOUT_ID,LAYOUT_WIDTH, LAYOUT_HEIGHT, ALIGN_PARENT_BOTTOM, CENTER_HORIZONTAL, BELOW, ABOVE 
    }; 

    protected int fragmentLayout; 

    protected fragmentOperations myActivity; 
    protected Bundle mySettings; 

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

     super.onCreate(savedInstanceState); 

     if (savedInstanceState!=null){ 

      mySettings=new Bundle(); 
      mySettings.putAll(savedInstanceState); 
     } 
     else mySettings=getArguments(); 
     fragmentLayout=mySettings.getInt(LAYOUT_ID); 
    } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 

     super.onActivityCreated(savedInstanceState); 

     if (savedInstanceState != null) { 

      mySettings.putAll(savedInstanceState); 
      refreshState(); 
     } 
    } 

    @Override 
    public void onSaveInstanceState(Bundle outState) { 

     super.onSaveInstanceState(outState); 

     setState(); 
     outState.putAll(mySettings); 
    } 

    public interface fragmentOperations{ 

     void ClickButtonOperation(Object[] arguments); 
    } 

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

     View view=inflater.inflate(fragmentLayout,container,false); 

     int widthSettings=mySettings.getInt(params[1]); 
     int heightSettings=mySettings.getInt(params[2]); 

     view.setLayoutParams(new RelativeLayout.LayoutParams((widthSettings==0?RelativeLayout.LayoutParams.WRAP_CONTENT:widthSettings),(heightSettings==0?RelativeLayout.LayoutParams.WRAP_CONTENT:heightSettings))); 

     RelativeLayout.LayoutParams layoutConfig= (RelativeLayout.LayoutParams) view.getLayoutParams(); 

     for (int counter=3;counter<params.length;counter++){ 

      int settings=mySettings.getInt(params[counter]); 

      if (settings!=0){ 

       if (counter==5){ 

        layoutConfig.addRule(RelativeLayout.BELOW,settings); 
       } 
       else if (counter==6){ 

        layoutConfig.addRule(RelativeLayout.ABOVE,settings); 
       } 
       else{ 

        layoutConfig.addRule(settings); 
       } 
      } 
     } 

     init(view); 

     return view; 
    } 

    protected abstract void init(View v); 
    protected abstract void setState(); 
    protected abstract void refreshState(); 

    @Override 
    public void onAttach(Context context) { 

     super.onAttach(context); 
     myActivity=(fragmentOperations)getActivity(); 
    } 
} 

EDIT:

Enfin, Action (interface), que j'edited afin de mettre en œuvre Serializable:

package elektro_fr.my_android; 

import java.io.Serializable; 

public interface Action extends Serializable{ 

    public void doAction(); 
} 

C'est l'erreur:

Process: elektro_fr.newapplication, PID: 24970 java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = elektro_fr.newapplication.FragmentsActivity$3)

Causée par:

Caused by: java.io.NotSerializableException: elektro_fr.newapplication.FragmentsActivity

pourquoi je implémente sérialisable dans cette classe?

+1

StackOverflow ne fonctionne pas comme un forum classique, il est un Q & A du site.S'il vous plaît modifier la question et supprimer le _ (résolu) _ du titre et aussi la solution. Ajoutez la solution en utilisant le bouton "Répondre à votre question" ci-dessous. Et pour l'avenir gardez à l'esprit de publier seulement la quantité minimale de code nécessaire pour déclencher le problème. – perissf

+0

@perissf Merci de l'avoir dit. J'ai édité mon post. Malheureusement, je ne savais pas où le problème pourrait être, alors je pensais que donner le code entier aurait été une bonne idée. –

Répondre

0

Vous essayez d'enregistrer menuEntries dans OnSaveInstanceState, mais le type est HashMap et ce type n'est pas sérialisable. Seules les primitives peuvent être sauvegardées ou personnalisées lorsque vous implémentez vous-même la sérialisation.

+0

De ce que je sais, la classe HashMap implémente sérialisable .. –

+0

Et est "Action" sérialisable? – Johann67

+0

Ajouté "implements Serializable" à "Action". L'erreur a changé: consultez la publication pour les modifications. –

0

SOLUTION:

Après idée Johann67:

Ok I understand your code. You can't do that. When you serialize an object, only the fields are serialized and save. But here you try to serialize the doAction() method... You need to change the Action object. Maybe you can just save the item position on your HashMap or create an object and store your information in the fields.

Je modifié mon code.

Tout d'abord, j'ai changé mon objet menuEntries en Liste de Chaînes.

En second lieu, je créé une nouvelle méthode:

protected void dispatchItemAction(int itemID); 

qui peut être redéfinie afin de basculer entre les actions à faire, sur la base du itemID.

Et cette méthode i modifié:

@Override 
    public boolean onOptionsItemSelected(MenuItem item) { 

     super.onOptionsItemSelected(item); 

     dispatchItemAction(item.getItemId()); 

     return menuEnabled; 
    } 

    protected void dispatchItemAction(int itemID){ 


    } 

maintenant, d'ajouter des éléments de menu:

protected void addMenuItems(){ 

    getMenuEntries().add("Menu Item #1"); 
    getMenuEntries().add("Menu Item #2"); 
    getMenuEntries().add("Menu Item #3"); 
} 

@Override 
protected void dispatchItemAction(int itemID) { 

    switch(itemID){ 

     case 0: 

      Log.i("Log","Pressed #1."); 
     break; 

     case 1: 

      Log.i("Log","Pressed #2."); 
     break; 

     case 2: 

      Log.i("Log","Pressed #3."); 
     break; 
    } 
}