Как передать объект 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>

Теперь вам нужно поймать все, что я сделал, и создать конечный продукт, чтобы он заработал.

Другие вопросы по тегам