Android httpclient файл загрузки данных повреждения данных и времени ожидания
У меня проблемы с загрузкой изображений в Android.
я использую apache httpmime 4.1 lib код выглядит так:
MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
reqEntity.addPart("image", new FileBody(new File(AndorraApplication.getPhotosPath() + "/" + entity.getFileName()), "image/jpeg"));
resp = NetworkUtils.sendHttpRequestMultipart(EXPORT_PHOTOS_URI, reqEntity);
Класс NetworkUtils:
public class NetworkUtils {
public static final int REGISTRATION_TIMEOUT = 3 * 1000;
public static final int WAIT_TIMEOUT = 5 * 1000;
public static HttpResponse sendHttpRequestMultipart(String uri, MultipartEntity entity) {
HttpClient mHttpClient = new DefaultHttpClient();
final HttpParams params = mHttpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, WAIT_TIMEOUT);
ConnManagerParams.setTimeout(params, WAIT_TIMEOUT);
HttpPost post = new HttpPost(uri);
post.addHeader(entity.getContentType());
post.setEntity(entity);
HttpResponse resp = mHttpClient.execute(post);
}
}
иногда все работает нормально, но иногда (особенно при медленном соединении) изображение загружается очень поврежденным. пример здесь: http://pixelbirthcloud.com/574_orig.jpg
это не бросает никаких исключений. длина загруженного файла такая же, как и у исходного. Попытался изменить тип MIME на application / octet-stream или вообще удалить его. пытается играть с таймаутами. все тот же результат. Конечные пользователи загружают испорченные изображения почти все время (хотя мне удавалось получать изображения с броней только 2 раза). Сначала размер изображения составлял 2,5 мегабайта, но затем я уменьшил его до 500-700 кб. не решил проблему, хотя
Я не пытался изменить библиотеку apache.. может быть, это проблема... но, насколько я читал в сети, никто не испытывал это с библиотекой httpmime.
что это может быть? я полностью потерян сейчас:(
Другая проблема заключается в том, что время ожидания иногда не работает.
например, когда дело доходит до этой строки: HttpResponse resp = mHttpClient.execute(post); и я отключаю 3g соединение, оно просто ждет как 17-20 минут вместо 3 или 5 секунд.. и только потом выдает исключение. пробовал разные методы. как это:
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
HttpProtocolParams.setUseExpectContinue(params, false);
HttpConnectionParams.setConnectionTimeout(params, 10000);
HttpConnectionParams.setSoTimeout(params, 10000);
ConnManagerParams.setMaxTotalConnections(params, 5);
ConnManagerParams.setTimeout(params, 30000);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http",PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https",PlainSocketFactory.getSocketFactory(), 80));
ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(params, registry);
HttpClient httpclient = new DefaultHttpClient(manager, params);
но все равно не работает:)
3 ответа
См. Мой код загрузки изображений, и он отлично сработал для меня. Этот класс загружает файл на сервер и, в конце концов, также читает ответ XML. Отфильтруйте код согласно вашему требованию
package com.classifieds;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import android.util.Log;
public class Uploader
{
private String Tag = "UPLOADER";
private String urlString ;//= "YOUR_ONLINE_PHP";
HttpURLConnection conn;
String exsistingFileName ;
private void uploadImageData(String existingFileName , String urlString)
{
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
try {
// ------------------ CLIENT REQUEST
Log.e(Tag, "Inside second Method");
FileInputStream fileInputStream = new FileInputStream(new File(
exsistingFileName));
// open a URL connection to the Servlet
URL url = new URL(urlString);
// Open a HTTP connection to the URL
conn = (HttpURLConnection) url.openConnection();
// Allow Inputs
conn.setDoInput(true);
// Allow Outputs
conn.setDoOutput(true);
// Don't use a cached copy.
conn.setUseCaches(false);
// Use a post method.
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + boundary);
DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos
.writeBytes("Content-Disposition: post-data; name=uploadedfile;filename="
+ exsistingFileName + "" + lineEnd);
dos.writeBytes(lineEnd);
Log.v(Tag, "Headers are written");
// create a buffer of maximum size
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1000;
// int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bytesAvailable];
// read file and write it into form...
int bytesRead = fileInputStream.read(buffer, 0, bytesAvailable);
while (bytesRead > 0) {
dos.write(buffer, 0, bytesAvailable);
bytesAvailable = fileInputStream.available();
bytesAvailable = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bytesAvailable);
}
// send multipart form data necesssary after file data...
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// close streams
Log.v(Tag, "File is written");
fileInputStream.close();
dos.flush();
dos.close();
} catch (MalformedURLException ex) {
Log.e(Tag, "error: " + ex.getMessage(), ex);
}
catch (IOException ioe) {
Log.e(Tag, "error: " + ioe.getMessage(), ioe);
}
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = null;
try {
sp = spf.newSAXParser();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Get the XMLReader of the SAXParser we created.
XMLReader xr = null;
try {
xr = sp.getXMLReader();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Create a new ContentHandler and apply it to the XML-Reader
MyExampleHandler1 myExampleHandler = new MyExampleHandler1();
xr.setContentHandler(myExampleHandler);
// Parse the xml-data from our URL.
try {
xr.parse(new InputSource(conn.getInputStream()));
//xr.parse(new InputSource(new java.io.FileInputStream(new java.io.File("login.xml"))));
} catch (MalformedURLException e) {
Log.d("Net Disconnected", "NetDisconeeted");
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
Log.d("Net Disconnected", "NetDisconeeted");
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
Log.d("Net Disconnected", "NetDisconeeted");
// TODO Auto-generated catch block
e.printStackTrace();
}
// Parsing has finished.
}
public Uploader(String existingFileName, boolean isImageUploading , String urlString ) {
this.exsistingFileName = existingFileName;
this.urlString = urlString;
}
class MyExampleHandler1 extends DefaultHandler
{
// ===========================================================
// Methods
// ===========================================================
@Override
public void startDocument() throws SAXException {
}
@Override
public void endDocument() throws SAXException {
// Nothing to do
}
@Override
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException {
}
/** Gets be called on closing tags like:
* </tag> */
@Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
}
/** Gets be called on the following structure:
* <tag>characters</tag> */
@Override
public void characters(char ch[], int start, int length) {
}
}
}
У меня была такая же проблема с повреждением на 80% моих загруженных файлов. Эмулятор не преминул загрузить. Поврежденные файлы были на 1k больше оригинальных. Затем я установил буфер выходного потока в 1 байт, и он начал работать без проблем. Наконец, я допустил, что это будет 8 байт, и у меня больше не было проблем с коррупцией. Буфер около 80 или 50, я не помню, тоже вышел из строя. Не понимаю, в чем проблема, но я рад, что так работает. Эта страница была очень вдохновляющей.
Хорошо. потратил 2 дня на тестирование этой проблемы и выяснил следующее:
при использовании tcpdump на Android получается, что данные не были повреждены, НО размер пакета tcp был 1516, что очень странно, потому что нормальный размер пакета Ethernet равен 1500, а все, что больше 1516, слишком велико.
я вручную изменил MTU на 576 (я считаю, что это стандарт для ppp, который на самом деле является 3G), и он работает отлично! 150 из 150 изображений были загружены нормально!
это не решает реальной проблемы, потому что невозможно изменить mtu на некорневых устройствах, я считаю, и вы должны менять его каждый раз, когда вы перезагружаете устройство (или каждый раз, когда вы открываете интерфейс - не уверен насчет это, потому что не удалось найти способ получить значение MTU через ifconfig). но, по крайней мере, я знаю, где проблема.
установка меньшего значения размера фрагмента http (пробовал 300 байт) не повлияла на него (я полагаю, это потому, что заголовки http сами по себе слишком велики)... так что... ничего такого =)
постараюсь опубликовать его в группе разработчиков Android на Google, но их модерация слишком медленная... посмотрим...