Android: приведение сериализуемого из пакета не удается в телефоне, но не в эмуляторе

долгое время слушаю, звоню впервые, так что извините, если мое форматирование ужасно.

Версия TL/DR:

Поместите сериализуемый класс [] в пакет/намерение в моей службе. Отправить в основную активность через BroadcastReceiver. При извлечении object[] из пакета и попытке вернуться к моему пользовательскому классу на моем телефоне (MOTO Razr HD) возникает дамп, но не в моем эмуляторе Android Studio.

Я только начал работать с Android в течение последних нескольких месяцев и в значительной степени полагался на их учебные пособия / Google, чтобы учиться, поэтому есть большая вероятность, что это может быть пробел.

Итак, моя цель здесь состоит в том, чтобы Служба работала во время моих различных действий, и чтобы эта служба отвечала за связь с сервером (создание игры в шахматы, по сути, для работы с Android). Эмулятор работал как положено во время моего тестирования, но когда я запускаю его на своем телефоне, он сбрасывается.

У меня были другие сериализуемые объекты, которые передавались между действиями в пакетах, и раньше это работало нормально. Однако с введением этой службы он, похоже, упускает из виду фактический тип объекта, которым он является (показан на снимках экрана ниже), и не позволяет мне вернуться из Object[] в мой GameContainer[].

Мой следующий шаг - попробовать другой телефон... Использование SharedPreferences вообще не работало на моем телефоне (логика этого происходит задолго до того, как произойдет дамп), и начало работать только тогда, когда я начал отлаживать свой телефон, несмотря на отсутствие изменений в моем исходном коде за это время. Мой телефон может быть просто borked.

Вот отладочное представление моего пакета(ов) в разное время:

http://imgur.com/a/hu5Tc

image #1 Вот вид отладки моего пакета после того, как я поместил в него свой GameContainer[] через bundle.putSerializable(String, Obj[]) на моем телефоне

image #2 Вот вид отладки моего пакета после того, как широковещательный приемник получает его в моем основном действии и до того, как он попытается передать (что вызывает дамп) на моем телефоне

imgae #3 И здесь то же самое, что и выше, только на моем эмуляторе на моем компе.

Я не уверен, что подмножества mMap, вызывающие исключение ClassNotFoundException, полезны... я вижу это как в своем телефоне, так и в эмуляторе, что заставляет меня предположить, что это просто потому, что я помещаю собственный класс в пакет.

Немного кода для вас, ребята

моя служба - в частности, часть под моей Runnalbe, если состояние = RequestedGames.

package chess2.Services;


import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Binder;
import android.util.Log;
import java.util.Date;


import ServerStuff.ChessClass;
import chess2.source.GameBoard;
import chess2.source.GameContainer;

public class ChessService extends Service {

protected ChessClass theGame;
protected String myState = "INITIAL";
protected String returnState = "INITIAL";
protected String returnMessage = "";
protected GameBoard myGB = null;
protected GameContainer[] myGC = null;
protected int myGameIndex = -1;
private static final String RM = "RETURNMESSSAGE";
private static final String RS = "RETURNSTATE";
private static final String RO = "RETURNOBJECT";
private static final String RA = "RETURNOBJECTARRAY";

public static final String SERVER_RESPONSE = "com.botna.chess2.server_response";
private final Handler handler = new Handler();
Intent intent;
private Runnable sendUpdatesToActivity = new Runnable() {
    public void run() {

        intent.putExtra(RS, returnState);
        intent.putExtra(RM, returnMessage);


        if (returnState.equals("REQUESTEDGAMES")) {
            Bundle b = new Bundle();
            b.putSerializable(RA,myGC);
            intent.putExtras(b);
        }
        if (returnState.equals("GAMELOADED"))
        {
            Bundle b = new Bundle();
            b.putSerializable(RO,myGB);
            intent.putExtras(b);
        }


        sendBroadcast(intent);
    }

};



@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    //TODO do something useful

    //make sure our connection is still setup.
    try {
        if (theGame == null) {

            theGame = new ChessClass();
        }
    }
    catch(Exception e)
    {
        //TODO
    }


    //Gather information out fo the intent and decipher what
    //we need to send to the server based on MODE, STATE, PAYLOAD etc

