Google SignInButton上的致命异常

时间:2017-06-23 10:37:53

标签: java android

遇到来自

的null对象的致命错误
signInButton = (SignInButton) findViewById(R.id.sign_in_button);

虽然我相信在setSize

中调用onCreate之前已经实例化了

我完全没有想法,任何人都可以指出是什么导致了这个错误?

package artlvlup.how.to.draw;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.NavigationView;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewPager;
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 com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.InterstitialAd;
import artlvlup.how.to.draw.drawer.MenuItemCallback;
import artlvlup.how.to.draw.drawer.NavItem;
import artlvlup.how.to.draw.drawer.SimpleMenu;
import artlvlup.how.to.draw.drawer.TabAdapter;
import artlvlup.how.to.draw.inherit.BackPressFragment;
import artlvlup.how.to.draw.inherit.CollapseControllingFragment;
import artlvlup.how.to.draw.inherit.PermissionsFragment;
import artlvlup.how.to.draw.providers.CustomIntent;
import artlvlup.how.to.draw.providers.fav.ui.FavFragment;
import artlvlup.how.to.draw.util.Log;
import artlvlup.how.to.draw.util.Helper;
import artlvlup.how.to.draw.util.layout.DisableableViewPager;

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.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;

import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

/**
 * This file is part of the Universal template
 * For license information, please check the LICENSE
 * file in the root of this project
 *
 * @author Sherdle
 * Copyright 2016
 */
