Как передать объект GoogleApiClient в другой вид деятельности
В моем логине у меня есть кнопка входа в Google. Я проверил и работает отлично. У меня были другие кнопки для выхода и отмены, и они работали нормально.
Это мой код экрана входа в систему.
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.auth.api.signin.GoogleSignInResult;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.SignInButton;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.OptionalPendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements
View.OnClickListener,
GoogleApiClient.OnConnectionFailedListener
{
private static final String TAG = MainActivity.class.getSimpleName();
private static final int RC_SIGN_IN = 007;
private GoogleApiClient mGoogleApiClient;
private ProgressDialog mProgressDialog;
private SignInButton btnSignIn;
List<String> profile=new ArrayList<>();
private MyGoogleApi_Singleton myGoogleApi_singleton;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnSignIn = (SignInButton) findViewById(R.id.sign_in_button);
btnSignIn.setOnClickListener(this);
updateUI(false);
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, this)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
/* Customizing G+ button
btnSignIn.setSize(SignInButton.SIZE_STANDARD);
btnSignIn.setScopes(gso.getScopeArray());*/
//Create a new objet to handle in all class
myGoogleApi_singleton= new MyGoogleApi_Singleton();
myGoogleApi_singleton.getInstance(mGoogleApiClient);
}
private void signIn()
{
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
}
private void signOut()
{
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>()
{
@Override
public void onResult(Status status)
{
updateUI(false);
}
});
}
private void revokeAccess()
{
Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>()
{
@Override
public void onResult(Status status)
{
updateUI(false);
}
});
}
private void handleSignInResult(GoogleSignInResult result)
{
Log.d(TAG, "handleSignInResult:" + result.isSuccess());
if (result.isSuccess())
{
// Signed in successfully, show authenticated UI.
GoogleSignInAccount acct = result.getSignInAccount();
String personName = acct.getDisplayName();
String personPhotoUrl = acct.getPhotoUrl().toString();
String email = acct.getEmail();
String idnumber= acct.getId();
Log.e(TAG, "Name: " + personName + ", email: " + email
+ ", Image: " + personPhotoUrl+ ", Id Number: "+ idnumber);
//Save the data into the arraylist
profile.add(idnumber);
profile.add(personName);
profile.add(email);
profile.add(personPhotoUrl);
//save into sharedpreferences
StringBuilder stringBuilder = new StringBuilder();
for (String s:profile)
{
stringBuilder.append(s);
stringBuilder.append(",");
}
SharedPreferences sharpref = getSharedPreferences("ProfileList",0);
SharedPreferences.Editor editor = sharpref.edit();
editor.putString("ProfileList", stringBuilder.toString());
editor.commit();
goIndexScreen();
} else
{
// Signed out, show unauthenticated UI.
updateUI(false);
}
}
@Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.sign_in_button:
signIn();
break;
default:
break;
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == RC_SIGN_IN)
{
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
handleSignInResult(result);
}
}
@Override
public void onStart()
{
super.onStart();
OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
if (opr.isDone())
{
// If the user's cached credentials are valid, the OptionalPendingResult will be "done"
// and the GoogleSignInResult will be available instantly.
Log.d(TAG, "Got cached sign-in");
GoogleSignInResult result = opr.get();
handleSignInResult(result);
} else
{
// If the user has not previously signed in on this device or the sign-in has expired,
// this asynchronous branch will attempt to sign in the user silently. Cross-device
// single sign-on will occur in this branch.
showProgressDialog();
opr.setResultCallback(new ResultCallback<GoogleSignInResult>()
{
@Override
public void onResult(GoogleSignInResult googleSignInResult)
{
hideProgressDialog();
handleSignInResult(googleSignInResult);
}
});
}
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult)
{
// An unresolvable error has occurred and Google APIs (including Sign-In) will not
// be available.
Log.d(TAG, "onConnectionFailed:" + connectionResult);
}
//method to show a progress dialog during the SignIn
private void showProgressDialog()
{
if (mProgressDialog == null)
{
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setMessage("Loading...");
mProgressDialog.setIndeterminate(true);
}
mProgressDialog.show();
}
//method to hide the progress dialog
private void hideProgressDialog()
{
if (mProgressDialog != null && mProgressDialog.isShowing())
{
mProgressDialog.hide();
}
}
//method to show or hide the buttons
private void updateUI(boolean isSignedIn)
{
if (isSignedIn)
{
btnSignIn.setVisibility(View.GONE);
} else
{
btnSignIn.setVisibility(View.VISIBLE);
}
}
//method to go to next activity
private void goIndexScreen()
{
Intent intent=new Intent(this,Index.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
После успешного входа в систему приложение переходит к другому виду деятельности. Мне нужно выйти из этой активности, но мне нужен mGoogleApiClient от LoginActivity, и я не знаю, как я могу это сделать.
Я создал новый класс (синглтон) здесь мой код
import com.google.android.gms.common.api.GoogleApiClient;
class MyGoogleApi_Singleton {
private static final String TAG = "GoogleApiClient";
private static MyGoogleApi_Singleton instance = null;
private static GoogleApiClient mGoogleApiClient = null;
private MyGoogleApi_Singleton(Context context) {
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();
mGoogleApiClient = new GoogleApiClient.Builder(context)
.enableAutoManage(this, this)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
}
public static MyGoogleApi_Singleton getInstance(Context context) {
if(instance == null) {
instance = new MyGoogleApi_Singleton(context);
}
return instance;
}
//methods SingIn,SignOut and Revoke
public void Login(GoogleApiClient bGoogleApiClient){
}
public void Logout(){
if(mGoogleApiClient.isConnected()) {
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
Log.d("LOGOUT-RESULT","LOGOUT");
}
});
}
}
public void Revoke() {
if ((mGoogleApiClient.isConnected())) {
Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
Log.d("REVOKE-RESULT","REVOKE");
}
});
}
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
}
Это код активности индекса
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.util.Log;
import android.view.View;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import java.util.ArrayList;
import java.util.List;
public class Index extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private ImageView ivprofile;
private TextView tvname;
private TextView tvemail;
private TextView tvidnumber;
private String picprofile;
private String name;
private String idnumber;
private String email;
final List<String> profile = new ArrayList<String>();
private View headerview;
private GoogleApiClient mGoogleApiClient;
private MyGoogleApi_Singleton myGoogleApiSingleton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_index);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
//create a headerview to conect to header of left menu
headerview=navigationView.getHeaderView(0);
ivprofile=(ImageView)headerview.findViewById(R.id.imageProfile);
tvname=(TextView)headerview.findViewById(R.id.fullName);
tvemail=(TextView)headerview.findViewById(R.id.email);
tvidnumber=(TextView) headerview.findViewById(R.id.idNumber);
//Load file saved by sharedpreferences into a new arraylist
final SharedPreferences sharpref = getSharedPreferences("ProfileList",0);
String Items = sharpref.getString("ProfileList","");
String [] listItems = Items.split(",");
for (int i=0;i<listItems.length;i++){
profile.add(listItems[i]);
}
//get the profile
idnumber=profile.get(0);
name=profile.get(1);
email=profile.get(2);
picprofile=profile.get(3);
Log.d("ArrayPerfil", name+email+idnumber+picprofile);
tvname.setText(name);
tvidnumber.setText(idnumber);
tvemail.setText(email);
Glide.with(this).load(picprofile).into(ivprofile);
//get the mgoogleapiclient objet
myGoogleApiSingleton=new MyGoogleApi_Singleton();
mGoogleApiClient=myGoogleApiSingleton.get_GoogleApiClient();
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.index, 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);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camera) {
// Handle the camera action
} else if (id == R.id.nav_gallery) {
} else if (id == R.id.nav_slideshow) {
} else if (id == R.id.nav_manage) {
} else if (id == R.id.nav_share) {
} else if (id == R.id.nav_send) {
}else if (id == R.id.logout) {
myGoogleApiSingleton.getInstance(context).Logout();
goLoginScreen();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
//method to go to login screen
private void goLoginScreen() {
Intent intent=new Intent(this,MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
Как вы сказали, я создал прозрачную деятельность. Я добавил метод handleSignInResult, потому что он вызывает метод OnActivityResult.
Это код:
public class GoogleActivity extends AppCompatActivity {
public static final int RC_SIGN_IN = 1000;
private static final String ACTION = "calling_action";
public static Intent getIntent(Context context, int action, Intent actionIntent) {
Intent i = new Intent(context, GoogleActivity.class);
i.putExtra(ACTION, action);
i.putExtra(Intent.EXTRA_INTENT, actionIntent);
return i;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
Intent actionIntent;
int action = getIntent().getIntExtra(ACTION, 0);
switch (action) {
case RC_SIGN_IN:
actionIntent = (Intent) getIntent().getExtras().get(Intent.EXTRA_INTENT);
if (actionIntent != null)
startActivityForResult(actionIntent, RC_SIGN_IN);
break;
case 0:
default:
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case RC_SIGN_IN:
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
handleSignInResult(result);
finish();
return;
}
}
private void handleSignInResult(GoogleSignInResult result)
{
if (result.isSuccess())
{
// Signed in successfully
Log.d("SIGNIN", "YOU ARE LOG IN");
} else
{
// Signed out,
Log.d("SIGNIN", "YOU ARE NOT LOG IN");
}
}
}
Я жду вашей помощи!
Спасибо!
1 ответ
Это не плохая идея, на самом деле это вы должны сделать. Если вы хотите обрабатывать все действия и события из Google Auth, самый простой, элегантный, многократно используемый и проверяемый способ сделать это - заключить эту логику в одно или несколько выделенных для этого предложений.
Если у вас мало действий, вы можете объединить их все в одном классе. Например, вы можете создать класс GoogleSingInWrapper
и использовать Singleton
чтобы убедиться, что во всем приложении есть только один экземпляр.
public class GoogleSingInWrapper {
private static GoogleSingInWrapper instance;
private GoogleApiClient mGoogleApiClient;
private GoogleSingainWrapper() {
// Private constructor to deny the creation of this object through the constructor and prevent creating more then one instance
mGoogleApiClient = /*create your client here*/;
}
public static getInstance(/*params you need*/) {
if(instance == null)
instance = new GoogleSingInWrapper (/*params*/);
return instance;
}
public void login(/*params*/) {
// Login
}
// Other methods
}
Таким образом, чтобы получить (и создать экземпляр, если еще не существует) экземпляр GoogleSingInWrapper
ты используешь:
GoogleSingInWrapper.gerInstance(/*params*/);
Теперь, если вы поместите все переменные и логику в этот класс, вы сможете получить к ним доступ откуда угодно. mGoogleApiClient
должно быть в этой обертке.
Теперь вы можете добавить все методы, которые вам нужны, такие login
, logout
а также revoke
,
И используйте его следующим образом:
GoogleSingInWrapper.getInstance().login(/*params*/);
GoogleSingInWrapper.getInstance().logout(/*params*/);
GoogleSingInWrapper.getInstance().revoke(/*params*/);
Вы не должны использовать mGoogleApiClient
непосредственно, он должен быть заключен в GoogleSingInWrapper
,
РЕДАКТИРОВАТЬ
Когда я сказал mGoogleApiClient
должен быть приватным внутри GoogleSingInWrapper
это означает, что у вас не должно быть доступа к нему вне GoogleSingInWrapper
учебный класс. Если вы создаете GoogleSingInWrapper
но вы создаете метод под названием
public GoogleApiClient get_GoogleApiClient();
ваши проблемы продолжают существовать, потому что вы все еще используете это mGoogleApiClient
во всех видах деятельности. Вы не хотите этого, поэтому вы хотите быть отделенным от этого объекта во всех действиях.
После ваших правок я напишу здесь больше кода, но чем больше свободного кода я вам дам, тем меньше вы узнаете.
public class GoogleSingInWrapper {
private static GoogleSingInWrapper instance;
private GoogleApiClient mGoogleApiClient;
private GoogleSingainWrapper(Context context) {
// Private constructor to deny the creation of this object through the constructor and prevent creating more then one instance
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();
mGoogleApiClient = new GoogleApiClient.Builder(context)
.enableAutoManage(this, this)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
}
public static getInstance(Context context) {
if(instance == null)
instance = new GoogleSingInWrapper (/*params*/);
return instance;
}
public void login(/*params*/) {
// Login
}
// Other methods
public void logout(){
if(mGoogleApiClient.isConnected()) {
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
Log.d("LOGOUT-RESULT","LOGOUT");
}
});
}
}
}
Это должно выглядеть как ваш GoogleSingInWrapper
, А для вызова, например, метода выхода из системы вы должны вызвать следующее:
if (id == R.id.logout) {
GoogleSingInWrapper.getInstance(context).logout();
goLoginScreen();
}
Обратите внимание, что конструктор Private
намеренно, потому что вы не хотите звонить new GoogleSingInWrapper
, Если вы делаете это, вы создаете несколько экземпляров этого объекта, и вы нарушаете Singleton
шаблон.
Кроме того, вы можете заметить, что некоторые процессы, такие как логин, требуют Activity
потому что результаты публикуются в onActivityResult
, Для того, чтобы отделить вас GoogleSingInWrapper
от всех ваших Activities
Вы могли бы создать выделенный Activity
управлять всем onActivityResults
, Это действие должно быть прозрачным и невидимым для пользователя.
Вы можете достичь этого с помощью этого кода:
public class GoogleActivity extends AppCompatActivity {
public static final int RC_SIGN_IN = 1000;
private static final String ACTION = "calling_action";
public static Intent getIntent(Context context, int action, Intent actionIntent) {
Intent i = new Intent(context, GoogleActivity.class);
i.putExtra(ACTION, action);
i.putExtra(Intent.EXTRA_INTENT, actionIntent);
return i;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
Intent actionIntent;
int action = getIntent().getIntExtra(ACTION, 0);
switch (action) {
case RC_SIGN_IN:
actionIntent = (Intent) getIntent().getExtras().get(Intent.EXTRA_INTENT);
if (actionIntent != null)
startActivityForResult(actionIntent, RC_SIGN_IN);
break;
case 0:
default:
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case RC_SIGN_IN:
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
handleSignInResult(result);
finish();
return;
}
}
}
Затем установите прозрачную тему в манифесте для этого Activity
:
<activity
android:name=".data.drive.GoogleActivity"
android:theme="@style/TransparentActivity"/>
И определите свой прозрачный стиль в вашем values
папка:
<style name="TransparentActivity" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
Теперь вам нужно поймать все, что я сделал, и создать конечный продукт, чтобы он заработал.