具有相同类的Parcelable嵌套writeTypedList

时间:2022-11-25 08:23:52

To give an idea of what I am doing. I have a Main activity that allows you to add names to a recyclerView then start a round that sends to an Arraylist of people through an Intent to CurrentMatchActivity. after a while of user input it launches another instance of CurrentMatchActivity by passing an Arraylist of people to a new CurrentMatchActivity.

想知道我在做什么。我有一个Main活动,允许您将名称添加到recyclerView然后开始一个回合,通过Intent to CurrentMatchActivity发送给人们的Arraylist。经过一段时间的用户输入后,它会通过将人员的Arraylist传递给新的CurrentMatchActivity来启动另一个CurrentMatchActivity实例。

Here is the Person class

这是Person类

public class Person implements Parcelable {
    private String name;
    private int wins;
    private long totalWins;
    private boolean stillPlaying;
    private ArrayList<Person> previousOpponents;

    Person(String name)
    {
        this.name = name;
        wins = 0;
        totalWins = 0;
        stillPlaying = true;
        previousOpponents = new ArrayList<>();
    }

    public void setStillPlaying(boolean playing)
    {
        stillPlaying = playing;
    }

    public void addOpponent(Person person) {
        previousOpponents.add(person);
    }

    public boolean hasFought(Person person) {
        return previousOpponents.contains(person);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    private Person(Parcel in)
    {
        name = in.readString();
        wins = in.readInt();
        totalWins = in.readLong();
        stillPlaying = (boolean) in.readValue(null);
        previousOpponents = new ArrayList<>();
        in.readTypedList(previousOpponents, null);
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(wins);
        dest.writeLong(totalWins);
        dest.writeValue(stillPlaying);
        dest.writeTypedList(previousOpponents);
    }

    public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
        public Person createFromParcel(Parcel in) {
            return new Person(in);
        }

        public Person[] newArray(int size) {
            return new Person[size];
        }
    };
}

Here is the CurrentMatchActivity

这是CurrentMatchActivity

package omarzious.myapplication;

public class CurrentMatchActivity extends Activity {

    private ArrayList<Person> people;
    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;
    private int round;

    private RetainedFragment dataFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_current_match);

        FragmentManager fm = getFragmentManager();
        dataFragment = (RetainedFragment) fm.findFragmentByTag("currentMatchData");

        if (dataFragment == null){
            dataFragment = new RetainedFragment();
            fm.beginTransaction().add(dataFragment, "currentMatchData").commit();
            round = getIntent().getIntExtra("round",1);
            people = getIntent().getParcelableArrayListExtra("people");
            prepareMatch();
        }
        else
        {
            people = dataFragment.getData();
        }

        this.setTitle(getString(R.string.round)+" "+round);
        mRecyclerView = (RecyclerView) findViewById(R.id.current_match_recycler_view);

        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        mAdapter = new CurrentMatchAdapter(people, getApplicationContext());
        mRecyclerView.setAdapter(mAdapter);

        // Swipe Portion

        SwipeableRecyclerViewTouchListener swipeTouchListener = new SwipeableRecyclerViewTouchListener(mRecyclerView,
                new SwipeableRecyclerViewTouchListener.SwipeListener() {
                    private int personIndex;
                    @Override
                    public boolean canSwipe(int position)
                    {

                        if (position == (int)people.size()/2)
                        {
                            return false;
                        }
                        return people.get(position*2).isStillPlaying();
                    }

                    @Override
                    public void onDismissedBySwipeRight(RecyclerView recyclerView, int[] reverseSortedPositions) {
                        for (int position : reverseSortedPositions)
                        {
                            personIndex = position*2;
                            //personBeat(personIndex, personIndex+1);

                            people.get(personIndex).won();
                            mAdapter.notifyItemChanged(position);

                            // if player on right won

                            if (people.get(personIndex).isWinner())
                            {
                                people.get(personIndex).setStillPlaying(false);
                                people.get(personIndex+1).setStillPlaying(false);

                                if (checkForRoundEnd())
                                {
                                    startNewRound();
                                }
                            }
                        }
                        mAdapter.notifyDataSetChanged();
                    }

                    public void onDismissedBySwipeLeft(RecyclerView recyclerView, int[] reverseSortedPositions) {
                        for (int position : reverseSortedPositions) {
                            personIndex = position*2+1;

                            people.get(personIndex).won();
                            mAdapter.notifyItemChanged(personIndex);

                            // if player on left won
                            if (people.get(personIndex).isWinner())
                            {
                                people.get(personIndex).setStillPlaying(false);
                                people.get(personIndex-1).setStillPlaying(false);

                                if (checkForRoundEnd())
                                {
                                    startNewRound();
                                }
                            }
                        }
                        mAdapter.notifyDataSetChanged();
                    }
                });

        mRecyclerView.addOnItemTouchListener(swipeTouchListener);
    }

    public void checkForRematches()
    {
        int i = 0;
        Person personA;
        Person personB;
        ListIterator<Person> a;

        boolean collision = false;
        int numberOfItterations = 0;

       // do {
            a = people.listIterator();
            collision = false;
            i=0;
            while ( i < (int)(people.size() / 2))
            {
                personA = a.next();
                personB = a.next();
                i++;

                if (personA.hasFought(personB)) {
                    a.remove();
                    a.add(personB);
                    people.add(personB);
                    collision = true;
                    Toast.makeText(this,"WTF", Toast.LENGTH_SHORT);
                }
            }
            numberOfItterations++;
       // } while(collision);

        Toast.makeText(this, "prepare match had to itterate "+numberOfItterations+ "times", Toast.LENGTH_SHORT).show();
    }

    public void prepareMatch() {
        Collections.shuffle(people);

        int i = 0;
        Person personA;
        Person personB;
        ListIterator<Person> a = people.listIterator();

        if (round > 1)
        {
        //    checkForRematches();
        }

        while (i < (int)(people.size() / 2))
        {
            personA = a.next();
            personB = a.next();
            i++;

            personA.addOpponent(personB);
            personB.addOpponent(personA);
        }
    }

    public boolean checkForRoundEnd()
    {
        int stillPlayingAllowed = people.size() % 2;
        int peopleStillPlaying = 0;

        for (Person person : people) {
            if (person.isStillPlaying()) {
                peopleStillPlaying++;
            }
        }
        return peopleStillPlaying == stillPlayingAllowed;
    }

    public void startNewRound()
    {
        Iterator<Person> i = people.iterator();
        Person person;
        while (i.hasNext()) {
            person = i.next();
            if (!person.isWinner() && !person.isStillPlaying())
            {
                i.remove();
            }
            person.clearWins();
            person.setStillPlaying(true);
        }
        if (people.size() > 1) {
            Toast.makeText(this, "Starting new round", Toast.LENGTH_SHORT).show();
            Intent intent = new Intent(this, CurrentMatchActivity.class);
            intent.putExtra("round",++round);
            intent.putParcelableArrayListExtra("people", people);
            startActivity(intent);
        }
        else
        {
            Intent intent = new Intent(this, GameOverActivity.class);
            intent.putParcelableArrayListExtra("people", people);
            startActivity(intent);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_current_match, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();
        dataFragment.setData(people);
    }
}

