【问题标题】:Android HttpUrlConnection w Persistent ConnectionAndroid HttpUrlConnection w 持久连接
【发布时间】:2016-02-02 03:11:13
【问题描述】:

场景

用户必须使用此应用程序登录服务器。稍后在应用程序中,我们需要根据服务器检查他们的登录状态。我们过去常常通过跟踪上次使用的HttpClient 来做到这一点。最近我们切换到HttpUrlConnection,但所谓的持久连接不起作用。

问题

我编写了这个测试应用程序来查看连接是否持久。我从两个 URL 中获取了 xml,但连接的行为不像是一致的。我怎样才能让它工作?

注意:如果您在浏览器中转到 Login 网址,然后在同一浏览器中转到 GetUserInfo 网址,一切都会按预期进行。

MainActivity.java

package com.mediajackagency.test;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;

public class MainActivity extends AppCompatActivity {

    public Button signInBtn = null;
    public Button getUserInfoBtn = null;
    public TextView xmlTextView = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        this.xmlTextView = (TextView)findViewById(R.id.xmlTxtView);

        this.signInBtn = (Button)findViewById(R.id.signInBtn);
        this.signInBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AsyncTask task = new AsyncTask() {
                    @Override
                    protected Object doInBackground(Object[] params) {
                        String xml = loadUrl("https://www.fake.site/Login?userName=test&password=pass123");

                        return xml;
                    }

                    @Override
                    protected void onPostExecute(Object o) {
                        super.onPostExecute(o);
                        xmlTextView.setText(o.toString());
                    }
                };
                task.execute();
            }
        });

        this.getUserInfoBtn = (Button)findViewById(R.id.getUserInfoBtn);
        this.getUserInfoBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AsyncTask task = new AsyncTask() {
                    @Override
                    protected Object doInBackground(Object[] params) {
                        String xml = loadUrl("https://www.fake.site/GetCurrentUser");

                        return xml;
                    }

                    @Override
                    protected void onPostExecute(Object o) {
                        super.onPostExecute(o);
                        xmlTextView.setText(o.toString());
                    }
                };
                task.execute();
            }
        });
    }

    public String loadUrl(String url) {
        URI uri = MainActivity.encodeUrl(url);
        Log.i("XMLParser", "Get URL: " + url);

        String xml = null;
        URL link;
        BufferedReader reader = null;
        StringBuilder stringBuilder = null;
        InputStream is = null;
        HttpURLConnection connection = null;

        try {
            link = new URL(url);
            connection = (HttpURLConnection) link.openConnection();
            connection.setRequestMethod("GET");
            connection.connect();

            is = connection.getInputStream();
            reader = new BufferedReader(new InputStreamReader(is));
            stringBuilder = new StringBuilder();

            String line = null;
            while ((line = reader.readLine()) != null)
            {
                stringBuilder.append(line + "\r");
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    if(reader != null) reader.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                try {
                    if(is != null) is.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                try {
                    if(connection != null) connection.disconnect();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        try {
            xml = stringBuilder.toString();
        } catch(Exception e) {
            e.printStackTrace();
        }
        return xml;
    }

    public static URI encodeUrl(String url) {
        URL urlObject;
        URI uri = null;
        try {
            urlObject = new URL(url);
            uri = new URI(urlObject.getProtocol(), urlObject.getUserInfo(), urlObject.getHost(),
                    urlObject.getPort(), urlObject.getPath(), urlObject.getQuery(), urlObject.getRef());

        } catch (Exception e) {
            e.printStackTrace();
        }
        return uri;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

【问题讨论】:

  • 您的代码示例中有很多噪音。这一切都归结为保持连接打开(在您的 try 语句之后没有 finally 块),并且从根本上说您确实希望在应用程序的生命周期内拥有一个可访问的 http 授权资源。这个问题可以很好地消除所有不重要的想法,并清理 cmets。这是一个很好的问题!不过,读起来很丑;)干杯
  • 删除包/导入。将 catch 的 {e.printStackTrace();} 替换为 catch(忽略 XException){},删除日志语句,删除与问题无关的 cmets,最后添加与问题相关的 cmets。

标签: android httpurlconnection persistent-connection


【解决方案1】:

通过 Cookie 解决

经过数天/数小时的工作后,我发现与 HttpUrlConnection 的持久连接 (http.keepalive) 并不是想象中的那样:

1) 您需要确保 InputStreamHttpUrlConnection 已关闭,然后才能重用连接,即便如此它可能并不总是可重用。

2) 打开的 TCP 连接可能会占用资源。

在找到并测试了using cookies with HttpUrlConnection 的想法后,我决定走这条路,因为它从根本上说比我最初的想法更合理,性能也更好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-09
    • 2015-06-11
    • 2011-03-19
    • 1970-01-01
    • 1970-01-01
    • 2014-09-08
    • 1970-01-01
    相关资源
    最近更新 更多