долгое время слушаю, звоню впервые, так что извините, если мое форматирование ужасно.
Версия TL/DR:
Поместите сериализуемый класс [] в пакет/намерение в моей службе. Отправить в основную активность через BroadcastReceiver. При извлечении object[] из пакета и попытке вернуться к моему пользовательскому классу на моем телефоне (MOTO Razr HD) возникает дамп, но не в моем эмуляторе Android Studio.
Я только начал работать с Android в течение последних нескольких месяцев и в значительной степени полагался на их учебные пособия / Google, чтобы учиться, поэтому есть большая вероятность, что это может быть пробел.
Итак, моя цель здесь состоит в том, чтобы Служба работала во время моих различных действий, и чтобы эта служба отвечала за связь с сервером (создание игры в шахматы, по сути, для работы с Android). Эмулятор работал как положено во время моего тестирования, но когда я запускаю его на своем телефоне, он сбрасывается.
У меня были другие сериализуемые объекты, которые передавались между действиями в пакетах, и раньше это работало нормально. Однако с введением этой службы он, похоже, упускает из виду фактический тип объекта, которым он является (показан на снимках экрана ниже), и не позволяет мне вернуться из Object[] в мой GameContainer[].
Мой следующий шаг - попробовать другой телефон... Использование SharedPreferences вообще не работало на моем телефоне (логика этого происходит задолго до того, как произойдет дамп), и начало работать только тогда, когда я начал отлаживать свой телефон, несмотря на отсутствие изменений в моем исходном коде за это время. Мой телефон может быть просто borked.
Вот отладочное представление моего пакета(ов) в разное время:
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[] через пакет и широковещательный приемник и просто позволить ему быть возвращаемым параметром.
Любая помощь будет здорово! Подобрался довольно близко к лимиту символов, у меня есть еще много кода, чтобы показать, может ли он быть полезен!