    //SEnd it to the server, get our response

    //PUt the response in our intent.


    //post our updates, which will trigger stuff in the activity.

    String state = intent.getStringExtra("STATE");
    String result = null;
    String[] payload;

    switch(state) {
        case "INITIAL":
            //this specifies the app just resumed activity or did something else that
            //caused the onDestory method to get executed.

            //we want to try and log in our connection if we have a stored username and pword,
            //otherwise, well send a response that the app needs to gather that.

            //find out if username and password is stored already.
            returnState = "NOSAVEDLOGIN";
            break;

        case "LOGINATTEMPT":
            payload = intent.getStringArrayExtra("PAYLOAD");
            if(myState.equals("INITIAL")) {
                try {
                    result = theGame.login(payload[0], payload[1]);

                    //login was a success.
                    returnState = "AUTHENTICATED";
                    returnMessage = result;
                    myState = "LOGGEDIN";
                } catch (Exception e) {

                    //Wrong username/pwrod/ or generic error.
                    returnState = "ERROR";
                    returnMessage = e.getMessage();
                }
            }
            else
                returnState = "ALREADYLOGGED";
            break;

        case "REGISTERATTEMPT":
            payload = intent.getStringArrayExtra("PAYLOAD");
            try {
                result = theGame.register(payload[0], payload[1]);
                //login was a success.
                returnState = "JUSTTOAST";
                returnMessage = result;
            } catch (Exception e) {

                //invalid username, username already exists, something else.
                returnState = "ERROR";
                returnMessage = e.getMessage();
            }

            break;

        case "CREATEGAME":
            payload = intent.getStringArrayExtra("PAYLOAD");

            try{

                result = theGame.createNewGame(payload[0],payload[1]);
                returnState = "JUSTTOAST";
                returnMessage = result;

            }
            catch (Exception e) {

                //invalid username, username already exists, something else.
                returnState = "ERROR";
                returnMessage = e.getMessage();
            }
            break;
        case "REQUESTGAMES":
            payload = intent.getStringArrayExtra("PAYLOAD");

            try{

                theGame.refreshGames();
                GameContainer[] myGames = theGame.getCurrentGames();
                myState = returnState = "REQUESTEDGAMES";
                returnMessage = "";
                myGC = myGames;

            }
            catch (Exception e) {

                //invalid username, username already exists, something else.
                returnState = "ERROR";
                returnMessage = e.getMessage();
            }

            break;

        case "CHOOSEBLACK":
            char variant = intent.getCharExtra("PAYLOAD", 'z');

            if(variant != 'z')
            {


                try {
                    theGame.updateClassChoice(variant);
                    //success, start a game jsut the same
                    returnState = "GAMELOADED";
                    returnMessage = theGame.getName();
                    myGB = theGame.getGame();
                }
                catch (Exception e) {

                    //invalid username, username already exists, something else.
                    returnState = "ERROR";
                    returnMessage = e.getMessage();
                }
            }

        case "LOADGAME":
            int index = intent.getIntExtra("INDEX", -1);
            myGameIndex = index;
            try{

                result =  theGame.loadGame(index);
                if(result.equals("SUCCESS")) {
                    returnState = "GAMELOADED";
                    returnMessage = theGame.getName();
                    myGB = theGame.getGame();
                }
                else
                {
                    //black needs update
                    returnState = "BLACKUPDATE";
                    returnMessage = "";
                }
            }
            catch (Exception e) {

                //invalid username, username already exists, something else.
                returnState = "ERROR";
                returnMessage = e.getMessage();
            }

            break;

        case "ATTEMPTMOVE":
            int[] moves = intent.getIntArrayExtra("PAYLOAD");

            try{

                result = theGame.sendMove(moves);
                returnState = "MOVEMADE";
                returnMessage = result;

            }
            catch (Exception e) {

                //invalid username, username already exists, something else.
                returnState = "ERROR";
                returnMessage = e.getMessage();
            }

            break;

        case "REFRESHGAME":

            try{

                result =  theGame.loadGame(myGameIndex);
                if(result.equals("SUCCESS")) {
                    returnState = "GAMELOADED";
                    returnMessage = theGame.getName();
                    myGB = theGame.getGame();
                }
            }
            catch (Exception e) {

                //invalid username, username already exists, something else.
                returnState = "ERROR";
                returnMessage = e.getMessage();
            }

            break;

        case "ENACTSKIRMISH":

            int wager = intent.getIntExtra("PAYLOAD",-1);

            try{

                result = theGame.sendSkirmish(wager);
                returnState = "SKIRMISHSENT";
            }
            catch (Exception e) {

                //invalid username, username already exists, something else.
                returnState = "ERROR";
                returnMessage = e.getMessage();
            }

            break;

        case "FINISHSKIRMISH":
            int finish = intent.getIntExtra("PAYLOAD",-1);


            try{

                result = theGame.finishSkirmish(finish);
                returnState = "SKIRMISHSENT";
            }
            catch (Exception e) {

                //invalid username, username already exists, something else.
                returnState = "ERROR";
                returnMessage = e.getMessage();
            }

            break;
    }
    //state suggests what we are being sent from the activity.
    //do the needful based on its payload and other stuff,
    //send to server, and send back the servers response so our
    //activity can do wahtever is necessary from taht point forward.

