我的 .onSucceed (okhttp) 抛出 "Service must only be used fromm FX Application Thread"
My .onSucceed (okhttp) throws "Service must only be used fromm FX Application Thread"
我编写了一个捕获 401 HTTP 状态的拦截器,然后调用一个向服务器发送 RefreshToken 的方法以获取新的 AccessToken。由于某种原因,尽管在同一个 class 中它不起作用,但我有第二个功能,它的功能几乎相同并且工作得很好。
我是不是错过了什么?
提前致谢。
发生错误的函数:
public void RefreshToken(){
try{
if(db==null){
db=Database.newInstance();
}
}catch(Exception ex){
System.out.println("Error in while getting new Database");
}
Service<String> t=db.GetAccessToken();
t.setOnSucceeded(e -> { //Error thrown here
Database.ACCESSTOKEN=t.getValue();
});
t.setOnFailed(e -> {
System.out.println("Error with HTTP GET new Token");
});
}
几乎相同的功能:
private void Login(String username, String password) {
Service<BothTokens> t=db.Login(new Credentials(username,password));
t.setOnSucceeded(e -> {
Database.REFRESHTOKEN=t.getValue().getRefreshToken();
Database.ACCESSTOKEN=t.getValue().getAccessToken();
openMainFXML();
closeWindow();
});
t.setOnFailed(e -> {
new ServiceExceptionHandler<>(t).handleServiceWithRetryOrClose((Stage) btnLogin.getScene().getWindow(),
"Error beim Login",
t.getException().getMessage(), (Exception) t.getException());
});
}
拦截器:
OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder().addInterceptor(chain -> {
Response originalResponse = chain.proceed(chain.request());
if(originalResponse.code()==401){
try{
Login_Controller login=Login_Controller.newInstance();
login.RefreshToken();
}catch(Exception ex){
System.out.println("Error getting new Token");
ex.printStackTrace();
}
}
return originalResponse;
}).build();
异常:
java.lang.IllegalStateException: Service must only be used from the FX Application Thread
at javafx.concurrent.Service.checkThread(Service.java:906)
at javafx.concurrent.Service.setOnSucceeded(Service.java:409)
at pkgController.Login_Controller.RefreshToken(Login_Controller.java:106)
at pkgServices.statics.StaticServerObjects.lambda$static[=14=](StaticServerObjects.java:19)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.kt:184)
at okhttp3.RealCall.execute(RealCall.kt:66)
at pkgServices.buildings.GetBuildings.call(GetBuildings.java:32)
at pkgServices.buildings.GetBuildings.call(GetBuildings.java:25)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1423)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at javafx.concurrent.Service.lambda$null3(Service.java:725)
at java.security.AccessController.doPrivileged(Native Method)
at javafx.concurrent.Service.lambda$executeTask4(Service.java:724)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
java.lang.Exception: java.lang.Exception: Exception occured in GetBuildings with code: 401
at pkgServices.buildings.GetBuildings.call(GetBuildings.java:40)
at pkgServices.buildings.GetBuildings.call(GetBuildings.java:25)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1423)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at javafx.concurrent.Service.lambda$null3(Service.java:725)
at java.security.AccessController.doPrivileged(Native Method)
at javafx.concurrent.Service.lambda$executeTask4(Service.java:724)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.Exception: Exception occured in GetBuildings with code: 401
at pkgServices.buildings.GetBuildings.call(GetBuildings.java:37)
... 9 more
问题是该函数 运行 在与 FXML-Controller 不同的线程中,我不得不编写
Platform.runLater(() -> {....} )
我建议使用 javafx AsyncTask Libray
并准备您的请求如下:
public class Example extends AsyncTask<Void,Void,String> {
private UIController controller;
public Example(UIController controller) {
this.controller = controller;
}
@Override
void onPreExecute() {
//PREPARE GUI, SHOW PROGRESS OR SOMETHING....
this.controller.updateProgressLabel("Starting Download")
}
@Override
String doInBackground() {
//THIS METHOD WORKING IN BACKGROUND HERE YOU SOULD IMPLEMENT CODE OF HTTP REQUEST AND RETURN RESULT OF REQUEST FOR EXAMPLE OBJECT OR JSON STRING
return new String();
}
@Override
void onPostExecute(String result) {
//HERE YOU CAN GET YOUR DATA FROM REQUEST AND SET RESULT ON GUI
this.controller.updateProgressLabel(result);
}
@Override
void progressCallback(Object... params) {
}
}
我编写了一个捕获 401 HTTP 状态的拦截器,然后调用一个向服务器发送 RefreshToken 的方法以获取新的 AccessToken。由于某种原因,尽管在同一个 class 中它不起作用,但我有第二个功能,它的功能几乎相同并且工作得很好。
我是不是错过了什么? 提前致谢。
发生错误的函数:
public void RefreshToken(){
try{
if(db==null){
db=Database.newInstance();
}
}catch(Exception ex){
System.out.println("Error in while getting new Database");
}
Service<String> t=db.GetAccessToken();
t.setOnSucceeded(e -> { //Error thrown here
Database.ACCESSTOKEN=t.getValue();
});
t.setOnFailed(e -> {
System.out.println("Error with HTTP GET new Token");
});
}
几乎相同的功能:
private void Login(String username, String password) {
Service<BothTokens> t=db.Login(new Credentials(username,password));
t.setOnSucceeded(e -> {
Database.REFRESHTOKEN=t.getValue().getRefreshToken();
Database.ACCESSTOKEN=t.getValue().getAccessToken();
openMainFXML();
closeWindow();
});
t.setOnFailed(e -> {
new ServiceExceptionHandler<>(t).handleServiceWithRetryOrClose((Stage) btnLogin.getScene().getWindow(),
"Error beim Login",
t.getException().getMessage(), (Exception) t.getException());
});
}
拦截器:
OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder().addInterceptor(chain -> {
Response originalResponse = chain.proceed(chain.request());
if(originalResponse.code()==401){
try{
Login_Controller login=Login_Controller.newInstance();
login.RefreshToken();
}catch(Exception ex){
System.out.println("Error getting new Token");
ex.printStackTrace();
}
}
return originalResponse;
}).build();
异常:
java.lang.IllegalStateException: Service must only be used from the FX Application Thread
at javafx.concurrent.Service.checkThread(Service.java:906)
at javafx.concurrent.Service.setOnSucceeded(Service.java:409)
at pkgController.Login_Controller.RefreshToken(Login_Controller.java:106)
at pkgServices.statics.StaticServerObjects.lambda$static[=14=](StaticServerObjects.java:19)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.kt:184)
at okhttp3.RealCall.execute(RealCall.kt:66)
at pkgServices.buildings.GetBuildings.call(GetBuildings.java:32)
at pkgServices.buildings.GetBuildings.call(GetBuildings.java:25)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1423)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at javafx.concurrent.Service.lambda$null3(Service.java:725)
at java.security.AccessController.doPrivileged(Native Method)
at javafx.concurrent.Service.lambda$executeTask4(Service.java:724)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
java.lang.Exception: java.lang.Exception: Exception occured in GetBuildings with code: 401
at pkgServices.buildings.GetBuildings.call(GetBuildings.java:40)
at pkgServices.buildings.GetBuildings.call(GetBuildings.java:25)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1423)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at javafx.concurrent.Service.lambda$null3(Service.java:725)
at java.security.AccessController.doPrivileged(Native Method)
at javafx.concurrent.Service.lambda$executeTask4(Service.java:724)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.Exception: Exception occured in GetBuildings with code: 401
at pkgServices.buildings.GetBuildings.call(GetBuildings.java:37)
... 9 more
问题是该函数 运行 在与 FXML-Controller 不同的线程中,我不得不编写
Platform.runLater(() -> {....} )
我建议使用 javafx AsyncTask Libray 并准备您的请求如下:
public class Example extends AsyncTask<Void,Void,String> {
private UIController controller;
public Example(UIController controller) {
this.controller = controller;
}
@Override
void onPreExecute() {
//PREPARE GUI, SHOW PROGRESS OR SOMETHING....
this.controller.updateProgressLabel("Starting Download")
}
@Override
String doInBackground() {
//THIS METHOD WORKING IN BACKGROUND HERE YOU SOULD IMPLEMENT CODE OF HTTP REQUEST AND RETURN RESULT OF REQUEST FOR EXAMPLE OBJECT OR JSON STRING
return new String();
}
@Override
void onPostExecute(String result) {
//HERE YOU CAN GET YOUR DATA FROM REQUEST AND SET RESULT ON GUI
this.controller.updateProgressLabel(result);
}
@Override
void progressCallback(Object... params) {
}
}