now the odd part is it works fine. unless I activate the code.

现在奇怪的部分是它工作正常。除非我激活代码。

public void prepareMatch() {
    Collections.shuffle(people);
    int i = 0;
    Person personA;
    Person personB;
    ListIterator<Person> a;

    while (i < (int)(people.size() / 2))
    {
        personA = a.next();
        personB = a.next();
        i++;

        personA.addOpponent(personB);
        personB.addOpponent(personA);
    }
}

which causes a null pointer crash in the MainAdapter

这导致MainAdapter中的空指针崩溃

The mainActivity uses the mainAdapter. but the currentMatchActivity uses a CurrentMatch adapter.. And the crash happens when it tries to create an CurrentMatchActivity from the CurrentMatchActivity.

mainActivity使用mainAdapter。但currentMatchActivity使用CurrentMatch适配器..当它试图从CurrentMatchActivity创建CurrentMatchActivity时发生崩溃。

I don't believe that MainAdapter should even be in use here... only CurrentMatchAdapter. Furthermore... I don't see how activating the prepareMatch function should affect the flow of my code in that way..

我不相信MainAdapter甚至应该在这里使用......只有CurrentMatchAdapter。此外...我没有看到如何激活prepareMatch函数应该以这种方式影响我的代码流。

Edit: found out that it was crashing because of because of the parcelable. Guess it didn't like a person list inside of a person list.

编辑:发现它因为可分解而崩溃了。猜猜它不喜欢人名单中的人名单。

1 个解决方案

#1


-1  

I came to the conclusion that the issue was nesting an arraylist of a class inside an arraylist of the same class and making it parcelable. I ended up using an arraylist of int primary keys inside of the class and it fixed the issue.

我得出的结论是,这个问题是在同一个类的一个arraylist中嵌入一个类的arraylist并使其可以分解。我最终在类中使用了int主键的arraylist并修复了问题。

Example:

class A implements parcelable {
      arraylist<int> keys;
}


arraylist<a>

#1


-1  

I came to the conclusion that the issue was nesting an arraylist of a class inside an arraylist of the same class and making it parcelable. I ended up using an arraylist of int primary keys inside of the class and it fixed the issue.

我得出的结论是,这个问题是在同一个类的一个arraylist中嵌入一个类的arraylist并使其可以分解。我最终在类中使用了int主键的arraylist并修复了问题。

Example:

class A implements parcelable {
      arraylist<int> keys;
}


arraylist<a>