使用片段实现登录的正确方法

时间:2018-01-13 00:13:01

标签: android facebook android-fragments login

我目前正在开发一款使用Facebook和Google登录的应用。 到目前为止,我使用LoginActivity,当登录成功时启动MainActivity。

我想用片段而不是两个活动来重写它,所以我想要做的是,当MainActivity启动时,如果用户没有登录,则显示LoginFragment,它完全符合我的LoginActivity所做的,但是我缺少的是什么是如何正确退出LoginFragment,并返回到我的主片段,即DashboardFragment。

我已经阅读了很多相关内容,但有很多方法可以做到这一点,我无法弄清楚哪种方法最好。此外,给出的解决方案通常与>>> import asyncio >>> async def foo(loop, iv): ... await asyncio.sleep(1, loop=loop) ... print(f'done: {iv}') ... >>> async def await_coro_later(delay, coro, *args, loop=None): ... await asyncio.sleep(delay, loop=loop) ... await coro(*args) ... >>> def callback_to_coroutine(coro, loop, *args): ... asyncio.ensure_future(coro(*args), loop=loop) ... >>> loop = asyncio.get_event_loop() >>> loop.call_later(2, callback_to_coroutine, foo, loop, loop, 'callback_to_coroutine') <TimerHandle when=1643515.105561161 callback_to_coroutine(<function foo at 0x1032dfe18>, <_UnixSelecto...e debug=False>, <_UnixSelecto...e debug=False>, 'callback_to_coroutine') at <stdin>:1> >>> loop.run_until_complete(await_coro_later(5, foo, loop, 'coro_later', loop=loop)) done: callback_to_coroutine done: coro_later 一样,我认为这不是一种正确的做法。

以下是我在MainActivity的onCreate方法中所做的事情

getActivity.onBackPressed()

我在contentLogin中替换了LoginFragment,因为我的另一个FrameLayout内容位于我的BottomNavigationView之上,我希望LoginFragment占用所有可用位置。

我也覆盖了onActivityResult

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    BottomNavigationView navigation = findViewById(R.id.navigation);
    navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);

    FragmentManager fragmentManager = getFragmentManager();

    navigation.setVisibility(View.INVISIBLE);
    fragmentManager.beginTransaction()
            .replace(R.id.contentLogin, new LoginFragment()).commit();
}

在我的LoginFragment中

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    Fragment fragment = getFragmentManager().findFragmentById(R.id.contentLogin);
    fragment.onActivityResult(requestCode, resultCode, data);
}

只有Facebook才能保持简单。

更新14.01

我使用以下代码:

MainActivity:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_login, container, false);

    callbackManager = CallbackManager.Factory.create();

    LoginManager.getInstance().registerCallback(callbackManager,
            new FacebookCallback<LoginResult>() {
                @Override
                public void onSuccess(LoginResult loginResult) {
                    final String token = loginResult.getAccessToken().getToken();
                    Toast.makeText(getActivity(), token, Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onCancel() {
                    Toast.makeText(getActivity(), "Login canceled", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onError(FacebookException exception) {
                    Toast.makeText(getActivity(), "Login error", Toast.LENGTH_SHORT).show();
                }
            });

    return view;
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    callbackManager.onActivityResult(requestCode, resultCode, data);
    super.onActivityResult(requestCode, resultCode, data);
}

LoginFragment:

@Override
public void onBackPressed() {
    Fragment fragment = fragmentManager.findFragmentById(R.id.content);

    if (fragment instanceof LoginFragment) {
        fragmentManager.beginTransaction().replace(R.id.content, new DashboardFragment())
                .commit();
        navigation.setVisibility(View.VISIBLE);
    } else {
        super.onBackPressed();
    }
}

还有一个主要问题:

  • 当我使用两个活动时,检查Facebook状态是否完美,现在发生的情况是,如果用户已经登录,应用程序将正确显示DashboardFragment,但Facebook登录活动将显示在上方(如果我点击Facebook登录按钮)登录后,应用程序将崩溃。 我正在使用此代码检查登录状态:

                    @Override
                    public void onSuccess(LoginResult loginResult) {
                        final String token = loginResult.getAccessToken().getToken();
                        final String user = loginResult.getAccessToken().getUserId();
                        loginStatus.setText("Login Success :\n" + user + "\n" + token);
                        getActivity().onBackPressed();
                    }
    

这是我得到的例外:

if (accessToken != null)
    LoginManager.getInstance().logInWithReadPermissions(this,
            Collections.singletonList("public_profile"));
else {
    navigation.setVisibility(View.GONE);
    fragmentManager.beginTransaction().replace(R.id.content, new LoginFragment())
 .commit();
}

由于我现在只实施Facebook登录,我猜Google登录会带来更多问题。

2 个答案:

答案 0 :(得分:0)

首先创建MainActivity。在activity_main.xml文件中。创建一个framelayout,或者您可以使用merge标签。

声明帧布局的id。喜欢@ + id / fragment_container到您的帧布局。

然后创建您的登录片段。将您的登录片段加载到主活动的framelayout中,如下所示

        FragmentTransaction transaction=null;
        transaction=getFragmentManager().beginTransaction();
        transaction.replace(R.id.fragment_container,new LoginFragment());
        transaction.commit();

然后在onBackPressed方法内的MainActivity.java文件中覆盖onBackPressed,编写此代码并确保在覆盖onBackPressed时删除super.onBackPressed()方法

  FragmentManager manager=getSupportFragmentManager();
    Fragment current_frag= manager.findFragmentById(R.id.fragment_container);

  if(current_frag instanceof SignInFragment)
 {

     finish();
          }

答案 1 :(得分:0)

我会说使用getActivity()。onBackPressed是完全有效的。

您可以在活动中覆盖它的实现并检查当前的片段数(在Backstack中)。当然你应该维护你的backstack(比如在移动到DashboardFragment后删除LoginFragment)。

我建议不要使用活动结果来降低复杂性。为什么不启动请求&gt;&gt; onSucess,显示下一个片段;否则显示错误。如果用户打开应用程序,应用程序应根据给定值和会话(有效/可更新?)确定是否需要显示LoginActivity。

我没有在任何项目中使用Facebook / Google登录,但我希望这个一般建议有助于为您的问题找到解决方案。

根据评论更新:(14-01-2018)

您的onBackPressed实现可能如此。

@Override
public void onBackPressed() {
   int count = getSupportFragmentManager().getBackStackEntryCount();
   if(count == 0) {
      finish();
   } else {
      super.onBackPressed();
   }
}

如果您的应用的后台堆栈为空,此部分将关闭您的应用。

关于LoginFragment:FragmentTransaction有不同的方法,如addToBackStack。通常,如果要将下一个片段添加到后端堆栈,则应调用该方法。在您的示例中,您应该避免使用LoginFragment。

LoginManager.getInstance().registerCallback(callbackManager,
            new FacebookCallback<LoginResult>() {
                @Override
                public void onSuccess(LoginResult loginResult) {
                    final String token = loginResult.getAccessToken().getToken();
                    Toast.makeText(getActivity(), token, Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onCancel() {
                    Toast.makeText(getActivity(), "Login canceled", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onError(FacebookException exception) {
                    Toast.makeText(getActivity(), "Login error", Toast.LENGTH_SHORT).show();
                }
            });

那部分看起来并不需要使用onActivityResult,你确定吗?您可以在调用onSuccess时执行新的FragmentTransaction。

您可以像这样开始下一个片段(请记住,您需要替换R.id.fragment_container):

FragmentTransaction  transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, new DashboardFragment());
transaction.addToBackStack(null);
transaction.commit();