2017-06-02 47 views
2

我正在創建一個在Android Studio上創建應用程序的項目,以便從Google電子表格中獲取數據以使用它。適用於Android的Google電子表格快速入門示例(APIv4)不適用於我

因此,我試圖通過在Google文檔上嘗試電子表格快速入門(Apiv4)來解決此問題。

因此,我在我的設備上啓動快速啓動應用程序。

但我可每次都是顯示一個錯誤,當我啓動我的設備我的應用程序,特別是當程序調用谷歌片,我無法連接到片:

The following error occurred: null 

我看看程序,找到哪個錯誤調試哪個方法是onCancelled()。但我真的不理解程序的某些部分被使用,例如該法「......」,這似乎有重要作用調試我的錯誤:

protected List<String> doInBackground(Void... params) 

我跟着完美教程,工作在Android Studio上,啓動了3次以上,但始終是相同的問題。我對Java和Android(第一個真正的應用)沒有信心。這就是爲什麼我需要你的幫助,以瞭解我做錯了什麼。

我恢復下面我按照步驟,程序我做:

  • 找回我的SHA1指紋在我的電腦上(CMD.EXE命令)
  • 創建我的谷歌電子表格
  • 激活我的Api的Android的,並把我的SHA1指紋和我將用於我的應用程序包
  • 創建我的應用程序爲教程說
  • 更改build.gradle(好的)並同步它
  • 更改AndroidManifest.xml:
  • 創建我的MainActivity.java,並用此代碼替換。
  • 建立一個apk,並通過USB將其傳輸到我的OnePlus3(我的Android手機)上。
  • 安裝此apk,並啓動它。
  • 單擊此按鈕,記錄與我的谷歌帳戶,顯示Calling Google Sheet Api,然後停止並顯示此錯誤: 出現以下錯誤:空

screenshot_error_1

screenshot_error_2

生成。 gradle這個:

apply plugin: 'com.android.application' 
android { 
    compileSdkVersion 25 
    buildToolsVersion "25.0.3" 
    defaultConfig { 
     applicationId "com.example.quickstart" 
     minSdkVersion 15 
     targetSdkVersion 25 
     versionCode 1 
     versionName "1.0" 
     testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 
     multiDexEnabled true 
    } 
    buildTypes { 
     release { 
      minifyEnabled false 
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 
     } 
    } 
    configurations.all { 
     resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9' 
    } } 

dependencies { 
    compile fileTree(dir: 'libs', include: ['*.jar']) 
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 
     exclude group: 'com.android.support', module: 'support-annotations' 
    }) 
    compile 'com.google.android.gms:play-services:8.1.0' 
    testCompile 'junit:junit:4.12' 
    compile 'pub.devrel:easypermissions:0.2.1' 
    compile('com.google.api-client:google-api-client-android:1.22.0') { 
     exclude group: 'org.apache.httpcomponents' 
    } 
    compile('com.google.apis:google-api-services-sheets:v4-rev476-1.22.0') { 
     exclude group: 'org.apache.httpcomponents' 
    } 

} 

AndroidManifest。 XML:

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.example.quickstart"> 

    <uses-permission android:name="android.permission.INTERNET" /> 
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 
    <uses-permission android:name="android.permission.GET_ACCOUNTS" /> 

    <application 
     android:allowBackup="true" 
     android:icon="@mipmap/ic_launcher" 
     android:label="Google Sheets API Android Quickstart" 
     android:theme="@style/AppTheme" > 
     <activity 
      android:name=".MainActivity" 
      android:label="Google Sheets API Android Quickstart" > 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN" /> 
       <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
     </activity> 

    </application> 
</manifest> 

MainActivity.java:

package com.example.quickstart; 

import android.Manifest; 
import android.accounts.AccountManager; 
import android.app.Activity; 
import android.app.Dialog; 
import android.app.ProgressDialog; 
import android.content.Context; 
import android.content.Intent; 
import android.content.SharedPreferences; 
import android.net.ConnectivityManager; 
import android.net.NetworkInfo; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.support.annotation.NonNull; 
import android.text.TextUtils; 
import android.text.method.ScrollingMovementMethod; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.Button; 
import android.widget.LinearLayout; 
import android.widget.TextView; 

