由于Android开发人员recommend使用HttpURLConnection类,我想知道是否有人能给我提供一个很好的示例,说明如何通过POST将位图"文件"(实际上是内存流)发送到Apache HTTP服务器.我对cookie或身份验证或任何复杂的东西不感兴趣,但我只希望有一个可靠的、符合逻辑的实现.我在这里看到的所有例子看起来更像是"让我们试试这个,也许它会奏效".

现在,我有以下代码:

URL url;
HttpURLConnection urlConnection = null;
try {
    url = new URL("http://example.com/server.cgi");

    urlConnection = (HttpURLConnection) url.openConnection();

} catch (Exception e) {
    this.showDialog(getApplicationContext(), e.getMessage());
}
finally {
    if (urlConnection != null)
    {
        urlConnection.disconnect();
    }
}

其中showDialog应该只显示AlertDialog(如果URL无效?).

现在,假设我在从View派生的控件中生成一个位图,如:Bitmap image = this.getBitmap(),我想通过POST发送它.实现这一目标的正确程序是什么?我需要使用什么课程?我能用this example分之一的HttpPost吗?如果是这样的话,我将如何为我的位图构造InputStreamEntity?如果要求我先将位图存储在设备上的文件中,我会觉得很恶心.


我还应该提到,我真的需要将原始位图的每个未更改的像素发送到服务器,所以我不能将其转换为JPEG.

推荐答案

我不知道为什么HttpURLConnection类不提供任何方法来发送文件,而不必手动编写文件包装器.以下是我最后做的事情,但如果有人知道更好的解决方案,请告诉我.

输入数据:

Bitmap bitmap = myView.getBitmap();

静态素材:

String attachmentName = "bitmap";
String attachmentFileName = "bitmap.bmp";
String crlf = "\r\n";
String twoHyphens = "--";
String boundary =  "*****";

设置请求:

HttpURLConnection httpUrlConnection = null;
URL url = new URL("http://example.com/server.cgi");
httpUrlConnection = (HttpURLConnection) url.openConnection();
httpUrlConnection.setUseCaches(false);
httpUrlConnection.setDoOutput(true);

httpUrlConnection.setRequestMethod("POST");
httpUrlConnection.setRequestProperty("Connection", "Keep-Alive");
httpUrlConnection.setRequestProperty("Cache-Control", "no-cache");
httpUrlConnection.setRequestProperty(
    "Content-Type", "multipart/form-data;boundary=" + this.boundary);

启动内容包装器:

DataOutputStream request = new DataOutputStream(
    httpUrlConnection.getOutputStream());

request.writeBytes(this.twoHyphens + this.boundary + this.crlf);
request.writeBytes("Content-Disposition: form-data; name=\"" +
    this.attachmentName + "\";filename=\"" + 
    this.attachmentFileName + "\"" + this.crlf);
request.writeBytes(this.crlf);

Bitmap转换为ByteBuffer:

//I want to send only 8 bit black & white bitmaps
byte[] pixels = new byte[bitmap.getWidth() * bitmap.getHeight()];
for (int i = 0; i < bitmap.getWidth(); ++i) {
    for (int j = 0; j < bitmap.getHeight(); ++j) {
        //we're interested only in the MSB of the first byte, 
        //since the other 3 bytes are identical for B&W images
        pixels[i + j] = (byte) ((bitmap.getPixel(i, j) & 0x80) >> 7);
    }
}

request.write(pixels);

结束内容包装器:

request.writeBytes(this.crlf);
request.writeBytes(this.twoHyphens + this.boundary + 
    this.twoHyphens + this.crlf);

刷新输出缓冲区:

request.flush();
request.close();

获得回复:

InputStream responseStream = new 
    BufferedInputStream(httpUrlConnection.getInputStream());

BufferedReader responseStreamReader = 
    new BufferedReader(new InputStreamReader(responseStream));

String line = "";
StringBuilder stringBuilder = new StringBuilder();

while ((line = responseStreamReader.readLine()) != null) {
    stringBuilder.append(line).append("\n");
}
responseStreamReader.close();

String response = stringBuilder.toString();

关闭响应流:

responseStream.close();

关闭连接:

httpUrlConnection.disconnect();

PS:当然,为了让Android平台满意,我必须将请求包装成private class AsyncUploadBitmaps extends AsyncTask<Bitmap, Void, String>,因为它不喜欢在主线程上有网络请求.

Android相关问答推荐

Android compose ,在图像中zoom 而不裁剪?

Android库中的kotlinCompilerExtensionVersion

Android Studio -未显示布局预览(不推荐使用安全管理器)

如何在Jetpack Compose中实现前后动画?

在Android中使用Room从SQlite数据库中获取实体列表的正确方式是什么?

页面更改时不显示 cogo toast 消息

仅当先前输入为 yes 时,Android 才会要求下一个输入

任务:app:kaptGenerateStubsDebugKotlin执行失败. > 'compileDebugJavaWithJavac' 任务(当前目标是 1.8)

使用 settings.gradle 文件将 Firebase 依赖项添加到 Android 项目

修复错误 Invariant Violation: requireNativeComponent: "RNSScreenStackHeaderConfig" was not found in the UIManager

如何像 XML 一样在 Compose Android Studio 中折叠/展开小部件代码区域/区域

单击过go 的文章时 NewsApp 崩溃

如何在 Compose 中使用合并的单元格创建网格视图?

无法解析依赖项'com.github.smarteist:autoimageslider:1.4.0-appcompat'

如何在 Android 上移动 EditText 上的图标?

无法使用 Gradle 托管设备对基线配置文件运行测试

如何使用jetpack compose实现布局,其中图标在列布局上是绝对位置

WindowManager 内的 RecyclerView 不更新

EAS 构建失败,错误代码为 1,但 Expo Build 成功,我需要 EAS 构建来删除未使用的包,如 com.segment.analytics.android:analytics

如何在 flow.stateIn() 之后从流中的另一个函数发出emits ?