android - Android Things 和 Google 日历 API
问题描述
我正在尝试在 Android Things 平台上获取用户的日历事件,并发现以下教程显示了一种方法: https ://medium.com/@F8Full/getaroom-android-things-google-calendar-api -2ab72a5b957f
我从手机上的用户那里获得了授权码,并将其发送到 Android Things 设备。然后我必须在 Android Things 上完成 OAuth 流程,但这就是我遇到问题的地方。这是我得到的错误:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.subs.projecthera/com.subs.projecthera.MainActivity}: android.os.NetworkOnMainThreadException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2778)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1450)
at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:102)
at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:90)
at java.net.InetAddress.getAllByName(InetAddress.java:787)
at com.android.okhttp.Dns$1.lookup(Dns.java:39)
at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:175)
at com.android.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:141)
at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:83)
at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:174)
at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:126)
at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:95)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:281)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:224)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:461)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:127)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:258)
at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:218)
at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(Unknown Source:0)
at com.google.api.client.http.javanet.NetHttpRequest.execute(NetHttpRequest.java:77)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:981)
at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:283)
at com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest.execute(GoogleAuthorizationCodeTokenRequest.java:158)
at com.subs.projecthera.Core.AuthHelper.<init>(AuthHelper.java:40)
at com.subs.projecthera.MainActivity.onCreate(MainActivity.java:48)
at android.app.Activity.performCreate(Activity.java:7010)
at android.app.Activity.performCreate(Activity.java:7001)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
我有一个 AuthHelper 类:
Activity activity;
Context context;
public AuthHelper(String authCode) {
// Exchange authCode for token
if (authCode != null) {
String CLIENT_SECRET_DATA = "{\"web\":{\"client_id\":\"529614308595-q103hbbbktc53tfrudofocg76a390bo1.apps.googleusercontent.com\",\"project_id\":\"smart-mirror-88c35\",\"auth_uri\":\"https://accounts.google.com/o/oauth2/auth\",\"token_uri\":\"https://oauth2.googleapis.com/token\",\"auth_provider_x509_cert_url\":\"https://www.googleapis.com/oauth2/v1/certs\"}}";
try {
GoogleClientSecrets GCS = GoogleClientSecrets.load(new JacksonFactory(), new StringReader(CLIENT_SECRET_DATA));
GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(
new NetHttpTransport(),
new JacksonFactory(),
"https://www.googleapis.com/oauth2/v4/token",
GCS.getDetails().getClientId(),
GCS.getDetails().getClientSecret(),
authCode,
"" )
.execute();
buildCredentialsAndUpdateActivityModel(tokenResponse);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static GoogleCredential mGoogleCredential;
private void buildCredentialsAndUpdateActivityModel(GoogleTokenResponse tokenResponse) {
String CLIENT_SECRET_DATA = "{\"web\":{\"client_id\":\"529614308595-q103hbbbktc53tfrudofocg76a390bo1.apps.googleusercontent.com\",\"project_id\":\"smart-mirror-88c35\",\"auth_uri\":\"https://accounts.google.com/o/oauth2/auth\",\"token_uri\":\"https://oauth2.googleapis.com/token\",\"auth_provider_x509_cert_url\":\"https://www.googleapis.com/oauth2/v1/certs\"}}";
try {
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(new JacksonFactory(), new StringReader(CLIENT_SECRET_DATA));
mGoogleCredential = new GoogleCredential.Builder()
.setJsonFactory(new JacksonFactory())
.setTransport(new NetHttpTransport())
.setClientSecrets(clientSecrets).build().setFromTokenResponse(tokenResponse);
} catch (IOException e) {
e.printStackTrace();
}
}
private boolean storeOAuth2TokenData(String storageID, GoogleCredential toStore) {
boolean wasStored = false;
try {
File oauth2StorageFolder = new File(context.getFilesDir(), "oauth2StorageFolder");
oauth2StorageFolder.mkdirs();
FileDataStoreFactory fileDataStoreFactory = new FileDataStoreFactory(oauth2StorageFolder);
DataStore storedCredentialDataStore = fileDataStoreFactory.getDataStore(storageID);//<new StoredCredential()>(storageID)
//val oauth2Credential = Credential(BearerToken.authorizationHeaderAccessMethod()).setFromTokenResponse(tokenResponse)
StoredCredential storedOAuth2Credential = new StoredCredential(toStore);
storedCredentialDataStore.set(storageID, storedOAuth2Credential);
wasStored = true;
} catch (Exception exception) {
//logInfo("Exception storing OAuth2TokenData :" + exception.localizedMessage)
}
return wasStored;
}
private TokenResponse getOAuth2TokenDataFromStore(String storageID) {
TokenResponse tokenResponse = null;
try {
File oauth2StorageFolder = new File(context.getFilesDir(), "oauth2StorageFolder");
oauth2StorageFolder.mkdirs();
FileDataStoreFactory fileDataStoreFactory = new FileDataStoreFactory(oauth2StorageFolder);
DataStore storedCredentialDataStore = fileDataStoreFactory.getDataStore(storageID);//<StoredCredential>(storageID);
StoredCredential storedCredential = (StoredCredential) storedCredentialDataStore.get(storageID);
if (storedCredential != null) {
tokenResponse = new TokenResponse();
tokenResponse.setAccessToken(storedCredential.getAccessToken());
tokenResponse.setRefreshToken(storedCredential.getRefreshToken());
if (storedCredential.getExpirationTimeMilliseconds() != null) {
tokenResponse.setExpiresInSeconds(TimeUnit.MILLISECONDS.toSeconds(storedCredential.getExpirationTimeMilliseconds()));
}
}
} catch (Exception exception) {
//logInfo("Exception getting OAuth2TokenData :" + exception.localizedMessage)
}
return tokenResponse;
}
我有一个 GoogleCalendarHelper:
public GoogleCalendarHelper() {
Calendar calendarAPIClient = new Calendar(new NetHttpTransport(), new JacksonFactory(), AuthHelper.mGoogleCredential);
calendarAPIClient.events();
Log.e("SOMETHING", "");
}
代码是从我的 MainActivity 的 onCreate 方法调用的。
AuthHelper AH = new AuthHelper(GoogleSignIn.getAuthCode(this));
GoogleCalendarHelper GCH = new GoogleCalendarHelper();
我意识到我可能必须使用 AsyncTask,但是这将如何实现呢?这是获取日历事件信息的最佳方式,还是有更好的方式?
谢谢
解决方案
错误日志很清楚:主线程上的网络。
您正在主线程上执行日历请求,这是一个网络请求。
您必须在后台执行此操作,一些常见的解决方案是协程、RxJava、Callable / Runnable、使用服务、手动管理线程甚至是 AsyncTask(已弃用)。
哪种解决方案完全取决于您,但在 Android 和 Android Things 上都禁止在 UI 线程上长时间运行操作。
推荐阅读
- c# - 如何以编程方式修改平面文件连接到 SSIS 包的连接字符串?
- python - Postgres死锁与(选择共享+插入)和(选择更新+更新)
- android - 意图广播:RegisterUponInstallReceiver、本机 ANR、无 Java 堆栈
- mpeg - 从 MPEG 传输流文件中获取数据以在脚本中使用的好方法是什么?
- c# - 无法使用 iText7 获得文档认证级别
- java - 使用 Iterator 调用多参数方法
- excel - 如何在高级筛选器 (Excel) 中对数字使用通配符
- android - 手机可以接收868.4 MHz频率的信号吗?
- c# - 如何成功存储和加载游戏角色的数据?
- javascript - React 被认为是一个库,Angular 被认为是一个框架。为什么这样?