视频文件上传到服务器安卓中的内存不足异常



在发布这个问题之前,我在堆栈溢出中搜索了很多,但找不到解决方案。其中一些是..

如何在服务器上上传大型视频?

安卓视频上传

在Android中上传大文件而不会出现内存不足错误

通过邮寄方式将文件上传到服务器内存不足

在安卓中上传文件,但出现内存不足错误 等。。。。。

我正在上传文件管理器/mfs_candidate_intro/65850 中的视频文件.mp4

现在主活动.java

package com.servicedemo;
import java.io.File;
import android.support.v7.app.ActionBarActivity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

    private String fpath;
    private String myfile;
    private static final String UPLOAD_URL = "http://www.ourgoalplan.com/CandidateIntroUploader.ashx";
    private int candidateID =65850; 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

   public void startMethod(View v) {
       fpath=setVideoOutPutFile();
       Intent i=new Intent(MainActivity.this,Uploadservice.class);
        i.putExtra("filepath", fpath);
        i.putExtra("uploadurl", UPLOAD_URL);
        i.putExtra("candidateID", candidateID);
        startService(i);
}

   private String setVideoOutPutFile()
    {
        File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), "/mfs_candidate_intro");
        if (!mediaStorageDir.exists())
        {
            if (!mediaStorageDir.mkdirs())
            {
                Log.d("VideoLogger", "failed to create directory");
            }
        }
        String path = Environment.getExternalStorageDirectory().getAbsolutePath();
        Log.e("external storagedirectory path= =", path);
        myfile = path + "/mfs_candidate_intro/" + candidateID + ".mp4";
        Log.e("external final file = =", myfile);
        return myfile;
    }

}

上传服务.java包含

