2

我试图将图像从我的 sdcard 发送到 php 服务器......我创建了 2 个类:第一个是 MainActivity.java,第二个是 Base64.java,它以 Base64 格式编码字节。

我的 MainActivity.java 是:

public class MainActivity extends Activity {
    InputStream inputStream;
    @Override
public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.activity_main);

        Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/DCIM/Camera/1378889572299.jpg");
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 90, stream); //compress to which format you want.
        byte [] byte_arr = stream.toByteArray();
        String image_str = Base64.encodeBytes(byte_arr);
         ArrayList<NameValuePair> nameValuePairs = new  ArrayList<NameValuePair>();

        nameValuePairs.add(new BasicNameValuePair("image",image_str));
Log.e("ok", "1");
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://myserver.com/upload_image.php");
Log.e("ok", "3");
try {
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
Log.e("ok", "4");
HttpResponse response = httpclient.execute(httppost);
Log.e("ok", "5");

    String the_string_response = convertResponseToString(response);
} catch (IllegalStateException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

    }

    public String convertResponseToString(HttpResponse response) throws IllegalStateException, IOException{

        String res = "";
         StringBuffer buffer = new StringBuffer();
         inputStream = response.getEntity().getContent();
         final int contentLength = (int) response.getEntity().getContentLength(); //getting content length…..
          runOnUiThread(new Runnable() {

        @Override
        public void run() {
            Toast.makeText(MainActivity.this, "contentLength : " + contentLength, Toast.LENGTH_LONG).show();                    
        }
    });

         if (contentLength < 0){
         }
         else{
                byte[] data = new byte[512];
                int len = 0;
                try
                {
                    while (-1 != (len = inputStream.read(data)) )
                    {
                        buffer.append(new String(data, 0, len)); //converting to string and appending  to stringbuffer…..
                    }
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
                try
                {
                    inputStream.close(); // closing the stream…..
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
                res = buffer.toString();     // converting stringbuffer to string…..
                final String res2 = res;
                runOnUiThread(new Runnable() {

                @Override
                public void run() {
                   Toast.makeText(MainActivity.this, "Result : " + res2, Toast.LENGTH_LONG).show();
                }
            });
                //System.out.println("Response => " +  EntityUtils.toString(response.getEntity()));
         }
         return res;
    }
}

我有这个错误:

........OutOfMemoryError
….at java.lang.AbstractStringBuilder.(AbstractStringBuilder.java:81)
….at java.lang.StringBuilder.(StringBuilder.java:68)
….at java.net.URLEncoder.encode(URLEncoder.java:98)
….at org.apache.http.client.utils.URLEncodedUtils.encode(URLEncodedUtils.java:184)
….at org.apache.http.client.utils.URLEncodedUtils.format(URLEncodedUtils.java:163)
….at org.apache.http.client.entity.UrlEncodedFormEntity.(UrlEncodedFormEntity.java:71)
….at com.example.imageuploadonserver.MainActivity.onCreate(MainActivity.java:43)

第 43 行是:httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

我对我的代码进行了一些更改......并将图像源从我的 sdcard 替换为我的 drawabel.ic_luncher :

Bitmap bitmap = BitmapFactory.decodeFile(“/sdcard/DCIM/Camera/1378889572299.jpg”);

这样 :

Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);

它成功地工作了!!!!

我google了很多,但是要么我使用了错误的关键字,要么互联网上没有简单的解决方案。我希望这里有人可以帮助我。

最好的问候和提前感谢,法德尔。

4

4 回答 4

3

假设您的图像大约是 5Mo,因为它是您相机拍摄的照片。

  1. 当您将其加载为位图时,您的堆大小会增加 5Mo。
  2. 然后你将它转换为带有 som 压缩的字节数组,所以你的堆大小可能再次增长 4Mo => 9Mo
  3. 然后你base64encode它到一个字符串,堆再次增长4Mo => 13Mo
  4. 然后,通过将它作为字符串添加到 NameValu¨Pair 中,我认为它复制了字符串(这里不确定)并且堆再次增长 => 17Mo
  5. 然后当你将它添加为实体时,它会对内容进行编码并且堆再次增长=> 22Mo

当您不再需要它时,您应该尝试释放内存:

  1. 在第 2 步之后使用 bitmap.recycle()。
  2. 在第 3 步之后将您的咬合数组设置为 null
  3. 在第 4 步之后将您的字符串设置为 null(不确定)

这样做你会释放大约 9 到 14Mo

但在所有情况下,通过对其进行编码(base64Encode 或 UrlEncode),您的堆大小将增长为位图大小的两倍。更好的方法应该是将文件内容写入 HTTP 流将从文件中读取。

于 2013-09-11T16:47:33.293 回答
2

似乎您要上传的图像非常大。您需要在创建位图时将其缩小。您的 ic_launcher png 的分辨率非常低,因此在创建位图时不会造成任何问题。

检查此链接以有效加载位图 - http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

希望能帮助到你.. :)

于 2013-09-11T15:51:06.150 回答
0

为了避免一次将所有数据加载到内存中,我将使用ChunkedOutputStream 以块的形式流式传输数据。如果您对此小心,您可以上传无限大小的图像,因为它从来没有必要将整个东西都放在内存中。

于 2013-09-11T17:14:12.860 回答
0

When dealing with Client <-> Server WebServices, loading a whole request or response data into a String or any memory object is bad practice and should be avoided as much as possible. It's avoidable in many scenarios.

Why should it be avoided?

Because in many scenarios you never have any guarantee about the data's size and it will often lead you to OOM exceptions.

How should you do?

For most requests data, you can build it while you are sending it (XML, JSON, Whatever-serialization) and you don't need to reed the whole structure in memory to be able to serialize it.

For most answers data, you can parse the objects out of the stream and save it in you database or discard whatever part of the stream you don't need. Without loading the whole response as a String.

In your specific case, you have a File on disk that is an image you wish to compress. Use the standard library or whatever other image library to covert it to 90% JPEG to another file. Then you can stream the file directly to the httpPost.entity's output stream.

It's even probable that some libraries (maybe even the standard library?) offers you the possibility to get an InputStream with the compressed image directly from your first image file.

In both cases, encapsulate your first InputStream in another InputStream that does the Base64 conversion and you're there.

That way you'll never need to load more than a few kilobytes at a time into memory, for stream buffers.

于 2013-09-11T17:54:31.997 回答