import com.google.android.gms.common.ConnectionResult; 
import com.google.android.gms.common.GoogleApiAvailability; 
import com.google.api.client.extensions.android.http.AndroidHttp; 
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential; 
import com.google.api.client.googleapis.extensions.android.gms.auth.GooglePlayServicesAvailabilityIOException; 
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException; 
import com.google.api.client.http.HttpTransport; 
import com.google.api.client.json.JsonFactory; 
import com.google.api.client.json.jackson2.JacksonFactory; 
import com.google.api.client.util.ExponentialBackOff; 
import com.google.api.services.sheets.v4.SheetsScopes; 
import com.google.api.services.sheets.v4.model.ValueRange; 

import java.io.IOException; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 

import pub.devrel.easypermissions.AfterPermissionGranted; 
import pub.devrel.easypermissions.EasyPermissions; 

public class MainActivity extends Activity 
     implements EasyPermissions.PermissionCallbacks { 
    GoogleAccountCredential mCredential; 
    private TextView mOutputText; 
    private Button mCallApiButton; 
    ProgressDialog mProgress; 

    static final int REQUEST_ACCOUNT_PICKER = 1000; 
    static final int REQUEST_AUTHORIZATION = 1001; 
    static final int REQUEST_GOOGLE_PLAY_SERVICES = 1002; 
    static final int REQUEST_PERMISSION_GET_ACCOUNTS = 1003; 

    private static final String BUTTON_TEXT = "Call Google Sheets API"; 
    private static final String PREF_ACCOUNT_NAME = "accountName"; 
    private static final String[] SCOPES = { SheetsScopes.SPREADSHEETS_READONLY }; 

    /** 
    * Create the main activity. 
    * @param savedInstanceState previously saved instance data. 
    */ 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     LinearLayout activityLayout = new LinearLayout(this); 
     LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
       LinearLayout.LayoutParams.MATCH_PARENT, 
       LinearLayout.LayoutParams.MATCH_PARENT); 
     activityLayout.setLayoutParams(lp); 
     activityLayout.setOrientation(LinearLayout.VERTICAL); 
     activityLayout.setPadding(16, 16, 16, 16); 

     ViewGroup.LayoutParams tlp = new ViewGroup.LayoutParams(
       ViewGroup.LayoutParams.WRAP_CONTENT, 
       ViewGroup.LayoutParams.WRAP_CONTENT); 

     mCallApiButton = new Button(this); 
     mCallApiButton.setText(BUTTON_TEXT); 
     mCallApiButton.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       mCallApiButton.setEnabled(false); 
       mOutputText.setText(""); 
       getResultsFromApi(); 
       mCallApiButton.setEnabled(true); 
      } 
     }); 
     activityLayout.addView(mCallApiButton); 

     mOutputText = new TextView(this); 
     mOutputText.setLayoutParams(tlp); 
     mOutputText.setPadding(16, 16, 16, 16); 
     mOutputText.setVerticalScrollBarEnabled(true); 
     mOutputText.setMovementMethod(new ScrollingMovementMethod()); 
     mOutputText.setText(
       "Click the \'" + BUTTON_TEXT +"\' button to test the API."); 
     activityLayout.addView(mOutputText); 

     mProgress = new ProgressDialog(this); 
     mProgress.setMessage("Calling Google Sheets API ..."); 

     setContentView(activityLayout); 

     // Initialize credentials and service object. 
     mCredential = GoogleAccountCredential.usingOAuth2(
       getApplicationContext(), Arrays.asList(SCOPES)) 
       .setBackOff(new ExponentialBackOff()); 
    } 



    /** 
    * Attempt to call the API, after verifying that all the preconditions are 
    * satisfied. The preconditions are: Google Play Services installed, an 
    * account was selected and the device currently has online access. If any 
    * of the preconditions are not satisfied, the app will prompt the user as 
    * appropriate. 
    */ 
    private void getResultsFromApi() { 
     if (! isGooglePlayServicesAvailable()) { 
      acquireGooglePlayServices(); 
     } else if (mCredential.getSelectedAccountName() == null) { 
      chooseAccount(); 
     } else if (! isDeviceOnline()) { 
      mOutputText.setText("No network connection available."); 
     } else { 
      new MakeRequestTask(mCredential).execute(); 
     } 
    } 

    /** 
    * Attempts to set the account used with the API credentials. If an account 
    * name was previously saved it will use that one; otherwise an account 
    * picker dialog will be shown to the user. Note that the setting the 
    * account to use with the credentials object requires the app to have the 
    * GET_ACCOUNTS permission, which is requested here if it is not already 
    * present. The AfterPermissionGranted annotation indicates that this 
    * function will be rerun automatically whenever the GET_ACCOUNTS permission 
    * is granted. 
    */ 
    @AfterPermissionGranted(REQUEST_PERMISSION_GET_ACCOUNTS) 
    private void chooseAccount() { 
     if (EasyPermissions.hasPermissions(
       this, Manifest.permission.GET_ACCOUNTS)) { 
      String accountName = getPreferences(Context.MODE_PRIVATE) 
        .getString(PREF_ACCOUNT_NAME, null); 
      if (accountName != null) { 
       mCredential.setSelectedAccountName(accountName); 
       getResultsFromApi(); 
      } else { 
       // Start a dialog from which the user can choose an account 
       startActivityForResult(
         mCredential.newChooseAccountIntent(), 
         REQUEST_ACCOUNT_PICKER); 
      } 
     } else { 
      // Request the GET_ACCOUNTS permission via a user dialog 
      EasyPermissions.requestPermissions(
        this, 
        "This app needs to access your Google account (via Contacts).", 
        REQUEST_PERMISSION_GET_ACCOUNTS, 
        Manifest.permission.GET_ACCOUNTS); 
     } 
    } 

    /** 
    * Called when an activity launched here (specifically, AccountPicker 
    * and authorization) exits, giving you the requestCode you started it with, 
    * the resultCode it returned, and any additional data from it. 
    * @param requestCode code indicating which activity result is incoming. 
    * @param resultCode code indicating the result of the incoming 
    *  activity result. 
    * @param data Intent (containing result data) returned by incoming 
    *  activity result. 
    */ 
    @Override 
    protected void onActivityResult(
      int requestCode, int resultCode, Intent data) { 
     super.onActivityResult(requestCode, resultCode, data); 
     switch(requestCode) { 
      case REQUEST_GOOGLE_PLAY_SERVICES: 
       if (resultCode != RESULT_OK) { 
        mOutputText.setText(
          "This app requires Google Play Services. Please install " + 
            "Google Play Services on your device and relaunch this app."); 
       } else { 
        getResultsFromApi(); 
       } 
       break; 
      case REQUEST_ACCOUNT_PICKER: 
       if (resultCode == RESULT_OK && data != null && 
         data.getExtras() != null) { 
        String accountName = 
          data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME); 
        if (accountName != null) { 
         SharedPreferences settings = 
           getPreferences(Context.MODE_PRIVATE); 
         SharedPreferences.Editor editor = settings.edit(); 
         editor.putString(PREF_ACCOUNT_NAME, accountName); 
         editor.apply(); 
         mCredential.setSelectedAccountName(accountName); 
         getResultsFromApi(); 
        } 
       } 
       break; 
      case REQUEST_AUTHORIZATION: 
       if (resultCode == RESULT_OK) { 
        getResultsFromApi(); 
       } 
       break; 
     } 
    } 

    /** 
    * Respond to requests for permissions at runtime for API 23 and above. 
    * @param requestCode The request code passed in 
    *  requestPermissions(android.app.Activity, String, int, String[]) 
    * @param permissions The requested permissions. Never null. 
    * @param grantResults The grant results for the corresponding permissions 
    *  which is either PERMISSION_GRANTED or PERMISSION_DENIED. Never null. 
    */ 
    @Override 
    public void onRequestPermissionsResult(int requestCode, 
              @NonNull String[] permissions, 
              @NonNull int[] grantResults) { 
     super.onRequestPermissionsResult(requestCode, permissions, grantResults); 
     EasyPermissions.onRequestPermissionsResult(
       requestCode, permissions, grantResults, this); 
    } 

    /** 
    * Callback for when a permission is granted using the EasyPermissions 
    * library. 
    * @param requestCode The request code associated with the requested 
    *   permission 
    * @param list The requested permission list. Never null. 
    */ 
    @Override 
    public void onPermissionsGranted(int requestCode, List<String> list) { 
     // Do nothing. 
    } 

    /** 
    * Callback for when a permission is denied using the EasyPermissions 
    * library. 
    * @param requestCode The request code associated with the requested 
    *   permission 
    * @param list The requested permission list. Never null. 
    */ 
    @Override 
    public void onPermissionsDenied(int requestCode, List<String> list) { 
     // Do nothing. 
    } 

    /** 
    * Checks whether the device currently has a network connection. 
    * @return true if the device has a network connection, false otherwise. 
    */ 
    private boolean isDeviceOnline() { 
     ConnectivityManager connMgr = 
       (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 
     NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); 
     return (networkInfo != null && networkInfo.isConnected()); 
    } 

    /** 
    * Check that Google Play services APK is installed and up to date. 
    * @return true if Google Play Services is available and up to 
    *  date on this device; false otherwise. 
    */ 
    private boolean isGooglePlayServicesAvailable() { 
     GoogleApiAvailability apiAvailability = 
       GoogleApiAvailability.getInstance(); 
     final int connectionStatusCode = 
       apiAvailability.isGooglePlayServicesAvailable(this); 
     return connectionStatusCode == ConnectionResult.SUCCESS; 
    } 

    /** 
    * Attempt to resolve a missing, out-of-date, invalid or disabled Google 
    * Play Services installation via a user dialog, if possible. 
    */ 
    private void acquireGooglePlayServices() { 
     GoogleApiAvailability apiAvailability = 
       GoogleApiAvailability.getInstance(); 
     final int connectionStatusCode = 
       apiAvailability.isGooglePlayServicesAvailable(this); 
     if (apiAvailability.isUserResolvableError(connectionStatusCode)) { 
      showGooglePlayServicesAvailabilityErrorDialog(connectionStatusCode); 
     } 
    } 


    /** 
    * Display an error dialog showing that Google Play Services is missing 
    * or out of date. 
    * @param connectionStatusCode code describing the presence (or lack of) 
    *  Google Play Services on this device. 
    */ 
    void showGooglePlayServicesAvailabilityErrorDialog(
      final int connectionStatusCode) { 
     GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance(); 
     Dialog dialog = apiAvailability.getErrorDialog(
       MainActivity.this, 
       connectionStatusCode, 
       REQUEST_GOOGLE_PLAY_SERVICES); 
     dialog.show(); 
    } 

    /** 
    * An asynchronous task that handles the Google Sheets API call. 
    * Placing the API calls in their own task ensures the UI stays responsive. 
    */ 
    private class MakeRequestTask extends AsyncTask<Void, Void, List<String>> { 
     private com.google.api.services.sheets.v4.Sheets mService = null; 
     private Exception mLastError = null; 

     MakeRequestTask(GoogleAccountCredential credential) { 
      HttpTransport transport = AndroidHttp.newCompatibleTransport(); 
      JsonFactory jsonFactory = JacksonFactory.getDefaultInstance(); 
      mService = new com.google.api.services.sheets.v4.Sheets.Builder(
        transport, jsonFactory, credential) 
        .setApplicationName("Google Sheets API Android Quickstart") 
        .build(); 
     } 

     /** 
     * Background task to call Google Sheets API. 
     * @param params no parameters needed for this task. 
     */ 
     @Override 
     protected List<String> doInBackground(Void... params) { 
      try { 
       return getDataFromApi(); 
      } catch (Exception e) { 
       mLastError = e; 
       cancel(true); 
       return null; 
      } 
     } 

     /** 
     * Fetch a list of names and majors of students in a sample spreadsheet: 
     * https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit 
     * @return List of names and majors 
     * @throws IOException 
     */ 
     private List<String> getDataFromApi() throws IOException { 
      String spreadsheetId = "629235369054-3cc387mt7mlnacv1kiq8d30auhqrh278.apps.googleusercontent.com"; 
      String range = "GroupMar!A2:C"; 
      List<String> results = new ArrayList<String>(); 
      ValueRange response = this.mService.spreadsheets().values() 
        .get(spreadsheetId, range) 
        .execute(); 
      List<List<Object>> values = response.getValues(); 
      if (values != null) { 
       results.add("Name, Major"); 
       for (List row : values) { 
        results.add(row.get(0) + ", " + row.get(1) + ", " + row.get(2)); 
       } 
      } 
      return results; 
     } 



     @Override 
     protected void onPreExecute() { 
      mOutputText.setText(""); 
      mProgress.show(); 
     } 

     @Override 
     protected void onPostExecute(List<String> output) { 
      mProgress.hide(); 
      if (output == null || output.size() == 0) { 
       mOutputText.setText("No results returned."); 
      } else { 
       output.add(0, "Data retrieved using the Google Sheets API:"); 
       mOutputText.setText(TextUtils.join("\n", output)); 
      } 
     } 

     @Override 
     protected void onCancelled() { 
      mProgress.hide(); 
      if (mLastError != null) { 
       if (mLastError instanceof GooglePlayServicesAvailabilityIOException) { 
        showGooglePlayServicesAvailabilityErrorDialog(
          ((GooglePlayServicesAvailabilityIOException) mLastError) 
            .getConnectionStatusCode()); 
       } else if (mLastError instanceof UserRecoverableAuthIOException) { 
        startActivityForResult(
          ((UserRecoverableAuthIOException) mLastError).getIntent(), 
          MainActivity.REQUEST_AUTHORIZATION); 
       } else { 
        mOutputText.setText("The following error occurred:\n" 
          + mLastError.getMessage()); 
       } 
      } else { 
       mOutputText.setText("Request cancelled."); 
      } 
     } 
    } 
} 

