如何在 Android 上发出 GET 请求?
How to make a GET request on Android?
我之前开发了一个实时货币转换器程序,想将其导出为 Android 应用程序。
为此,我使用带有 RestTemplate 的 GET 请求来获取 2 种货币之间的汇率。但是,我收到此错误:android.os.NetworkOnMainThreadException
这是我第一次尝试的代码:
public void displayResult(View view) {
TextView output = (TextView) findViewById(R.id.conversion);
output.setInputType(InputType.TYPE_CLASS_NUMBER);
output.setText(String.valueOf(convert()));
}
float convert() {
EditText textBaseCurrency = (EditText) findViewById(R.id.BASE_CURRENCY);
EditText textTargetCurrency = (EditText) findViewById(R.id.TARGET_CURRENCY);
EditText textAmount = (EditText) findViewById(R.id.AMOUNT);
String baseCurrency = textBaseCurrency.getText().toString().toUpperCase();
String targetCurrency = textTargetCurrency.getText().toString().toUpperCase();
float amount = Integer.parseInt(textAmount.getText().toString());
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
String url = "https://v6.exchangerate-api.com/v6/" + API_KEY + "/latest/" + baseCurrency;
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
System.out.println(responseEntity);
ObjectMapper mapper = new ObjectMapper();
JsonNode root = null;
try {
root = mapper.readTree(responseEntity.getBody());
} catch (IOException e) {
e.printStackTrace();
}
JsonNode name = root.get(conversionRates);
JsonNode rates = name.get(targetCurrency);
float rate = rates.floatValue();
float newAmount = rate * amount;
return newAmount;
}
我看到解决方案是使用 AsyncTask
。我试过了,但是没有成功:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Connection().execute();
}
public class Connection extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
EditText textBaseCurrency = (EditText) findViewById(R.id.BASE_CURRENCY);
EditText textTargetCurrency = (EditText) findViewById(R.id.TARGET_CURRENCY);
EditText textAmount = (EditText) findViewById(R.id.AMOUNT);
String baseCurrency = textBaseCurrency.getText().toString().toUpperCase();
String targetCurrency = textTargetCurrency.getText().toString().toUpperCase();
float amount = Integer.parseInt(textAmount.getText().toString());
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
String url = "https://v6.exchangerate-api.com/v6/" + API_KEY + "/latest/" + baseCurrency;
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
System.out.println(responseEntity);
ObjectMapper mapper = new ObjectMapper();
JsonNode root = null;
try {
root = mapper.readTree(responseEntity.getBody());
} catch (IOException e) {
e.printStackTrace();
}
JsonNode name = root.get(conversionRates);
JsonNode rates = name.get(targetCurrency);
float rate = rates.floatValue();
float newAmount = rate * amount;
return null;
}
此外,现在已弃用。
我的 gradle.build 文件:
packagingOptions{
exclude 'META-INF/notice.txt'
exclude 'META-INF/license.txt'
}dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.10.6'
implementation 'javax.xml.stream:stax-api:1.0'
implementation 'org.springframework.android:spring-android-rest-template:1.0.1.RELEASE'
}
我还在 AndroidManifest.xml
中添加了 <uses-permission android:name="android.permission.INTERNET" />
您需要执行 api 进程 im 后台线程而不是主线程
使用异步任务
使用改造
使用 Runnable
从中选择一项。还有很多
您可以使用一些类似的库来执行此操作:
但首先你应该添加这个权限:
<uses-permission android:name="android.permission.INTERNET" />
但最简单的方法是:
class RequestTask extends AsyncTask<String, String, String>{
@Override
protected String doInBackground(String... uri) {
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
String responseString = null;
try {
response = httpclient.execute(new HttpGet(uri[0]));
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpStatus.SC_OK){
ByteArrayOutputStream out = new ByteArrayOutputStream();
response.getEntity().writeTo(out);
responseString = out.toString();
out.close();
} else{
//Closes the connection.
response.getEntity().getContent().close();
throw new IOException(statusLine.getReasonPhrase());
}
} catch (ClientProtocolException e) {
//TODO Handle problems..
} catch (IOException e) {
//TODO Handle problems..
}
return responseString;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
//Do anything with response..
}
}
然后您可以通过以下方式提出请求:
new RequestTask().execute("https://v6.exchangerate-api.com/v6/" + API_KEY + "/latest/" + baseCurrency);
请记住,如果您在 android9 上使用此应用程序,您应该将此属性用于您的 AndroidManifest.xml,您允许所有请求的所有 http:
<application android:usesCleartextTraffic="true">
</application>
但如果您需要为不同的链接进行更多配置,例如,允许某些域使用 HTTP 而不是其他域,您必须提供 res/xml/networkSecurityConfig.xml
文件。
要在 Android 9 Pie 中执行此操作,您必须在清单应用程序标记中设置一个 networkSecurityConfig,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application android:networkSecurityConfig="@xml/network_security_config">
</application>
</manifest>
然后在你的 xml
文件夹中,你现在必须创建一个名为 network_security_config
的文件,就像你在清单中命名它的方式一样,从那里你的文件内容应该是这样的启用所有不加密的请求:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
</network-security-config>
但请注意:
sdk 23 不再支持 HttpClient
。您必须使用 URLConnection
或降级到 sdk 22 (compile 'com.android.support:appcompat-v7:22.2.0'
)
如果您需要 sdk 23,请将其添加到您的 gradle:
android {
useLibrary 'org.apache.http.legacy'
}
您也可以尝试下载 HttpClient.jar 并将其直接包含到您的项目中,或者改用 OkHttp
您不能在主线程中执行 HTTP 请求。您需要 运行 它们在不同的线程上,然后 运行 在主线程中进行回调。
是的,您可以使用 AsyncTask
,但代码会非常冗长,我个人不喜欢 AsyncTask
s
您必须在单独的线程上执行与网络相关的操作...
您可以使用 AsyncTask
private class DownloadFilesTask extends AsyncTask<Void, Void, Float> {
protected Float doInBackground(Void) {
// put the convert function definition
}
protected void onPostExecute(Float result) {
// update the UI after background processes completes
}
}
将此 class 定义为 activity 的子 class,然后将其命名为
new MyTask().execute();
我之前开发了一个实时货币转换器程序,想将其导出为 Android 应用程序。
为此,我使用带有 RestTemplate 的 GET 请求来获取 2 种货币之间的汇率。但是,我收到此错误:android.os.NetworkOnMainThreadException
这是我第一次尝试的代码:
public void displayResult(View view) {
TextView output = (TextView) findViewById(R.id.conversion);
output.setInputType(InputType.TYPE_CLASS_NUMBER);
output.setText(String.valueOf(convert()));
}
float convert() {
EditText textBaseCurrency = (EditText) findViewById(R.id.BASE_CURRENCY);
EditText textTargetCurrency = (EditText) findViewById(R.id.TARGET_CURRENCY);
EditText textAmount = (EditText) findViewById(R.id.AMOUNT);
String baseCurrency = textBaseCurrency.getText().toString().toUpperCase();
String targetCurrency = textTargetCurrency.getText().toString().toUpperCase();
float amount = Integer.parseInt(textAmount.getText().toString());
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
String url = "https://v6.exchangerate-api.com/v6/" + API_KEY + "/latest/" + baseCurrency;
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
System.out.println(responseEntity);
ObjectMapper mapper = new ObjectMapper();
JsonNode root = null;
try {
root = mapper.readTree(responseEntity.getBody());
} catch (IOException e) {
e.printStackTrace();
}
JsonNode name = root.get(conversionRates);
JsonNode rates = name.get(targetCurrency);
float rate = rates.floatValue();
float newAmount = rate * amount;
return newAmount;
}
我看到解决方案是使用 AsyncTask
。我试过了,但是没有成功:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Connection().execute();
}
public class Connection extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
EditText textBaseCurrency = (EditText) findViewById(R.id.BASE_CURRENCY);
EditText textTargetCurrency = (EditText) findViewById(R.id.TARGET_CURRENCY);
EditText textAmount = (EditText) findViewById(R.id.AMOUNT);
String baseCurrency = textBaseCurrency.getText().toString().toUpperCase();
String targetCurrency = textTargetCurrency.getText().toString().toUpperCase();
float amount = Integer.parseInt(textAmount.getText().toString());
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
String url = "https://v6.exchangerate-api.com/v6/" + API_KEY + "/latest/" + baseCurrency;
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
System.out.println(responseEntity);
ObjectMapper mapper = new ObjectMapper();
JsonNode root = null;
try {
root = mapper.readTree(responseEntity.getBody());
} catch (IOException e) {
e.printStackTrace();
}
JsonNode name = root.get(conversionRates);
JsonNode rates = name.get(targetCurrency);
float rate = rates.floatValue();
float newAmount = rate * amount;
return null;
}
此外,现在已弃用。
我的 gradle.build 文件:
packagingOptions{
exclude 'META-INF/notice.txt'
exclude 'META-INF/license.txt'
}dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.10.6'
implementation 'javax.xml.stream:stax-api:1.0'
implementation 'org.springframework.android:spring-android-rest-template:1.0.1.RELEASE'
}
我还在 AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
您需要执行 api 进程 im 后台线程而不是主线程
使用异步任务 使用改造 使用 Runnable
从中选择一项。还有很多
您可以使用一些类似的库来执行此操作:
但首先你应该添加这个权限:
<uses-permission android:name="android.permission.INTERNET" />
但最简单的方法是:
class RequestTask extends AsyncTask<String, String, String>{
@Override
protected String doInBackground(String... uri) {
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
String responseString = null;
try {
response = httpclient.execute(new HttpGet(uri[0]));
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpStatus.SC_OK){
ByteArrayOutputStream out = new ByteArrayOutputStream();
response.getEntity().writeTo(out);
responseString = out.toString();
out.close();
} else{
//Closes the connection.
response.getEntity().getContent().close();
throw new IOException(statusLine.getReasonPhrase());
}
} catch (ClientProtocolException e) {
//TODO Handle problems..
} catch (IOException e) {
//TODO Handle problems..
}
return responseString;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
//Do anything with response..
}
}
然后您可以通过以下方式提出请求:
new RequestTask().execute("https://v6.exchangerate-api.com/v6/" + API_KEY + "/latest/" + baseCurrency);
请记住,如果您在 android9 上使用此应用程序,您应该将此属性用于您的 AndroidManifest.xml,您允许所有请求的所有 http:
<application android:usesCleartextTraffic="true">
</application>
但如果您需要为不同的链接进行更多配置,例如,允许某些域使用 HTTP 而不是其他域,您必须提供 res/xml/networkSecurityConfig.xml
文件。
要在 Android 9 Pie 中执行此操作,您必须在清单应用程序标记中设置一个 networkSecurityConfig,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application android:networkSecurityConfig="@xml/network_security_config">
</application>
</manifest>
然后在你的 xml
文件夹中,你现在必须创建一个名为 network_security_config
的文件,就像你在清单中命名它的方式一样,从那里你的文件内容应该是这样的启用所有不加密的请求:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
</network-security-config>
但请注意:
sdk 23 不再支持HttpClient
。您必须使用 URLConnection
或降级到 sdk 22 (compile 'com.android.support:appcompat-v7:22.2.0'
)
如果您需要 sdk 23,请将其添加到您的 gradle:
android {
useLibrary 'org.apache.http.legacy'
}
您也可以尝试下载 HttpClient.jar 并将其直接包含到您的项目中,或者改用 OkHttp
您不能在主线程中执行 HTTP 请求。您需要 运行 它们在不同的线程上,然后 运行 在主线程中进行回调。
是的,您可以使用 AsyncTask
,但代码会非常冗长,我个人不喜欢 AsyncTask
s
您必须在单独的线程上执行与网络相关的操作... 您可以使用 AsyncTask
private class DownloadFilesTask extends AsyncTask<Void, Void, Float> {
protected Float doInBackground(Void) {
// put the convert function definition
}
protected void onPostExecute(Float result) {
// update the UI after background processes completes
}
}
将此 class 定义为 activity 的子 class,然后将其命名为
new MyTask().execute();