public class MainActivity extends AppCompatActivity implements
        MenuItemCallback, ConfigParser.CallBack,
        OnConnectionFailedListener, View.OnClickListener {

    private Toolbar mToolbar;
    private TabLayout tabLayout;
    private DisableableViewPager viewPager;
    private NavigationView navigationView;
    private TabAdapter adapter;
    private static SimpleMenu menu;

    private DrawerLayout drawer;
    private ActionBarDrawerToggle toggle;

    private SignInButton signInButton;
    private TextView sign_in_text_button;
    private GoogleSignInOptions gso;
    private GoogleApiClient mGoogleApiClient;

    //Keep track of the interstitials we show
    private int interstitialCount = -1;

    //Data to pass to a fragment
    public static String FRAGMENT_DATA = "transaction_data";
    public static String FRAGMENT_CLASS = "transation_target";

    public static boolean TABLET_LAYOUT = true;

    //Permissions Queu
    List<NavItem> queueItem;
    MenuItem queueMenuItem;


    @Override
    public void configLoaded(boolean facedException) {
        if (facedException || menu.getFirstMenuItem() == null){
            if (Helper.isOnlineShowDialog(MainActivity.this))
                Toast.makeText(this, artlvlup.how.to.draw.R.string.invalid_configuration, Toast.LENGTH_LONG).show();
        } else {
            //Load the first item (we assume the first item doesn't require purchase)
            menuItemClicked(menu.getFirstMenuItem().getValue(), menu.getFirstMenuItem().getKey(), false);
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Google Sign-in
        // Configure sign-in to request the user's ID, email address, and basic
        // profile. ID and basic profile are included in DEFAULT_SIGN_IN.
        GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestEmail()
                .build();

        //Initializing signinbutton
        signInButton = (SignInButton) findViewById(R.id.sign_in_button);
        signInButton.setSize(SignInButton.SIZE_WIDE);
        signInButton.setOnClickListener(this);

        // Build a GoogleApiClient with access to the Google Sign-In API and the
        // options specified by gso.
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
                .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                .build();

        //Load the appropriate layout
        if (useTabletMenu()){
            setContentView(artlvlup.how.to.draw.R.layout.activity_main_tablet);
            Helper.setStatusBarColor(MainActivity.this,
                    ContextCompat.getColor(this, artlvlup.how.to.draw.R.color.myPrimaryDarkColor));
        } else {
            setContentView(artlvlup.how.to.draw.R.layout.activity_main);
        }

        mToolbar = (Toolbar) findViewById(artlvlup.how.to.draw.R.id.toolbar);
        setSupportActionBar(mToolbar);

        if (!useTabletMenu())
            getSupportActionBar().setDisplayShowHomeEnabled(true);
        else {
            getSupportActionBar().setDisplayShowHomeEnabled(false);
        }

        //Drawer
        if (!useTabletMenu()) {
            drawer = (DrawerLayout) findViewById(artlvlup.how.to.draw.R.id.drawer);
            toggle = new ActionBarDrawerToggle(
                    this, drawer, mToolbar, artlvlup.how.to.draw.R.string.drawer_open, artlvlup.how.to.draw.R.string.drawer_close);
            drawer.setDrawerListener(toggle);
            toggle.syncState();
        }

        //Layouts
        tabLayout = (TabLayout) findViewById(artlvlup.how.to.draw.R.id.tabs);
        viewPager = (DisableableViewPager) findViewById(artlvlup.how.to.draw.R.id.viewpager);

        //Check if we should open a fragment based on the arguments we have
        if (getIntent().getExtras() != null && getIntent().getExtras().containsKey(FRAGMENT_CLASS)) {
            try {
                Class<? extends Fragment> fragmentClass = (Class<? extends Fragment>) getIntent().getExtras().getSerializable(FRAGMENT_CLASS);
                if (fragmentClass != null) {
                    String[] extra = getIntent().getExtras().getStringArray(FRAGMENT_DATA);

                    HolderActivity.startActivity(this, fragmentClass, extra);
                    finish();
                    //Optionally, we can also point intents to holderactivity directly instead of MainAc.
                }
            } catch (Exception e) {
                //If we come across any errors, just continue and open the default fragment
                Log.printStackTrace(e);
            }
        }

        //Menu items
        navigationView = (NavigationView) findViewById(artlvlup.how.to.draw.R.id.nav_view);
        menu = new SimpleMenu(navigationView.getMenu(), this);
        if (Config.USE_HARDCODED_CONFIG) {
            Config.configureMenu(menu, this);
        } else if (!Config.CONFIG_URL.isEmpty() && Config.CONFIG_URL.contains("http"))
            new ConfigParser(Config.CONFIG_URL, menu, this, this).execute();
        else
            new ConfigParser("config.json", menu, this, this).execute();
        tabLayout.setupWithViewPager(viewPager);

        if (!useTabletMenu()) {
            drawer.setStatusBarBackgroundColor(
                ContextCompat.getColor(this, artlvlup.how.to.draw.R.color.myPrimaryDarkColor));
        }

        applyDrawerLocks();

        Helper.admobLoader(this, getResources(), findViewById(artlvlup.how.to.draw.R.id.adView));
        Helper.updateAndroidSecurityProvider(this);

        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            public void onPageScrollStateChanged(int state) {}
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}

            public void onPageSelected(int position) {
                onTabBecomesActive(position);
            }
        });
    }

    @SuppressLint("NewApi")
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case 1:
                boolean foundfalse = false;
                for (int i = 0; i < grantResults.length; i++) {
                    if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                        foundfalse = true;
                    }
                }
                if (!foundfalse){
                    //Retry to open the menu item
                    //(we can assume the item is 'purchased' otherwise a permission check would have not occured)
                    menuItemClicked(queueItem, queueMenuItem, false);
                } else {
                    // Permission Denied
                    Toast.makeText(MainActivity.this, getResources().getString(artlvlup.how.to.draw.R.string.permissions_required), Toast.LENGTH_SHORT)
                            .show();
                }
                break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    @Override
    public void menuItemClicked(List<NavItem> actions, MenuItem item, boolean requiresPurchase) {
        // Checking if the user would prefer to show the menu on start
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
        boolean openOnStart = prefs.getBoolean("menuOpenOnStart", false);
        if (drawer != null)
            if (openOnStart && !useTabletMenu() && adapter == null) {
                drawer.openDrawer(GravityCompat.START);
            } else {
                //Close the drawer
                drawer.closeDrawer(GravityCompat.START);
            }


        //Check if the user is allowed to open item
        if (requiresPurchase && !isPurchased()) return; //isPurchased will handle this.
        if (!checkPermissionsHandleIfNeeded(actions, item)) return; //checkPermissions will handle.

        if (isCustomIntent(actions)) return;

        //Uncheck all other items, check the current item
        if (item != null) {
            for (MenuItem menuItem : menu.getMenuItems())
                menuItem.setChecked(false);
            item.setChecked(true);
        }

        //Load the new tabs
        adapter = new TabAdapter(getSupportFragmentManager(), actions, this);
        viewPager.setAdapter(adapter);

        //Show or hide the tab bar depending on if we need it
        if (actions.size() == 1) {
            tabLayout.setVisibility(View.GONE);
            viewPager.setPagingEnabled(false);
        } else {
            tabLayout.setVisibility(View.VISIBLE);
            viewPager.setPagingEnabled(true);
        }

        //Show in interstitial
        showInterstitial(false);

        onTabBecomesActive(0);
    }

    private void onTabBecomesActive(int position){
        Fragment fragment = adapter.getItem(position);
        //If fragment does not support collapse, or if OS does not support collaps, disable collapsing toolbar
        if ((fragment instanceof CollapseControllingFragment
                && !((CollapseControllingFragment) fragment).supportsCollapse())
                ||
                (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT))
            lockAppBar();
        else
            unlockAppBar();

        if (position != 0)
            showInterstitial(true);
    }

    /**
     * Show an interstitial ad
     * @param fromPager if the showing is triggered from a swipe in the viewpager
     */
    private void showInterstitial(boolean fromPager){
        //if (fromPager) return;
        if (getResources().getString(artlvlup.how.to.draw.R.string.admob_interstitial_id).length() == 0) return;
        if (SettingsFragment.getIsPurchased(this)) return;

        if (interstitialCount == (Config.INTERSTITIAL_INTERVAL - 1)) {
            final InterstitialAd mInterstitialAd = new InterstitialAd(this);
            mInterstitialAd.setAdUnitId(getResources().getString(artlvlup.how.to.draw.R.string.admob_interstitial_id));
            AdRequest adRequestInter = new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR).build();
            mInterstitialAd.setAdListener(new AdListener() {
                @Override
                public void onAdLoaded() {
                    mInterstitialAd.show();
                }
            });
            mInterstitialAd.loadAd(adRequestInter);

            interstitialCount = 0;
        } else {
            interstitialCount++;
        }

    }

    /**
     * Checks if the item is/contains a custom intent, and if that the case it will handle it.
     * @param items List of NavigationItems
     * @return True if the item is a custom intent, in that case
     */
    private boolean isCustomIntent(List<NavItem> items){
        NavItem customIntentItem = null;
        for (NavItem item : items){
            if (CustomIntent.class.isAssignableFrom(item.getFragment())){
                customIntentItem = item;
            }
        }

        if (customIntentItem == null) return false;
        if (items.size() > 1) Log.e("INFO", "Custom Intent Item must be only child of menu item! Ignorning all other tabs");

        CustomIntent.performIntent(MainActivity.this, customIntentItem.getData());
        return true;
    }

    /**
     * If the item can be opened because it either has been purchased or does not require a purchase to show.
     * @return true if the app is purchased. False if the app hasn't been purchased, or if iaps are disabled
     */
    private boolean isPurchased(){
        String license = getResources().getString(artlvlup.how.to.draw.R.string.google_play_license);
        // if item does not require purchase, or app has purchased, or license is null/empty (app has no in app purchases)
        if (!SettingsFragment.getIsPurchased(this) && !license.equals("")) {
            String[] extra = new String[] {SettingsFragment.SHOW_DIALOG};
            HolderActivity.startActivity(this, SettingsFragment.class, extra);

            return false;
        }

        return true;
    }

    /**
     * Checks if the item can be opened because it has sufficient permissions.
     * @param tabs The tabs to check
     * @return true if the item is safe to open
     */
    private boolean checkPermissionsHandleIfNeeded(List<NavItem> tabs, MenuItem item){
        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) return true;

        List<String> allPermissions = new ArrayList<>();
        for (NavItem tab : tabs){
            if (PermissionsFragment.class.isAssignableFrom(tab.getFragment())) {
                try {
                    allPermissions.addAll(Arrays.asList(((PermissionsFragment) tab.getFragment().newInstance()).requiredPermissions()));
                } catch (Exception e) {
                    //Don't really care
                }
            }
        }

        if (allPermissions.size() > 1) {
            boolean allGranted = true;
            for (String permission : allPermissions) {
                if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED)
                    allGranted = false;
            }

            if (!allGranted) {
                //TODO An explaination before asking
                requestPermissions(allPermissions.toArray(new String[0]), 1);
                queueItem = tabs;
                queueMenuItem = item;
                return false;
            }

            return true;
        }

        return true;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(artlvlup.how.to.draw.R.menu.settings_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        switch (item.getItemId()) {
            case artlvlup.how.to.draw.R.id.settings:
                HolderActivity.startActivity(this, SettingsFragment.class, null);
                return true;
            case artlvlup.how.to.draw.R.id.favorites:
                HolderActivity.startActivity(this, FavFragment.class, null);
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onBackPressed() {
        Fragment activeFragment = null;
        if (adapter != null)
            activeFragment = adapter.getCurrentFragment();

        if (drawer != null && drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else if (activeFragment instanceof BackPressFragment){
            boolean handled = ((BackPressFragment) activeFragment).handleBackPress();
            if (!handled){
                super.onBackPressed();
            }
        } else {
            super.onBackPressed();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        List<Fragment> fragments = getSupportFragmentManager().getFragments();
        if (fragments != null)
            for (Fragment frag : fragments)
                if (frag != null)
                    frag.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        getWindow().getDecorView().findViewById(android.R.id.content).invalidate();
    }

    //Check if we should adjust our layouts for tablets
    public boolean useTabletMenu(){
        return (getResources().getBoolean(artlvlup.how.to.draw.R.bool.isWideTablet) && TABLET_LAYOUT);
    }

    //Apply the appropiate locks to the drawer
    public void applyDrawerLocks(){
        if (drawer == null) {
            if (Config.HIDE_DRAWER)
                navigationView.setVisibility(View.GONE);
            return;
        }

        if (Config.HIDE_DRAWER){
            toggle.setDrawerIndicatorEnabled(false);
            drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
        } else {
            drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
        }
    }

    public void lockAppBar() {
        AppBarLayout.LayoutParams params =
                (AppBarLayout.LayoutParams) mToolbar.getLayoutParams();
        params.setScrollFlags(0);
    }

    public void unlockAppBar() {
        AppBarLayout.LayoutParams params =
                (AppBarLayout.LayoutParams) mToolbar.getLayoutParams();
        params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL
                | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS);
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        // An unresolvable error has occurred and Google APIs (including Sign-In) will not
        // be available.
    }

    private void updateUI(boolean signedIn) {
        if (signedIn) {
            findViewById(R.id.sign_in_button).setVisibility(View.GONE);
            findViewById(R.id.sign_out_and_disconnect).setVisibility(View.VISIBLE);
        } else {
            findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
            findViewById(R.id.sign_out_and_disconnect).setVisibility(View.GONE);
        }
    }

    private void signIn() {
        Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
        startActivityForResult(signInIntent, 100);
    }

    private void signOut() {
        Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
            new ResultCallback<Status>() {
                @Override
                public void onResult(Status status) {
                    // [START_EXCLUDE]
                    updateUI(false);
                    // [END_EXCLUDE]
                }
            });
    }

    private void revokeAccess() {
        Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback(
            new ResultCallback<Status>() {
                @Override
                public void onResult(Status status) {
                    // [START_EXCLUDE]
                    updateUI(false);
                    // [END_EXCLUDE]
                }
            });
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.sign_in_button:
                signIn();
                break;
            case R.id.sign_out_button:
                signOut();
                break;
            case R.id.disconnect_button:
                revokeAccess();
                break;
        }
    }
}