    handler.removeCallbacks(sendUpdatesToActivity);
    handler.post(sendUpdatesToActivity);
    return Service.START_STICKY;

}

@Override
public void onCreate()
{
    super.onCreate();
    intent = new Intent(SERVER_RESPONSE);


}

@Override
public void onDestroy()
{
    theGame.disconnect();
}

@Override
public IBinder onBind(Intent intent) {
    return null;
}

}

Вот мой широковещательный приемник в моей основной деятельности, так как мне не хватает места. В частности, найдите случай «REQUESTEDGAMES», чтобы увидеть строку пакета, которую я пометил ->, чтобы указать на нее.

package com.botna.chess2;




import java.util.ArrayList;

import chess2.Services.ChessService;

import chess2.source.GameContainer;
import chess2.Activities.*;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.Toast;

import ServerStuff.ChessClass;


public class MainActivity extends ActionBarActivity {

    public static final String PREFERENCES = "com.botna.chess2";
    public static final String INITIAL = "INITIAL";
    public static final String LOGGED = "LOGGED";
    private static final String RM = "RETURNMESSSAGE";
    private static final String RS = "RETURNSTATE";
    private static final String RO = "RETURNOBJECT";
    private static final String RA = "RETURNOBJECTARRAY";


    protected ChessClass theGame;
    protected Toast toast = null;
    protected String[] variants={"Classic", "Reapers", "Nemesis","Empowered",
            "Animals","Two-Kings"};
    protected String[] myGamesString;
    protected GameContainer[] myGames;
    protected String myName;
    protected String state = null;
    protected boolean transitioning = false;
    protected MainActivity pointer = this;
    private Intent myService;


