过去四天我的Android应用程序一直困在这个问题上。我正在尝试从Google Play服务启动默认的播放器选择器UI屏幕,每当我这样做时,我都会遇到NullPointerException:
04-03 13:12:22.045: E/AndroidRuntime(13042): FATAL EXCEPTION: main
04-03 13:12:22.045: E/AndroidRuntime(13042): java.lang.NullPointerException: Appropriate Api was not requested.
04-03 13:12:22.045: E/AndroidRuntime(13042): at com.google.android.gms.internal.er.b(Unknown Source)
04-03 13:12:22.045: E/AndroidRuntime(13042): at com.google.android.gms.common.api.b.a(Unknown Source)
04-03 13:12:22.045: E/AndroidRuntime(13042): at com.google.android.gms.games.Games.c(Unknown Source)
04-03 13:12:22.045: E/AndroidRuntime(13042): at com.google.android.gms.internal.gn.getSelectOpponentsIntent(Unknown Source)
04-03 13:12:22.045: E/AndroidRuntime(13042): at com.geti.geti.graphics.MultiplayerLobbyView.startInviteGame(MultiplayerLobbyView.java:102)
04-03 13:12:22.045: E/AndroidRuntime(13042): at com.geti.geti.graphics.MultiplayerLobbyView.onClick(MultiplayerLobbyView.java:302)
04-03 13:12:22.045: E/AndroidRuntime(13042): at android.view.View.performClick(View.java:4475)
04-03 13:12:22.045: E/AndroidRuntime(13042): at android.view.View$PerformClick.run(View.java:18786)
04-03 13:12:22.045: E/AndroidRuntime(13042): at android.os.Handler.handleCallback(Handler.java:730)
04-03 13:12:22.045: E/AndroidRuntime(13042): at android.os.Handler.dispatchMessage(Handler.java:92)
04-03 13:12:22.045: E/AndroidRuntime(13042): at android.os.Looper.loop(Looper.java:137)
04-03 13:12:22.045: E/AndroidRuntime(13042): at android.app.ActivityThread.main(ActivityThread.java:5419)
04-03 13:12:22.045: E/AndroidRuntime(13042): at java.lang.reflect.Method.invokeNative(Native Method)
04-03 13:12:22.045: E/AndroidRuntime(13042): at java.lang.reflect.Method.invoke(Method.java:525)
04-03 13:12:22.045: E/AndroidRuntime(13042): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187)
04-03 13:12:22.045: E/AndroidRuntime(13042): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
04-03 13:12:22.045: E/AndroidRuntime(13042): at dalvik.system.NativeStart.main(Native Method)
我关注此事:https://developers.google.com/games/services/android/realtimeMultiplayer。这是我的相关代码(我删除了导入):
public class MainActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener, OnClickListener {
private static final int RC_SIGN_IN = 0;
private GoogleApiClient mGoogleApiClient;
private boolean mIntentInProgress;
private boolean mSignInClicked;
private ConnectionResult mConnectionResult;
public void onCreate(Bundle savedInstanceState)
{
requestWindowFeature(Window.FEATURE_NO_TITLE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Plus.API, null)
.addScope(Plus.SCOPE_PLUS_LOGIN)
.build();
findViewById(R.id.sign_in_button).setOnClickListener(this);
findViewById(R.id.sign_out_button).setOnClickListener(this);
findViewById(R.id.goButton).setOnClickListener(this);
}
public GoogleApiClient getApiClient()
{
return mGoogleApiClient;
}
private void resolveSignInError()
{
if (mConnectionResult.hasResolution())
{
try
{
mIntentInProgress = true;
mConnectionResult.startResolutionForResult(this, RC_SIGN_IN);
}
catch (SendIntentException e)
{
mIntentInProgress = false;
mGoogleApiClient.connect();
}
}
}
protected void onStart()
{
super.onStart();
mGoogleApiClient.connect();
}
protected void onStop()
{
super.onStop();
if (mGoogleApiClient.isConnected())
{
mGoogleApiClient.disconnect();
}
}
@Override
public void onConnectionFailed(ConnectionResult result)
{
if (!mIntentInProgress)
{
mConnectionResult = result;
if (mSignInClicked)
{
resolveSignInError();
}
}
}
protected void onActivityResult(int requestCode, int responseCode, Intent intent)
{
if (requestCode == RC_SIGN_IN)
{
if (requestCode == RC_SIGN_IN)
{
if (responseCode != RESULT_OK)
{
mSignInClicked = false;
}
}
mIntentInProgress = false;
if (!mGoogleApiClient.isConnecting())
{
mGoogleApiClient.connect();
}
}
}
@Override
public void onConnected(Bundle connectionHint)
{
mSignInClicked = false;
if (Plus.PeopleApi.getCurrentPerson(mGoogleApiClient) != null)
{
Person currentPerson = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient);
String personName = currentPerson.getDisplayName();
Toast.makeText(this, "User if connected! Welcome " + personName +"!", Toast.LENGTH_LONG).show();
}
}
@Override
public void onConnectionSuspended(int cause)
{
mGoogleApiClient.connect();
}
@Override
public void onClick(View v)
{
if (v.getId() == R.id.sign_in_button)
{
findViewById(R.id.sign_in_button).setVisibility(View.GONE);
findViewById(R.id.sign_out_button).setVisibility(View.VISIBLE);
}
if (v.getId() == R.id.sign_in_button
&& !mGoogleApiClient.isConnecting())
{
mSignInClicked = true;
resolveSignInError();
}
if (v.getId() == R.id.sign_out_button)
{
if (mGoogleApiClient.isConnected())
{
Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
mGoogleApiClient.disconnect();
mGoogleApiClient.connect();
findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
findViewById(R.id.sign_out_button).setVisibility(View.GONE);
}
}
if (v.getId() == R.id.goButton)
{
goToTitleScreen();
}
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onPause() {
super.onPause();
}
public void goToTitleScreen() {
Intent intent = new Intent(this, TitleScreen.class);
startActivity(intent);
finish();
}
}
我的多人游戏大厅:
public class MultiplayerLobbyView extends MainActivity implements RoomUpdateListener, RoomStatusUpdateListener, RealTimeMessageReceivedListener
{
final static int RC_SELECT_PLAYERS = 10000;
final static int RC_WAITING_ROOM = 10002;
boolean mPlaying = false;
final static int MIN_PLAYERS = 2;
@Override
public void onCreate(Bundle savedInstanceState)
{
requestWindowFeature(Window.FEATURE_NO_TITLE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
super.onCreate(savedInstanceState);
setContentView(R.layout.multiplayer_lobby);
findViewById(R.id.quickGame).setOnClickListener(this);
findViewById(R.id.invitePlayers).setOnClickListener(this);
}
private RoomConfig.Builder makeBasicRoomConfigBuilder()
{
RoomConfig.Builder builder = RoomConfig.builder(this);
builder.setRoomStatusUpdateListener(this);
builder.setMessageReceivedListener(this);
return builder;
}
boolean shouldStartGame(Room room)
{
int connectedPlayers = 0;
for (Participant p : room.getParticipants())
{
if (p.isConnectedToRoom())
{
++connectedPlayers;
}
}
return (connectedPlayers >= MIN_PLAYERS);
}
private void startQuickGame()
{
// auto-match criteria to invite one random automatch opponent.
// You can also specify more opponents (up to 3).
Bundle am = RoomConfig.createAutoMatchCriteria(1, 1, 0);
// build the room config:
RoomConfig.Builder roomConfigBuilder = makeBasicRoomConfigBuilder();
roomConfigBuilder.setAutoMatchCriteria(am);
RoomConfig roomConfig = roomConfigBuilder.build();
// create room:
Games.RealTimeMultiplayer.create(getApiClient(), roomConfig);
// prevent screen from sleeping during handshake
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// go to game screen
}
private void startInviteGame()
{
GoogleApiClient mClient = getApiClient();
Intent intent = Games.RealTimeMultiplayer.getSelectOpponentsIntent(mClient, 1, 4, true);
try
{
startActivityForResult(intent, RC_SELECT_PLAYERS);
}catch (NullPointerException e)
{
System.out.println("Error.");
}
}
public void onActivityResult(int request, int response, Intent data)
{
if (request == RC_SELECT_PLAYERS)
{
if (response != Activity.RESULT_OK)
{
// user canceled
return;
}
// get the invitee list
Bundle extras = data.getExtras();
final ArrayList<String> invitees =
data.getStringArrayListExtra(Multiplayer.EXTRA_INVITATION);
// get auto-match criteria
Bundle autoMatchCriteria = null;
int minAutoMatchPlayers =
data.getIntExtra(Multiplayer.EXTRA_MIN_AUTOMATCH_PLAYERS, 0);
int maxAutoMatchPlayers =
data.getIntExtra(Multiplayer.EXTRA_MAX_AUTOMATCH_PLAYERS, 0);
if (minAutoMatchPlayers > 0)
{
autoMatchCriteria =
RoomConfig.createAutoMatchCriteria(
minAutoMatchPlayers, maxAutoMatchPlayers, 0);
} else
{
autoMatchCriteria = null;
}
startQuickGame();
}
}
@Override
public void onConnectedToRoom(Room room) {
// TODO Auto-generated method stub
}
@Override
public void onDisconnectedFromRoom(Room room)
{
}
@Override
public void onP2PConnected(String participantId) {
// TODO Auto-generated method stub
}
@Override
public void onP2PDisconnected(String participantId) {
// TODO Auto-generated method stub
}
@Override
public void onPeerDeclined(Room room, List<String> peers)
{
if (!mPlaying && shouldCancelGame(room))
{
Games.RealTimeMultiplayer.leave(getApiClient(), null, room.getRoomId());
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
private boolean shouldCancelGame(Room room) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onPeerInvitedToRoom(Room arg0, List<String> arg1) {
// TODO Auto-generated method stub
}
@Override
public void onPeerJoined(Room arg0, List<String> arg1) {
// TODO Auto-generated method stub
}
@Override
public void onPeerLeft(Room room, List<String> peers)
{
if (!mPlaying && shouldCancelGame(room))
{
Games.RealTimeMultiplayer.leave(getApiClient(),null, room.getRoomId());
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
@Override
public void onPeersConnected(Room room, List<String> peers)
{
if (mPlaying)
{
String mNewParticipant = new String();
room.getParticipantIds().add(mNewParticipant);
}
else if (shouldStartGame(room))
{
//start
}
}
@Override
public void onPeersDisconnected(Room arg0, List<String> arg1) {
// TODO Auto-generated method stub
}
@Override
public void onRoomAutoMatching(Room room) {
// TODO Auto-generated method stub
}
@Override
public void onRoomConnecting(Room room) {
// TODO Auto-generated method stub
}
@Override
public void onJoinedRoom(int statusCode, Room room)
{
if (statusCode != GamesStatusCodes.STATUS_OK)
{
Toast.makeText(this, "Error!", Toast.LENGTH_LONG).show();
return;
}
Intent i = Games.RealTimeMultiplayer.getWaitingRoomIntent(getApiClient(), room, Integer.MAX_VALUE);
startActivityForResult(i, RC_WAITING_ROOM);
}
@Override
public void onLeftRoom(int statusCode, String roomId) {
// TODO Auto-generated method stub
}
@Override
public void onRoomConnected(int statusCode, Room room)
{
if (statusCode != GamesStatusCodes.STATUS_OK)
{
// let screen go to sleep
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// show error message, return to main screen.
Toast.makeText(this, "Error!", Toast.LENGTH_LONG).show();
goToTitleScreen();
}
}
@Override
public void onRoomCreated(int statusCode, Room room)
{
if (statusCode != GamesStatusCodes.STATUS_OK)
{
Toast.makeText(this, "Error!", Toast.LENGTH_LONG).show();
return;
}
// get waiting room intent
Intent i = Games.RealTimeMultiplayer.getWaitingRoomIntent(getApiClient(), room, Integer.MAX_VALUE);
startActivityForResult(i, RC_WAITING_ROOM);
}
@Override
public void onClick(View v)
{
if (v.getId() == R.id.quickGame)
{
startQuickGame();
}
else if (v.getId() == R.id.invitePlayers)
{
startInviteGame();
}
}
@Override
public void onRealTimeMessageReceived(RealTimeMessage message) {
// TODO Auto-generated method stub
}
}
我发现抛出异常的方法是:
private void startInviteGame()
{
GoogleApiClient mClient = getApiClient();
Intent intent = Games.RealTimeMultiplayer.getSelectOpponentsIntent(mClient, 1, 4, true);
try
{
startActivityForResult(intent, RC_SELECT_PLAYERS);
}catch (NullPointerException e)
{
System.out.println("Error.");
}
}
我是否正确使用了GoogleApiClient?还是有什么我想念的?我认为MainActivity中的getter足以抓住客户端。
答案 0 :(得分:1)
我一直在玩,并在一分钟前遇到了同样的错误。这对我有用。请查看Accessing the Developer APIs页面。重要的是:
@Override
public void onCreate(Bundle savedInstanceState) {
// set requested clients (games and cloud save)
setRequestedClients(BaseGameActivity.CLIENT_GAMES |
BaseGameActivity.CLIENT_APPSTATE);
…
}
标志BaseGameActivity.CLIENT_GAMES | BaseGameActivity.CLIENT_APPSTATE要求Play游戏和Cloud Save API。
如果您正在扩展BaseGameActivity类,那么也可以选择不同的选项。在CollectAllTheStars sample中,它们将请求的API传递给BaseGameActivity构造函数:
public MainActivity() {
// request that superclass initialize and manage the AppStateClient for us
super(BaseGameActivity.CLIENT_APPSTATE);
}
此游戏仅使用Cloud Save,因此它只有CLIENT_APPSTATE标志。