错误如下所示:

06-23 18:24:14.987 24144-24144/artlvlup.how.to.draw E/AndroidRuntime: FATAL EXCEPTION: main
                                                                      Process: artlvlup.how.to.draw, PID: 24144
                                                                      java.lang.RuntimeException: Unable to start activity ComponentInfo{artlvlup.how.to.draw/artlvlup.how.to.draw.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.google.android.gms.common.SignInButton.setSize(int)' on a null object reference
                                                                          at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2356)
                                                                          at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2418)
                                                                          at android.app.ActivityThread.access$900(ActivityThread.java:154)
                                                                          at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1321)
                                                                          at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                          at android.os.Looper.loop(Looper.java:135)
                                                                          at android.app.ActivityThread.main(ActivityThread.java:5289)
                                                                          at java.lang.reflect.Method.invoke(Native Method)
                                                                          at java.lang.reflect.Method.invoke(Method.java:372)
                                                                          at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
                                                                          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)
                                                                          at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:102)
                                                                       Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.google.android.gms.common.SignInButton.setSize(int)' on a null object reference
                                                                          at artlvlup.how.to.draw.MainActivity.onCreate(MainActivity.java:126)
                                                                          at android.app.Activity.performCreate(Activity.java:5990)
                                                                          at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
                                                                          at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2309)
                                                                          at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2418) 
                                                                          at android.app.ActivityThread.access$900(ActivityThread.java:154) 
                                                                          at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1321) 
                                                                          at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                          at android.os.Looper.loop(Looper.java:135) 
                                                                          at android.app.ActivityThread.main(ActivityThread.java:5289) 
                                                                          at java.lang.reflect.Method.invoke(Native Method) 
                                                                          at java.lang.reflect.Method.invoke(Method.java:372) 
                                                                          at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904) 
                                                                          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699) 
                                                                          at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:102) 

2 个答案:

答案 0 :(得分:4)

在访问布局中的项目之前,您需要调用setContentView方法。

应该是第一个,

//Load the appropriate layout
if (useTabletMenu()){
    setContentView(artlvlup.how.to.draw.R.layout.activity_main_tablet);
    Helper.setStatusBarColor(MainActivity.this,
    ContextCompat.getColor(this, artlvlup.how.to.draw.R.color.myPrimaryDarkColor));
} else {
    setContentView(artlvlup.how.to.draw.R.layout.activity_main);
}

然后,

//Initializing signinbutton
signInButton = (SignInButton) findViewById(R.id.sign_in_button);
signInButton.setSize(SignInButton.SIZE_WIDE);
signInButton.setOnClickListener(this);

答案 1 :(得分:2)

在行onCreate之后的super.onCreate...中,您必须致电loc并初步设置R.id.sign_in_button的布局。