如何在 Android 上发出 GET 请求?

Posted

技术标签:

【中文标题】如何在 Android 上发出 GET 请求?【英文标题】:How to make a GET request on Android? 【发布时间】:2020-12-25 21:51:15 【问题描述】:

我之前开发了一个实时货币转换器程序,并希望将其导出为 android 应用程序。 为此,我使用带有 RestTemplate 的 GET 请求来获取两种货币之间的汇率。但是,然后我收到此错误: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 中添加了 &lt;uses-permission android:name="android.permission.INTERNET" /&gt;

【问题讨论】:

I saw that the solution would be to use AsyncTask. I tried it, but I wasn't successful. - 显示您尝试过的内容,这是正确的方法。您可以将AsyncTask 换成其他解决方案,例如喜欢HERE 【参考方案1】:

您可以使用类似的库来执行此操作:

Retrofit OkHttp HttpUrlConnection

但首先你应该添加这个权限:

    <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);

请记住,如果您在 android 9 上使用此应用程序,您应该在您的 AndroidManifest.xml 中使用此属性,您可以在其中允许所有 http 用于所有请求:

<application android:usesCleartextTraffic="true">
</application>

但如果您想为不同的链接进行更多配置,例如,允许某些域使用 HTTP 但不允许其他域使用 HTTP,则必须提供 res/xml/networkSecurityConfig.xml 文件。

要在 Android 9 Pie 中执行此操作,您必须在 Manifest 应用程序标签中设置 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

【讨论】:

【参考方案2】:

你不能像它一样在主线程中执行 HTTP 请求。您需要在不同的线程上运行它们,然后在主线程中运行回调。 是的,您可以使用AsyncTask,但代码会非常冗长,我个人不喜欢AsyncTasks

但是我建议您使用更高级的库,例如 Retrofit 或 OkHttp

【讨论】:

【参考方案3】:

您必须在单独的线程上执行与网络相关的操作... 您可以使用 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
    

将此类定义为该活动的子类,然后像这样调用它

new MyTask().execute();

【讨论】:

【参考方案4】:

您需要在后台线程而不是主线程中执行您的 api 进程

使用异步任务 使用改造 使用 Runnable

从这些中选择一个。还有很多

【讨论】:

以上是关于如何在 Android 上发出 GET 请求?的主要内容,如果未能解决你的问题,请参考以下文章

如何在协程中发出GET请求?

端口 3000 用于 express,端口 8081 用于响应本机,如何发出 get 请求

如何监控我的应用在 android 中发出的 HTTP(获取、发布等)请求

如何在 Android 上使用 cookie 发出 http 请求?

如何捕获从 MFC Web 浏览器 C++ 发出的 GET/POST 请求

如何在 Android (Facebook SDK v4) 上发出 Facebook 游戏请求后获取收件人 ID?