    private BroadcastReceiver broadCastReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            updateActivity(intent);
        }
    };


    private void updateActivity(Intent intent)
    {


        String returnState = intent.getStringExtra(RS);
        String returnMessage = intent.getStringExtra(RM);
        Bundle b = null;

        switch(returnState)
        {
            case "NOSAVEDLOGIN":

                setContentView(R.layout.activity_main);
                break;

            case "AUTHENTICATED":
                setContentView(R.layout.activity_main_menu);
                state = LOGGED;

                SharedPreferences prefs = getSharedPreferences(PREFERENCES, MODE_PRIVATE);
                String restoredUName = prefs.getString("USERNAME", null);
                String restoredPWord = prefs.getString("PASSWORD", null);
                if(restoredUName == null || restoredPWord == null);
                {
                //need to save our username and password in the preferences now.
                //no previous shared preferences, lets update it.

                SharedPreferences.Editor editor = getSharedPreferences(PREFERENCES, MODE_PRIVATE).edit();
                editor.putString("USERNAME", myService.getStringArrayExtra("PAYLOAD")[0]);
                editor.putString("PASSWORD",myService.getStringArrayExtra("PAYLOAD")[1]);
                editor.commit();
                }

                break;

            case "REQUESTEDGAMES":

                b = intent.getExtras();
                 //DUMPS RIGHT HERE AT THE ->  
                ->myGames = (GameContainer[])b.getSerializable(RA);
                //myGames = (GameContainer[])intent.getSerializableExtra(RA);

                int counter = 1;


                if(myGames.length == 0 || myGames[0] == null)
                {
                    toast = Toast.makeText(getApplicationContext(),"You dont have any games =(",Toast.LENGTH_LONG);
                    toast.show();
                }
                else
                {
                    ArrayList<String> list = new ArrayList<String>();
                    String temp;
                    for(int i = 0; i< myGames.length; i++)
                    {
                        if(myGames[i] != null)
                        {
                            temp = myGames[i].getWhiteTeam() + " vs " + myGames[i].getBlackTeam() ;
                            if(myGames[i].getWinner() != null)
                            {
                                //game is over.
                                temp = temp + " - Game Over";
                            }
                            else if(myGames[i].getBlackVar() < 'A')
                            {
                                temp = temp + " - Awaiting Pick";
                            }
                            else if(myGames[i].getTurn().equals(myName))
                                temp = temp + " - Your Turn";
                            else
                                temp = temp + " - Their Turn";
                            list.add(temp);
                            counter++;
                        }
                    }
                    myGamesString = null;
                    myGamesString = list.toArray(new String[list.size()]);
                    GameChoiceDialog gameDialog = new GameChoiceDialog();
                    state = "GAMESELECTED";
                    FragmentManager fm = getSupportFragmentManager();
                    gameDialog.show(fm, "Dialog Fragment");
                }
                break;

            case "BLACKUPDATE":
                        ClassChoiceDialog classChoiceDialog = new ClassChoiceDialog();

                        FragmentManager fm = getSupportFragmentManager();
                        classChoiceDialog.show(fm, "Dialog Fragment");
                break;
            case "GAMELOADED":

                        state = "PLAYINGGAME";
                        b = intent.getExtras();
                        Intent playGameIntent = new Intent(this, PlayGameActivity.class);
                        playGameIntent.putExtras(b);
                        startActivityForResult(playGameIntent, 0);
                break;
            case "JUSTTOAST":
            case "ERROR":
                if(toast != null)
                    toast.cancel();

                toast = Toast.makeText(getApplicationContext(),returnMessage,Toast.LENGTH_LONG);
                toast.show();
                break;


        }
    }

и вот часть моего игрового контейнера, показывающая, что он Serializable

package chess2.source;



import java.io.Serializable;
import java.util.UUID;



public class GameContainer implements Serializable{

В зависимости от интереса, который это вызывает, моим следующим шагом будет отойти от широковещательных приемников и просто привязаться к Сервису, как я понимаю, с точным 1 учебным пособием, которое я прочитал о привязке к сервисам, это позволяет вам выполнять методы непосредственно внутри класс обслуживания, который должен обойти необходимость транспортировки моего GameContainer[] через пакет и широковещательный приемник и просто позволить ему быть возвращаемым параметром.

Любая помощь будет здорово! Подобрался довольно близко к лимиту символов, у меня есть еще много кода, чтобы показать, может ли он быть полезен!


person Andrew Moore    schedule 26.02.2015    source источник
comment
Немного смущает, что я не нашел статей об этом ранее, но, видимо, java действительно трудно преобразовать Object[] в CustomClass[]. Многие статьи, которые я вижу, показывают, что если он исходит от Object[], его нужно повторять и каста индивидуально. Я должен дать этому шанс и посмотреть, имеет ли это какое-то значение. Когда я думаю об этом, кастинг, который я использовал ранее для этого массива, был прямо из InputStream с моего сервера, поэтому, возможно, он никогда не достигает этого промежуточного состояния «объекта», поэтому он терпит неудачу сейчас, а не раньше. Все еще не уверен на SIM против телефона.   -  person Andrew Moore    schedule 26.02.2015


Ответы (1)


Очевидно, Java не любит приведение от Object[] к CustomClass[]. Однако выполнение bundle.getSerializable() и помещение его в Object[], а затем приведение каждого объекта по отдельности устранило проблему. Должно быть какое-то несоответствие между моим телефоном и моим эмулятором!

person Andrew Moore    schedule 26.02.2015