Java 如何在影响当前活动的Runnable中提供回调函数
我有以下课程:Java 如何在影响当前活动的Runnable中提供回调函数,java,android,Java,Android,我有以下课程: package com.example.vodafone_fu_h300s.logic; import com.example.vodafone_fu_h300s.logic.exceptions.CsrfTokenNotFound; import com.example.vodafone_fu_h300s.logic.exceptions.SettingsFailedException; import com.example.vodafone_fu_h300s.logic.
package com.example.vodafone_fu_h300s.logic;
import com.example.vodafone_fu_h300s.logic.exceptions.CsrfTokenNotFound;
import com.example.vodafone_fu_h300s.logic.exceptions.SettingsFailedException;
import com.example.vodafone_fu_h300s.logic.lambdas.ExceptionHandler;
import com.example.vodafone_fu_h300s.logic.lambdas.LoginHandler;
import com.example.vodafone_fu_h300s.logic.lambdas.RetrieveSettingsHandler;
import com.example.vodafone_fu_h300s.logic.lambdas.SettingsRetrievalFailedHandler;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.FormBody.Builder;
import java.security.MessageDigest;
public class Η300sCredentialsRetriever {
private String url;
private OkHttpClient httpClient;
private String username;
private String password;
private LoginHandler loginHandler;
private ExceptionHandler exceptionHandler;
private RetrieveSettingsHandler settingsHandler;
private SettingsRetrievalFailedHandler failedHandler;
private String session_id;
public Η300sCredentialsRetriever()
{
this.exceptionHandler = (Exception e)->{};
this.loginHandler = (boolean loginStatus)->{};
this.settingsHandler = (H300sVoipSettings settings)->{};
this.failedHandler = ()->{};
this.setHttpClient(new OkHttpClient());
}
public void setSettingsHandler(RetrieveSettingsHandler handler){
this.settingsHandler = handler;
}
public void setFailedHandler(SettingsRetrievalFailedHandler handler){
this.failedHandler = handler;
}
public void setExceptionHandler(ExceptionHandler handler){
this.exceptionHandler= handler;
}
public void setLoginHandler(LoginHandler handler){
this.loginHandler=handler;
}
public void setUrl(String url){
url = "http://"+url.replaceAll("http(s?)://","");
this.url = url;
}
public String getUrl(){
return this.url;
}
public void setHttpClient(OkHttpClient client)
{
this.httpClient = client;
}
public void setUsername(String username){
this.username = username.trim();
}
public void setPassword(String password){
this.password = password.trim();
}
public String getSessionId()
{
return this.session_id;
}
public String retrieveCSRFTokenFromHtml(String htmlPageUrl) throws IOException {
if(htmlPageUrl==null || htmlPageUrl.trim().equals("")){
return "";
}
Pattern csrfRegex = Pattern.compile("var csrf_token\\s*=\\s*'.+'");
Matcher match = csrfRegex.matcher(htmlPageUrl);
if(match.find()){
String matched = match.group();
matched=matched.replaceAll("var|csrf_token|'|\\s|=","");
return matched;
}
return "";
}
public String retrieveUrlContents(String url, String csrfToken, String referer) throws Exception
{
url = this.url.replaceAll("/$","")+"/"+url.replaceAll("^/","");
csrfToken=(csrfToken == null)?"":csrfToken;
if(!csrfToken.equals("")){
long unixtime = System.currentTimeMillis() / 1000L;
// AJAX Calls also require to offer the _ with a unix timestamp alongside csrf token
url+="?_="+unixtime+"&csrf_token="+csrfToken;
}
Request.Builder request = new Request.Builder()
.url(url)
.header("User-Agent","Mozila/5.0 (X11;Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0")
.header("Accept","text/html,application/xhtml+html;application/xml;q=0.9,image/webp,*/*;q=0.8")
.header("Upgrade-Insecure-Requests","1")
.header("Sec-GPC","1");
String session_id = this.getSessionId();
session_id = session_id==null?"":session_id;
if(!session_id.equals("")){
request.header("Cookie","login_uid="+Math.random()+"; session_id="+session_id);
}
referer = (referer==null)?"":referer;
if(!referer.trim().equals("")){
request.header("Referer",referer);
}
Response response = this.httpClient.newCall(request.build()).execute();
int code = response.code();
if( code != 200){
throw new Exception("The url "+url+" returned code "+code);
}
String responseBody = response.body().string();
return responseBody;
}
public String retrieveUrlContents(String url, String csrfToken) throws Exception
{
return retrieveUrlContents(url,csrfToken,"");
}
public String retrieveUrlContents(String url) throws Exception {
return retrieveUrlContents(url,"");
}
public String retrieveCsrfTokenFromUrl(String url,String referer) throws CsrfTokenNotFound {
try {
String html = retrieveUrlContents(url,"",referer);
return retrieveCSRFTokenFromHtml(html);
} catch (Exception e) {
exceptionHandler.handle(e);
throw new CsrfTokenNotFound(url);
}
}
public boolean login() {
if(
username == null || username.equals("") ||
password == null || password.equals("")){
return false;
}
try {
this.session_id = null;
String token = this.retrieveCsrfTokenFromUrl("/login.html",null);
if(token == null){
return false;
}
if(token.trim().equals("")){
return false;
}
String challengeJson = this.retrieveUrlContents("/data/login.json");
if(challengeJson == null){
return false;
}
if(challengeJson.trim().equals("")){
return false;
}
JSONObject json = (JSONObject) (new JSONArray(challengeJson)).get(0);
String challenge = json.getString("challenge");
if(challenge == null){
return false;
}
if(challenge.trim().equals("")){
return false;
}
MessageDigest md = MessageDigest.getInstance("SHA-256");
String stringToDigest = password+challenge;
byte []hash = md.digest(stringToDigest.getBytes(StandardCharsets.UTF_8));
BigInteger number = new BigInteger(1, hash);
StringBuilder hexString = new StringBuilder(number.toString(16));
String loginPwd = hexString.toString();
RequestBody requestBody = new Builder()
.add("LoginName", username)
.add("LoginPWD", loginPwd)
.add("challenge",challenge)
.build();
long unixTime = System.currentTimeMillis() / 1000L;
Request request = new Request.Builder()
.url(this.url+"/data/login.json?_="+unixTime+"&csrfToken="+token)
.post(requestBody)
.header("Cookie","login_uid="+Math.random())
.header("Referer","http://192.158.2.1/login.html")
.header("X-Requested-With","XMLHttpRequest")
.header("Content-Type","application/x-www-form-urnencoded; charset=UTF-8")
.header("User-Agent","Mozila/5.0 (X11;Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0")
.header("Origin","http://192.168.2.1")
.build();
Call call = this.httpClient.newCall(request);
Response response = call.execute();
String responseString = response.body().string();
String cookies = response.header("Set-Cookie");
if(cookies == null || cookies.trim().equals("")){
return false;
}
cookies=cookies.replaceAll("path=/|session_id=|;","");
this.session_id=cookies;
return responseString.equals("1");
} catch (Exception e){
exceptionHandler.handle(e);
return false;
}
}
public H300sVoipSettings retrieveVOIPSettings() throws Exception {
H300sVoipSettings settings;
String csrfToken = retrieveCsrfTokenFromUrl("/overview.html",this.url+"/login.html");
if(csrfToken == null || csrfToken.trim().equals("")){
throw new SettingsFailedException();
}
String contents = retrieveUrlContents("/data/phone_voip.json",csrfToken,this.url+"/phone.html");
if(contents == null || contents.trim().equals("")){
throw new SettingsFailedException();
}
try{
settings = H300sVoipSettings.createFromJson(contents);
} catch (Exception e){
this.exceptionHandler.handle(e);
throw new SettingsFailedException();
}
return settings;
}
public void retrieveVoipCredentials()
{
try {
boolean loginStatus = login();
loginHandler.loginCallback(loginStatus);
if (loginStatus) {
H300sVoipSettings settings = retrieveVOIPSettings();
settingsHandler.retrieveSettings(settings);
}
} catch (SettingsFailedException f){
failedHandler.handler();
exceptionHandler.handle(f);
} catch (Exception e){
exceptionHandler.handle(e);
}
}
}
它的主要目的是执行一系列HttpCalls,并检索H300s Sercomm路由器的voip凭据
该类通过以下活动运行:
package com.example.vodafone_fu_h300s.screens;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.text.TextWatcher;
import com.example.vodafone_fu_h300s.R;
import com.example.vodafone_fu_h300s.logic.H300sVoipSettings;
import com.example.vodafone_fu_h300s.logic.Η300sCredentialsRetriever;
import kotlin.reflect.KFunction;
public class ConnectIntoRouterActivity extends AppCompatActivity implements View.OnClickListener, TextWatcher {
private CredentialsRetriever retriever;
private EditText url;
private EditText admin;
private EditText password;
private Button submit;
private class CredentialsRetriever extends Η300sCredentialsRetriever implements Runnable {
private ConnectIntoRouterActivity activity;
public CredentialsRetriever(ConnectIntoRouterActivity activity)
{
super();
this.activity = activity;
this.setExceptionHandler((Exception e) -> {
Log.e("Η300s",ConnectIntoRouterActivity.class+e.getMessage());
});
this.setLoginHandler((boolean loginStatus)->{
if(!loginStatus){
Log.e("Η300s",ConnectIntoRouterActivity.class+" Login Failed");
this.activity.getSubmit().setEnabled(true);
}
});
this.setSettingsHandler((H300sVoipSettings settings)->{
this.activity.getSubmit().setEnabled(true);
Intent displaySettings = new Intent(this.activity, DisplaySettingsActivity.class);
displaySettings.putExtra("settings",settings);
startActivity(displaySettings);
});
}
public void run() {
this.retrieveVoipCredentials();
}
}
public Button getSubmit()
{
return this.submit;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_connect_into_router);
Intent activityIntent = getIntent();
String menu_url = activityIntent.getStringExtra("router_url");
Button submit = (Button)findViewById(R.id.connect_btn);
submit.setOnClickListener(this);
this.submit = submit;
this.retriever = new CredentialsRetriever(this);
this.url = (EditText)findViewById(R.id.menu_url);
url.setText(menu_url);
url.addTextChangedListener(this);
this.admin = (EditText)findViewById(R.id.username);
admin.setText("admin");
admin.addTextChangedListener(this);
this.password = (EditText)findViewById(R.id.password);
password.addTextChangedListener(this);
}
private void onUpdateForm() {
String menu_url = this.url.getText().toString();
String admin = this.admin.getText().toString();
String password = this.password.getText().toString();
if(menu_url.equals("")||admin.equals("")||password.equals("")){
Button submit = (Button)findViewById(R.id.connect_btn);
submit.setEnabled(false);
return;
}
Button submit = (Button)findViewById(R.id.connect_btn);
submit.setEnabled(true);
this.retriever.setUrl(menu_url);
this.retriever.setUsername(admin);
this.retriever.setPassword(password);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable s) {
onUpdateForm();
}
@Override
public void onClick(View v){
Button submit = (Button)findViewById(R.id.connect_btn);
submit.setEnabled(false);
Thread thread = new Thread(this.retriever);
thread.start();
}
}
但一旦我按下活动呈现的以下表单上的提交:
我得到以下错误:
我还尝试了以下方法:
package com.example.vodafone_fu_h300s.screens;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.text.TextWatcher;
import com.example.vodafone_fu_h300s.R;
import com.example.vodafone_fu_h300s.logic.H300sVoipSettings;
import com.example.vodafone_fu_h300s.logic.Η300sCredentialsRetriever;
import kotlin.reflect.KFunction;
public class ConnectIntoRouterActivity extends AppCompatActivity implements View.OnClickListener, TextWatcher {
private CredentialsRetriever retriever;
private EditText url;
private EditText admin;
private EditText password;
private Button submit;
private class CredentialsRetriever extends Η300sCredentialsRetriever implements Runnable {
private ConnectIntoRouterActivity activity;
public CredentialsRetriever(ConnectIntoRouterActivity activity)
{
super();
this.activity = activity;
this.setExceptionHandler((Exception e) -> {
Log.e("Η300s",ConnectIntoRouterActivity.class+e.getMessage());
});
this.setLoginHandler((boolean loginStatus)->{
if(!loginStatus){
Log.e("Η300s",ConnectIntoRouterActivity.class+" Login Failed");
this.activity.getSubmit().setEnabled(true);
}
});
this.setSettingsHandler((H300sVoipSettings settings)->{
this.activity.getSubmit().setEnabled(true);
Intent displaySettings = new Intent(this.activity, DisplaySettingsActivity.class);
displaySettings.putExtra("settings",settings);
startActivity(displaySettings);
});
}
public void run() {
this.retrieveVoipCredentials();
}
}
public Button getSubmit()
{
return this.submit;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_connect_into_router);
Intent activityIntent = getIntent();
String menu_url = activityIntent.getStringExtra("router_url");
Button submit = (Button)findViewById(R.id.connect_btn);
submit.setOnClickListener(this);
this.submit = submit;
this.retriever = new CredentialsRetriever(this);
this.url = (EditText)findViewById(R.id.menu_url);
url.setText(menu_url);
url.addTextChangedListener(this);
this.admin = (EditText)findViewById(R.id.username);
admin.setText("admin");
admin.addTextChangedListener(this);
this.password = (EditText)findViewById(R.id.password);
password.addTextChangedListener(this);
}
private void onUpdateForm() {
String menu_url = this.url.getText().toString();
String admin = this.admin.getText().toString();
String password = this.password.getText().toString();
if(menu_url.equals("")||admin.equals("")||password.equals("")){
Button submit = (Button)findViewById(R.id.connect_btn);
submit.setEnabled(false);
return;
}
Button submit = (Button)findViewById(R.id.connect_btn);
submit.setEnabled(true);
this.retriever.setUrl(menu_url);
this.retriever.setUsername(admin);
this.retriever.setPassword(password);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable s) {
onUpdateForm();
}
@Override
public void onClick(View v){
Button submit = (Button)findViewById(R.id.connect_btn);
submit.setEnabled(false);
runOnUiThread(this.retriever);
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.vodafone_fu_h300s">
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.VfuH300s"
android:usesCleartextTraffic="true">
<activity android:name=".screens.DisplaySettingsActivity"></activity>
<activity android:name=".screens.ConnectIntoRouterActivity" />
<activity android:name=".screens.InstructionsActivity" />
<activity android:name=".screens.ErrorActivity" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
但我得到了以下错误:
E/Η300s:class com.example.vodafone_fu_h300s.screens.connectionToRouterActivity创建视图层次结构的原始线程只能接触其视图
那么,如何运行线程并为任何事件提供回调,例如在事件发生错误的情况下,例如成功检索完整凭据
我的应用程序清单如下所示:
package com.example.vodafone_fu_h300s.screens;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.text.TextWatcher;
import com.example.vodafone_fu_h300s.R;
import com.example.vodafone_fu_h300s.logic.H300sVoipSettings;
import com.example.vodafone_fu_h300s.logic.Η300sCredentialsRetriever;
import kotlin.reflect.KFunction;
public class ConnectIntoRouterActivity extends AppCompatActivity implements View.OnClickListener, TextWatcher {
private CredentialsRetriever retriever;
private EditText url;
private EditText admin;
private EditText password;
private Button submit;
private class CredentialsRetriever extends Η300sCredentialsRetriever implements Runnable {
private ConnectIntoRouterActivity activity;
public CredentialsRetriever(ConnectIntoRouterActivity activity)
{
super();
this.activity = activity;
this.setExceptionHandler((Exception e) -> {
Log.e("Η300s",ConnectIntoRouterActivity.class+e.getMessage());
});
this.setLoginHandler((boolean loginStatus)->{
if(!loginStatus){
Log.e("Η300s",ConnectIntoRouterActivity.class+" Login Failed");
this.activity.getSubmit().setEnabled(true);
}
});
this.setSettingsHandler((H300sVoipSettings settings)->{
this.activity.getSubmit().setEnabled(true);
Intent displaySettings = new Intent(this.activity, DisplaySettingsActivity.class);
displaySettings.putExtra("settings",settings);
startActivity(displaySettings);
});
}
public void run() {
this.retrieveVoipCredentials();
}
}
public Button getSubmit()
{
return this.submit;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_connect_into_router);
Intent activityIntent = getIntent();
String menu_url = activityIntent.getStringExtra("router_url");
Button submit = (Button)findViewById(R.id.connect_btn);
submit.setOnClickListener(this);
this.submit = submit;
this.retriever = new CredentialsRetriever(this);
this.url = (EditText)findViewById(R.id.menu_url);
url.setText(menu_url);
url.addTextChangedListener(this);
this.admin = (EditText)findViewById(R.id.username);
admin.setText("admin");
admin.addTextChangedListener(this);
this.password = (EditText)findViewById(R.id.password);
password.addTextChangedListener(this);
}
private void onUpdateForm() {
String menu_url = this.url.getText().toString();
String admin = this.admin.getText().toString();
String password = this.password.getText().toString();
if(menu_url.equals("")||admin.equals("")||password.equals("")){
Button submit = (Button)findViewById(R.id.connect_btn);
submit.setEnabled(false);
return;
}
Button submit = (Button)findViewById(R.id.connect_btn);
submit.setEnabled(true);
this.retriever.setUrl(menu_url);
this.retriever.setUsername(admin);
this.retriever.setPassword(password);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable s) {
onUpdateForm();
}
@Override
public void onClick(View v){
Button submit = (Button)findViewById(R.id.connect_btn);
submit.setEnabled(false);
runOnUiThread(this.retriever);
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.vodafone_fu_h300s">
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.VfuH300s"
android:usesCleartextTraffic="true">
<activity android:name=".screens.DisplaySettingsActivity"></activity>
<activity android:name=".screens.ConnectIntoRouterActivity" />
<activity android:name=".screens.InstructionsActivity" />
<activity android:name=".screens.ErrorActivity" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>