package com.servicedemo;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import org.apache.commons.io.FileUtils;
import android.app.IntentService;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class Uploadservice extends IntentService{
    private String uploadURL;
    private int candidateID;
    private String FilePath;
    public Uploadservice() {      
        super("My service");
    }
    @Override
    public IBinder onBind(Intent intent) {
    return null;
    }

    @Override
    protected void onHandleIntent(Intent intent) {   //After completion of onstartcommand system will deliver all intent object to onHandleItent method.          
        uploadURL=intent.getExtras().getString("uploadurl");
        candidateID=intent.getExtras().getInt("candidateID");
        FilePath =intent.getExtras().getString("filepath");
        Log.d("Inside onhandleIntent", FilePath);
        try {
            uploadVideo(uploadURL,candidateID,FilePath);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public byte[] filecovert(String path)
    {
        return null;
    }
    public void uploadVideo(String iUploadUrl, int iCandidateId, String iFilePath) throws IOException
    {
        /**
         * converts the file in the specified path to byte Array
         */
        byte[] videobytes = convertFileToBytes(iFilePath);

        // Number of chunks in Bytes..
        final long chunkSize = 100000;
        // creates a new file in the specified path..
        File videoFile = new File(iFilePath);

        if (videobytes != null && videobytes.length > 0)
        {

            String requestUri = iUploadUrl + "?CandidateID=" + iCandidateId + "&fileName=" + videoFile.getName();
            // get the number of chunks
            long numOfChunks = (videobytes.length / chunkSize);
            byte[] byteArray = new byte[(int) chunkSize];
            /**
             * Get the remaining Bytes. /Check if there is some bytes remaining after calculation of numOfChunks
             */
            long remaingbytes = videobytes.length % chunkSize;
            if (remaingbytes > 0)
            {
                // Increase number of chunks by one if some bytes are left ...
                numOfChunks = numOfChunks + 1;
            }
            long copyBytesLength = chunkSize;
            for (int chunkNo = 1; chunkNo <= numOfChunks; chunkNo++)
            {
                String requestURL = requestUri + "&TotalChunks=" + numOfChunks + "&ChunkCounter=" + chunkNo;
                copyBytesLength = ((chunkNo * chunkSize) > videobytes.length) ? remaingbytes : chunkSize;
                byteArray = new byte[(int) copyBytesLength];
                System.arraycopy(videobytes, (int) ((chunkNo - 1) * chunkSize), byteArray, 0, (int) copyBytesLength);
                // send request to Handler
                if (requestHandler(numOfChunks, byteArray, chunkNo, requestURL))
                {
                    Log.e("SplashScreen", "Request Handler Returns False " + iCandidateId);
                    break;
                }
            }
        }
    }
    /**
     * This method provides the file data as byte array
     * 
     * @param iFilePath
     *            the path to the file
     * @return the corresponding byte array representation
     * @throws IOException
     */
    private byte[] convertFileToBytes(String iFilePath) throws IOException
    {
        return FileUtils.readFileToByteArray(new File(iFilePath));
    }
    /**
     * This method handles the division of byte array data into small chunks
     * 
     * @param iNumOfChunks
     *            number of chunks available after dividing data as separate 1 MB units
     * @param iByteArray
     *            the byte array representation of video data.
     * @param iChunkNum
     *            current chunk number
     * @param iRequestURL
     *            complete upload url
     * @return true/false based upon the success result.
     */
    private boolean requestHandler(long iNumOfChunks, byte[] iByteArray, int iChunkNum, String iRequestURL)
    {
        try
        {
            boolean valid = true;
            HttpURLConnection conn = null;
            DataOutputStream dos = null;
            DataInputStream inStream = null;
            URL url = new URL(iRequestURL);
            conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            dos = new DataOutputStream(conn.getOutputStream());
            // Writes iByteArray.length from IByteArray starting at offset 0 to the dos output stream.
            dos.write(iByteArray, 0, iByteArray.length);
            dos.flush();
            dos.close();
            // get the response code returned by the HTTP server...
            int responseCode = conn.getResponseCode();
            Log.e("SplashScreen", "Response code is " + responseCode);
            /**
             * If response code is OK ,Check if the iChunkNum == iNumOfChunks If it is equal ,it means Writting to th
             */
            if (responseCode == HttpURLConnection.HTTP_OK)
            {
                if (iChunkNum == iNumOfChunks)
                {
                    inStream = new DataInputStream(conn.getInputStream());
                    String str;
                    StringBuffer buf = new StringBuffer();
                    while ((str = inStream.readLine()) != null)
                    {
                        buf.append(str);
                    }
                    str = buf.toString();
                    Log.e("SplashScreen", "Server Response" + str);
                    inStream.close();
                }
                else
                {
                    valid = false;
                }
            }
            return valid;
        }
        catch (IOException e)
        {
            e.printStackTrace();
            return false;
        }
    }
 @Override
public void onDestroy() {
    Log.d("destroyed", "Intent destroyed");
    Toast.makeText(getApplicationContext(), "helloooooooooooo", Toast.LENGTH_LONG).show();
    super.onDestroy();
}
}

清单.xml包含..

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.servicedemo"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
         <service
             android:name=".Myservice"
             android:exported="false"
        />
         <service
             android:name=".Uploadservice"
             android:exported="false"
        />
    </application>

</manifest>

我的问题是当文件大小很大时,它会显示

12-02 18:36:35.944: E/dalvikvm-heap(21228): Out of memory on a 90981622-byte allocation.
12-02 18:36:35.944: I/dalvikvm(21228): "IntentService[My service]" prio=5 tid=11 RUNNABLE
12-02 18:36:35.944: I/dalvikvm(21228):   | group="main" sCount=0 dsCount=0 obj=0x41bb0780 self=0x5832c038
12-02 18:36:35.944: I/dalvikvm(21228):   | sysTid=21405 nice=0 sched=0/0 cgrp=apps handle=1479722576
12-02 18:36:35.944: I/dalvikvm(21228):   | schedstat=( 23006625 25262207 18 ) utm=2 stm=0 core=2
12-02 18:36:35.944: I/dalvikvm(21228):   at org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:~512)
12-02 18:36:35.944: I/dalvikvm(21228):   at org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:488)
12-02 18:36:35.944: I/dalvikvm(21228):   at org.apache.commons.io.FileUtils.readFileToByteArray(FileUtils.java:1764)
12-02 18:36:35.944: I/dalvikvm(21228):   at com.servicedemo.Uploadservice.convertFileToBytes(Uploadservice.java:126)
12-02 18:36:35.944: I/dalvikvm(21228):   at com.servicedemo.Uploadservice.uploadVideo(Uploadservice.java:68)
12-02 18:36:35.944: I/dalvikvm(21228):   at com.servicedemo.Uploadservice.onHandleIntent(Uploadservice.java:47)
12-02 18:36:35.944: I/dalvikvm(21228):   at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
12-02 18:36:35.944: I/dalvikvm(21228):   at android.os.Handler.dispatchMessage(Handler.java:99)
12-02 18:36:35.944: I/dalvikvm(21228):   at android.os.Looper.loop(Looper.java:137)
12-02 18:36:35.944: I/dalvikvm(21228):   at android.os.HandlerThread.run(HandlerThread.java:60)
12-02 18:36:35.949: W/dalvikvm(21228): threadid=11: thread exiting with uncaught exception (group=0x40e962a0)
12-02 18:36:35.954: E/AndroidRuntime(21228): FATAL EXCEPTION: IntentService[My service]
12-02 18:36:35.954: E/AndroidRuntime(21228): java.lang.OutOfMemoryError
12-02 18:36:35.954: E/AndroidRuntime(21228):    at org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:512)
12-02 18:36:35.954: E/AndroidRuntime(21228):    at org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:488)
12-02 18:36:35.954: E/AndroidRuntime(21228):    at org.apache.commons.io.FileUtils.readFileToByteArray(FileUtils.java:1764)
12-02 18:36:35.954: E/AndroidRuntime(21228):    at com.servicedemo.Uploadservice.convertFileToBytes(Uploadservice.java:126)
12-02 18:36:35.954: E/AndroidRuntime(21228):    at com.servicedemo.Uploadservice.uploadVideo(Uploadservice.java:68)
12-02 18:36:35.954: E/AndroidRuntime(21228):    at com.servicedemo.Uploadservice.onHandleIntent(Uploadservice.java:47)
12-02 18:36:35.954: E/AndroidRuntime(21228):    at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
12-02 18:36:35.954: E/AndroidRuntime(21228):    at android.os.Handler.dispatchMessage(Handler.java:99)
12-02 18:36:35.954: E/AndroidRuntime(21228):    at android.os.Looper.loop(Looper.java:137)
12-02 18:36:35.954: E/AndroidRuntime(21228):    at android.os.HandlerThread.run(HandlerThread.java:60)

问题出在里面

private byte[] convertFileToBytes(String iFilePath) throws IOException
    {
        return FileUtils.readFileToByteArray(new File(iFilePath));
    } 

它在上传服务中定义.java

另外,有必要使用

String requestURL = requestUri + "&TotalChunks=" + numOfChunks + "&ChunkCounter=" + chunkNo;

或者我们可以删除它???

这是因为您在上传之前将整个视频读入内存!这对于图像文件来说可能是可以的,但您不能假设您有足够的 RAM 来存储上传视频。

您需要将文件作为InputStream打开,并在从流中读取时上传。

您也可以使用MappedByteBuffer .我会使用流,但看起来MappedByteBuffer确实更接近您已有的代码。

最新更新