誰能幫我明白了嗎?

+0

張貼提示:使用imgur.com而不是您自己的圖片主機,理想情況下使用上傳按鈕,因此它使用正確的域名。這將有助於將圖像保存到未來。接下來,從評論中刪除你的pastebins - 如果它們是必需的,就把它們放在問題中。最後,將你的pastebins轉換爲代碼塊 - 如果你願意的話,保留鏈接,但我們也希望在問題本身中看到這些材料。 – halfer

+0

這些指導原則有助於減少遠程圖像/代碼網站中由404和刪除引起的未來管理數量。 – halfer

+0

@halfer。我注意到你說的話。我用imgur取代了。對於代碼,我無法將我的pastebin轉換爲我的代碼塊,我之前嘗試過,但它似乎不起作用。我會再試一次,看看你是否想要。 –

回答

2

我有同樣的問題。如果應用程序無法登錄,即無效的憑據,則會發生此錯誤。所以,這個問題可能是

  • 憑據沒有創建(但你提到你做),這樣..
  • 證書的應用和開發者控制檯例如之間的不匹配錯誤的SHA1密鑰

我遇到的問題是通過keytool獲得的SHA1密鑰與應用中使用的實際密鑰不匹配。所以首先得到應用程序中實際使用的SHA1密鑰。檢查this發佈,瞭解如何獲取應用程序中使用的SHA1密鑰。如果它與keytool密鑰不同,那麼在開發人員控制檯中更新它可以解決您的問題。

相關問題