I'm developing an app that allows to users to upload mediafiles(such as images, photos, videos) to server and I've got a little bit problem with large files - is too long to wait and view a progress bar in activity while its uploading and another problem - if app dies upload dies too so I need to transfer my uploading code to service. So here my troubles begins - if I'll transfer my upload code to server how can I send progress updates(%) to activity?
here's my upload method's code:
public static void uploadMovie(final HashMap<String, String> dataSource, final OnResponseListener finishedListener, final ProgressListener progressListener) {
if (finishedListener != null) {
new Thread(new Runnable() {
public void run() {
try {
//Prepare data-->
String boundary = getMD5(dataSource.size() + String.valueOf(System.currentTimeMillis()));
MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create();
multipartEntity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
multipartEntity.setCharset(Charset.forName("UTF-8"));
for (String key : dataSource.keySet()) {
if (key.equals(MoviesFragmentAdd.USERFILE)) {
FileBody userFile = new FileBody(new File(dataSource.get(key)));
multipartEntity.addPart(key, userFile);
continue;
}
multipartEntity.addPart(key, new StringBody(dataSource.get(key), ContentType.APPLICATION_JSON));
}
HttpEntity entity = multipartEntity.build();
//<--
//Prepare Connection-->
trustAllHosts();
HttpsURLConnection conn = (HttpsURLConnection) new URL(SAKH_URL_API + "/video/addForm/").openConnection();
conn.setUseCaches(false);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Accept-Charset", "UTF-8");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
conn.setRequestProperty("Content-length", entity.getContentLength() + "");
conn.setRequestProperty(entity.getContentType().getName(), entity.getContentType().getValue());
conn.connect();
//<--
// Upload-->
OutputStream os = conn.getOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
entity.writeTo(baos);
baos.close();
byte[] payload = baos.toByteArray();
baos = null;
int totalSize = payload.length;
int bytesTransferred = 0;
int chunkSize = 2000;
while (bytesTransferred < totalSize) {
int nextChunkSize = totalSize - bytesTransferred;
if (nextChunkSize > chunkSize) {
nextChunkSize = chunkSize;
}
os.write(payload, bytesTransferred, nextChunkSize);
bytesTransferred += nextChunkSize;
//Progress update-->
if (progressListener != null) {
progressListener.onProgressUpdate((100 * bytesTransferred / totalSize));
}
//<--
}
os.flush();
//<--
//Get server response-->
int status = conn.getResponseCode();
if (conn.getResponseCode() == HttpsURLConnection.HTTP_OK) {
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
JsonObject request = (JsonObject) gparser.parse(in.readLine());
if (!request.get("error").getAsBoolean()) {
finishedListener.onLoadFinished(new Object());
}
} else {
throw new IOException("Server returned non-OK status: " + status);
}
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
finishedListener.onNotConnected();
}
}
}).start();
}
}
1-Create a bindable service and implement the necessary Binder
Start your service BEFORE binding to it or in other case if your app is closed the service will also close
2-Expose a public function like StartDownload(url, IUpdateTarget) on your service.
3-Create an interface (IUpdateTarget) with a function like UpdateProgress(somevalues);
4-Implement the IUpdateTarget interface in the View which should receive the update notifications
5-Bind to the service and retrieve the running service's instance
6-Now you have the instance of your service, call to StartDownload passing the URL and the target view for notifications.
7-Whenever you must update the interface from the service call to UpdateProgress from the IUpdateProgress instance passed to the service (the target view).
Beware with cross-threading calls, remember that you must always update interface on main thread.
Use Handler to send process
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
android.os.Message msg = new android.os.Message();
Bundle bundle = new Bundle();
bundle.putInt("process", process);
msg.setData(bundle);
mHandler.sendMessage(msg);
}
}).start();
Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
int process = msg.getData().getInt("process");
};
};
Related
I want to receive and send data with a web server but the code does not work
What do I do for this code to work?
Note this code inside onCreate
try {
URL url = new URL("http://myweb.com/");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
InputStream Stream = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(Stream);
BufferedReader b = new BufferedReader(reader);
StringBuilder s = new StringBuilder();
String str ="";
while ((str = b.readLine())!=null) {
s.append(str);
}
String data = s.toString();
TextView myText = (TextView) findViewById(R.id.Text);
myText.setText(data);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Make sure that you do network-related tasks on a separate thread in Android. Also, check that you have the INTERNET permission set.
If you want to then update the UI from another thread, you have to use
runOnUiThread (new Runnable () {
public void run() {
//update ui in here
}
}
All your code runs in Main thread which should be always used for setting up the UI and to listen for UI events such as on click listeners.
Network calls are not allowed on this thread as they might take long time. Use AsyncTask API of android which is designed for running code in separate thread.
Create a class like one below for all GET request tasks.
public class DownloadTask extends AsyncTask<String, Void, Integer> {
private String TAG = "InDownloadTask";
private DownloadCallback callback;
private String data;
public DownloadTask(DownloadCallback cb){
callback = cb;
}
#Override
protected Integer doInBackground(String... params) {
Integer result = 0;
HttpURLConnection urlConnection;
try {
URL url = new URL(params[0]);
urlConnection = (HttpURLConnection) url.openConnection();
int statusCode = urlConnection.getResponseCode();
if (statusCode == 200) {
BufferedReader r = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
response.append(line);
}
data = response.toString();
result = 1;
} else {
result = 0;
}
} catch (Exception e) {
Log.d(TAG, e.getLocalizedMessage());
}
return result;
}
#Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
callback.onFinishDownload(data, integer);
}
}
Create a callback interface that we use for the above class.
public interface DownloadCallback {
public void onFinishDownload(String data, Integer result);
}
Now from your activity onCreate
String url = "http://myweb.com/";
new DownloadTask(new DownloadCallback() {
public void onFinishDownload(String data, Integer result) {
if(result == 1)
myText.setText(data);
else
myText.setText("Error");
}
}).execute(url);
If you have many network related operations, use a Network library such as Volley which will take care of this.
The docs say AsyncTask is designed to handle short operations(few seconds maximum) and states that Java classes like FutureTask are better for operations that last long. So I tried to send my location updates to the server using FutureTask but I am getting NetworkOnMainThreadException. I don't want to use AsyncTask because I wanted to keep the http connection open until the updates are cancelled. Here is my code:
SendLocation updates = new SendLocation(idt, String.valueOf(location.getLatitude()), String.valueOf(location.getLongitude()));
FutureTask ft = new FutureTask<String>(updates);
boolean b = ft.cancel(false);
ft.run();
class SendLocation implements Callable<String> {
String t, la, lo;
public SendLocation(String a, String b, String c){
this.t = a;
this.la = b;
this.lo = c;
}
public String call() {
sendUpdates(token, la, lo);
return "Task Done";
}
public void sendUpdates(String a, String b, String c){
HttpURLConnection urlConn = null;
try {
try {
URL url;
//HttpURLConnection urlConn;
url = new URL(remote + "driver.php");
urlConn = (HttpURLConnection) url.openConnection();
System.setProperty("http.keepAlive", "true");
//urlConn.setDoInput(true); //this is for get request
urlConn.setDoOutput(true);
urlConn.setUseCaches(false);
urlConn.setRequestProperty("Content-Type", "application/json");
urlConn.setRequestProperty("Accept", "application/json");
urlConn.setRequestMethod("POST");
urlConn.connect();
try {
//Create JSONObject here
JSONObject json = new JSONObject();
json.put("drt", a);
json.put("drlat", b);
json.put("drlon", c);
String postData = json.toString();
// Send POST output.
OutputStreamWriter os = new OutputStreamWriter(urlConn.getOutputStream(), "UTF-8");
os.write(postData);
Log.i("NOTIFICATION", "Data Sent");
os.flush();
os.close();
BufferedReader reader = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
String msg = "";
String line = "";
while ((line = reader.readLine()) != null) {
msg += line;
}
Log.i("msg=", "" + msg);
} catch (JSONException jsonex) {
jsonex.printStackTrace();
Log.e("jsnExce", jsonex.toString());
}
} catch (MalformedURLException muex) {
// TODO Auto-generated catch block
muex.printStackTrace();
} catch (IOException ioex) {
ioex.printStackTrace();
try { //if there is IOException clean the connection and clear it for reuse(works if the stream is not too long)
int respCode = urlConn.getResponseCode();
InputStream es = urlConn.getErrorStream();
byte[] buffer = null;
int ret = 0;
// read the response body
while ((ret = es.read(buffer)) > 0) {
Log.e("streamingError", String.valueOf(respCode) + String.valueOf(ret));
}
// close the errorstream
es.close();
} catch(IOException ex) {
// deal with the exception
ex.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
Log.e("ERROR", "There is error in this code " + String.valueOf(e));
}
}
}
Doesn't it get executed in a worker thread? If the answer is no why does the docs say that it is an alternative to AsyncTask?
Your code must not be in the void run() method. This is where the asynchronous code is ran.
I am trying to convert the speech to text in android.In my project i am having two buttons namely Record and Stop.
If i click the record button the speech will be recorded from the user, after triggering the stop button recorded speech will be saved in FLAC format and then that sound will be send to Google API for transcription[ie., speech to text]
Well it is working fine, but it is taking much more time to convert the speech to text if the speech is too large.
Can any one please tell me how to increase the speed and performance of to show the text as soon as possible?
Suggestion please.
Thanks for your precious time!..
Please find the source for reference
MainActivity.java
public class MainActivity extends Activity {
String str_RecordFailed = "RECORD_FAILED";
// Language spoken
// Obs: It requires Google codes: English(en_us), Portuguese(pt_br), Spanish
// (es_es), etc
String language = "en_us";
// Key obtained through Google Developer group
String api_key = "AIzaSyBgnC5fljMTmCFeilkgLsOKBvvnx6CBS0M";
// Name of the sound file (.flac)
String fileName = Environment.getExternalStorageDirectory() + "/recording.flac";
// URL for Google API
String root = "https://www.google.com/speech-api/full-duplex/v1/";
String dwn = "down?maxresults=1&pair=";
String API_DOWN_URL = root + dwn;
String up_p1 = "up?lang=" + language
+ "&lm=dictation&client=chromium&pair=";
String up_p2 = "&key=";
// Variables used to establish return code
private static final long MIN = 10000000;
private static final long MAX = 900000009999999L;
long PAIR;
// Constants
private int mErrorCode = -1;
private static final int DIALOG_RECORDING_ERROR = 0;
// Rate of the recorded sound file
int sampleRate;
// Recorder instance
private Recorder mRecorder;
// Output for Google answer
TextView txtView;
Button recordButton, stopButton;//, listenButton;
// Handler used for sending request to Google API
Handler handler = new Handler();
// Recording callbacks
private Handler mRecordingHandler = new Handler(new Handler.Callback() {
public boolean handleMessage(Message m) {
switch (m.what) {
case FLACRecorder.MSG_AMPLITUDES:
FLACRecorder.Amplitudes amp = (FLACRecorder.Amplitudes) m.obj;
break;
case FLACRecorder.MSG_OK:
// Ignore
break;
case Recorder.MSG_END_OF_RECORDING:
break;
default:
mRecorder.stop();
mErrorCode = m.what;
showDialog(DIALOG_RECORDING_ERROR);
break;
}
return true;
}
});
// DOWN handler
Handler messageHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1: // GET DOWNSTREAM json id="#+id/comment"
String mtxt = msg.getData().getString("text");
if (mtxt.length() > 20) {
final String f_msg = mtxt;
handler.post(new Runnable() { // This thread runs in the UI
// TREATMENT FOR GOOGLE RESPONSE
#Override
public void run() {
String msg = null;
System.out.println("===transcript "+f_msg);
try {
JSONObject jsonObject = new JSONObject(f_msg);
JSONArray array = jsonObject.getJSONArray("result");
jsonObject = array.getJSONObject(0);
JSONArray array2 =jsonObject.getJSONArray("alternative");
jsonObject = array2.getJSONObject(0);
msg = jsonObject.getString("transcript");
System.out.println("===transcript "+msg);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
txtView.setText(msg);
}
});
}
break;
case 2:
break;
}
}
}; // doDOWNSTRM Handler end
// UPSTREAM channel. its servicing a thread and should have its own handler
Handler messageHandler2 = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1: // GET DOWNSTREAM json
Log.d("ParseStarter", msg.getData().getString("post"));
break;
case 2:
Log.d("ParseStarter", msg.getData().getString("post"));
break;
}
}
}; // UPstream handler end
/**************************************************************************************************************
* Implementation
**/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtView = (TextView) this.findViewById(R.id.txtView);
recordButton = (Button) this.findViewById(R.id.record);
stopButton = (Button) this.findViewById(R.id.stop);
stopButton.setEnabled(false);
// listenButton = (Button) this.findViewById(R.id.listen);
// listenButton.setEnabled(false);
mRecorder = new Recorder(this, mRecordingHandler);
}
/***************************************************************************************************************
* Method related to recording in FLAC file
*/
/*Thread th = new Thread()
{
public void run() {
};
};*/
public void recordButton(View v) {
mRecorder.start(fileName);
txtView.setText("");
recordButton.setEnabled(false);
stopButton.setEnabled(true);
Toast.makeText(getApplicationContext(), "Recording...",Toast.LENGTH_LONG).show();
/*sampleRate = mRecorder.mFLACRecorder.getSampleRate();
getTranscription(sampleRate);
mRecorder.stop();*/
}
/***************************************************************************************************************
* Method that stops recording
*/
public void stopRecording(View v) {
Toast.makeText(getApplicationContext(), "Loading...", Toast.LENGTH_LONG).show();
sampleRate = mRecorder.mFLACRecorder.getSampleRate();
getTranscription(sampleRate);
mRecorder.stop();
stopButton.setEnabled(false);
recordButton.setEnabled(true);
}
/***************************************************************************************************************
* Method that listens to recording
*/
public void listenRecord(View v) {
Context context = this;
FLACPlayer mFlacPlayer = new FLACPlayer(context, fileName);
mFlacPlayer.start();
}
/**************************************************************************************************************
* Method related to Google Voice Recognition
**/
public void getTranscription(int sampleRate) {
File myfil = new File(fileName);
if (!myfil.canRead())
{
Log.d("ParseStarter", "FATAL no read access");
Toast.makeText(MainActivity.this, "Sorry : Unable to convert the recorded voice", Toast.LENGTH_LONG).show();
}
// first is a GET for the speech-api DOWNSTREAM
// then a future exec for the UPSTREAM / chunked encoding used so as not
// to limit
// the POST body sz
PAIR = MIN + (long) (Math.random() * ((MAX - MIN) + 1L));
// DOWN URL just like in curl full-duplex example plus the handler
downChannel(API_DOWN_URL + PAIR, messageHandler);
// UP chan, process the audio byteStream for interface to UrlConnection
// using 'chunked-encoding'
FileInputStream fis;
try {
fis = new FileInputStream(myfil);
FileChannel fc = fis.getChannel(); // Get the file's size and then
// map it into memory
int sz = (int) fc.size();
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, sz);
byte[] data2 = new byte[bb.remaining()];
Log.d("ParseStarter", "mapfil " + sz + " " + bb.remaining());
bb.get(data2);
// conform to the interface from the curl examples on full-duplex
// calls
// see curl examples full-duplex for more on 'PAIR'. Just a globally
// uniq value typ=long->String.
// API KEY value is part of value in UP_URL_p2
upChannel(root + up_p1 + PAIR + up_p2 + api_key, messageHandler2,
data2);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void downChannel(String urlStr, final Handler messageHandler) {
final String url = urlStr;
new Thread() {
Bundle b;
public void run() {
String response = "NAO FOI";
Message msg = Message.obtain();
msg.what = 1;
// handler for DOWN channel http response stream - httpsUrlConn
// response handler should manage the connection.... ??
// assign a TIMEOUT Value that exceeds by a safe factor
// the amount of time that it will take to write the bytes
// to the UPChannel in a fashion that mimics a liveStream
// of the audio at the applicable Bitrate. BR=sampleRate * bits
// per sample
// Note that the TLS session uses
// "* SSLv3, TLS alert, Client hello (1): "
// to wake up the listener when there are additional bytes.
// The mechanics of the TLS session should be transparent. Just
// use
// httpsUrlConn and allow it enough time to do its work.
Scanner inStream = openHttpsConnection(url);
// process the stream and store it in StringBuilder
while (inStream.hasNextLine()) {
b = new Bundle();
b.putString("text", inStream.nextLine());
msg.setData(b);
messageHandler.dispatchMessage(msg);
}
}
}.start();
}
private void upChannel(String urlStr, final Handler messageHandler,
byte[] arg3) {
final String murl = urlStr;
final byte[] mdata = arg3;
Log.d("ParseStarter", "upChan " + mdata.length);
new Thread() {
public void run() {
String response = "NAO FOI";
Message msg = Message.obtain();
msg.what = 2;
Scanner inStream = openHttpsPostConnection(murl, mdata);
inStream.hasNext();
// process the stream and store it in StringBuilder
while (inStream.hasNextLine()) {
response += (inStream.nextLine());
Log.d("ParseStarter", "POST resp " + response.length());
}
Bundle b = new Bundle();
b.putString("post", response);
msg.setData(b);
// in.close(); // mind the resources
messageHandler.sendMessage(msg);
}
}.start();
}
// GET for DOWNSTREAM
private Scanner openHttpsConnection(String urlStr) {
InputStream in = null;
int resCode = -1;
Log.d("ParseStarter", "dwnURL " + urlStr);
try {
URL url = new URL(urlStr);
URLConnection urlConn = url.openConnection();
if (!(urlConn instanceof HttpsURLConnection)) {
throw new IOException("URL is not an Https URL");
}
HttpsURLConnection httpConn = (HttpsURLConnection) urlConn;
httpConn.setAllowUserInteraction(false);
// TIMEOUT is required
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
resCode = httpConn.getResponseCode();
if (resCode == HttpsURLConnection.HTTP_OK) {
return new Scanner(httpConn.getInputStream());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
// GET for UPSTREAM
private Scanner openHttpsPostConnection(String urlStr, byte[] data) {
InputStream in = null;
byte[] mextrad = data;
int resCode = -1;
OutputStream out = null;
// int http_status;
try {
URL url = new URL(urlStr);
URLConnection urlConn = url.openConnection();
if (!(urlConn instanceof HttpsURLConnection)) {
throw new IOException("URL is not an Https URL");
}
HttpsURLConnection httpConn = (HttpsURLConnection) urlConn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("POST");
httpConn.setDoOutput(true);
httpConn.setChunkedStreamingMode(0);
httpConn.setRequestProperty("Content-Type", "audio/x-flac; rate="
+ sampleRate);
httpConn.connect();
try {
// this opens a connection, then sends POST & headers.
out = httpConn.getOutputStream();
// Note : if the audio is more than 15 seconds
// dont write it to UrlConnInputStream all in one block as this
// sample does.
// Rather, segment the byteArray and on intermittently, sleeping
// thread
// supply bytes to the urlConn Stream at a rate that approaches
// the bitrate ( =30K per sec. in this instance ).
Log.d("ParseStarter", "IO beg on data");
out.write(mextrad); // one big block supplied instantly to the
// underlying chunker wont work for duration
// > 15 s.
Log.d("ParseStarter", "IO fin on data");
// do you need the trailer?
// NOW you can look at the status.
resCode = httpConn.getResponseCode();
Log.d("ParseStarter", "POST OK resp "
+ httpConn.getResponseMessage().getBytes().toString());
if (resCode / 100 != 2) {
Log.d("ParseStarter", "POST bad io ");
}
} catch (IOException e) {
Log.d("ParseStarter", "FATAL " + e);
}
if (resCode == HttpsURLConnection.HTTP_OK) {
Log.d("ParseStarter", "OK RESP to POST return scanner ");
return new Scanner(httpConn.getInputStream());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}}
On same concept am working and same thing is happening with me in different manner. i mean when am trying to record audio more than 40 second it is not giving me output . But below than 40 sec it gives me proper output when recording length is high it mean your FLAC file size is big thats why it takes time so as per my research i found way to reduce the size of recording file by changing frequency of recording but there is disadvantage of it when you decrease the frequency the result may vary i mean it may not be accurate as compare to high frequency recording clip
so here is my suggestion to you to increase performance (But result will may varies due to this suggestion)
go into FLACRecorder.java file and in run() method use this line
final int sample_rates[] = { 8000 };
instead of
final int sample_rates[] = { 44100, 22050, 11025, 8000 };
it means During recording your sample rate will be 8000 which is very low so your recorded file size will be low and due to this it will fastly get uploaded on google server for voice recognition and performance will get improve hope this will help you
I want to check progress of uploading file by HttpUrlConnection. How I can do this? I've tried to calculate bytes when writing data in OutputStream but it's wrong, cause real uploading happens only when I call conn.getInputStream(), so I need somehow to check inputStream. Here is my code:
public static void uploadMovie(final HashMap<String, String> dataSource, final OnLoadFinishedListener finishedListener, final ProgressListener progressListener) {
if (finishedListener != null) {
new Thread(new Runnable() {
public void run() {
try {
String boundary = getMD5(dataSource.size()+String.valueOf(System.currentTimeMillis()));
MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create();
multipartEntity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
multipartEntity.setCharset(Charset.forName("UTF-8"));
for (String key : dataSource.keySet()) {
if (key.equals(MoviesFragmentAdd.USERFILE)) {
FileBody userFile = new FileBody(new File(dataSource.get(key)));
multipartEntity.addPart(key, userFile);
continue;
}
multipartEntity.addPart(key, new StringBody(dataSource.get(key),ContentType.APPLICATION_JSON));
}
HttpEntity entity = multipartEntity.build();
HttpURLConnection conn = (HttpsURLConnection) new URL(URL_API + "/video/addForm/").openConnection();
conn.setUseCaches(false);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Accept-Charset", "UTF-8");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Cache-Control", "no-cache");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
conn.setRequestProperty("Content-length", entity.getContentLength() + "");
conn.setRequestProperty(entity.getContentType().getName(),entity.getContentType().getValue());
OutputStream os = conn.getOutputStream();
entity.writeTo(os);
os.close();
//Real upload starting here -->>
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
//<<--
JsonObject request = (JsonObject) gparser.parse(in.readLine());
if (!request.get("error").getAsBoolean()) {
//do something
}
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
Because you have to deal with upload, I'd suppose most time is taken when doing entity.writeTo(os);. Maybe the first contact to the server takes some time as well (DNS resolution, SSL-handshake, ...). The markers you set for "the real upload" are not correct IMO.
Now it depends on your Multipart-library, whether you can intercept writeTo. If it is clever and resource-efficient, it's iterating over the parts and streams the content one-by-one to the output stream. If not, and the .build() operation is creating a big fat byte[], then you could take this array, stream it in chunks to the server and tell your user how many percent of the upload is already done.
From a resource perspective I'd prefer not really knowing what happens. But if feedback is that important and if the movies are only a few megabytes in size, you could stream the Multipart-Entity first to a ByteArrayOutputStream and then write little chunks of the created byte-array to the server while notifying your user about progress. The following code is not validated or tested (you can see it as pseudo-code):
ByteArrayOutputStream baos = new ByteArrayOutputStream();
entity.writeTo(baos);
baos.close();
byte[] payload = baos.toByteArray();
baos = null;
OutputStream os = conn.getOutputStream();
int totalSize = payload.length;
int bytesTransferred = 0;
int chunkSize = 2000;
while (bytesTransferred < totalSize) {
int nextChunkSize = totalSize - bytesTransferred;
if (nextChunkSize > chunkSize) {
nextChunkSize = chunkSize;
}
os.write(payload, bytesTransferred, nextChunkSize); // TODO check outcome!
bytesTransferred += nextChunkSize;
// Here you can call the method which updates progress
// be sure to wrap it so UI-updates are done on the main thread!
updateProgressInfo(100 * bytesTransferred / totalSize);
}
os.close();
A more elegant way would be to write an intercepting OutputStream which registers progress and delegates the real write-operations to the underlaying "real" OutputStream.
Edit
#whizzzkey wrote:
I've re-checked it many times - entity.writeTo(os) DOESN'T do a real upload, it does conn.getResponseCode() or conn.getInputStream()
Now it's clear. HttpURLConnection is buffering your upload data, because it doesn't know the content-length. You've set the header 'Content-length', but oviously this is ignored by HUC. You have to call
conn.setFixedLengthStreamingMode(entity.getContentLength());
Then you should better remove the call to conn.setRequestProperty("Content-length", entity.getContentLength() + "");
In this case, HUC can write the headers and entity.writeTo(os) can really stream the data to the server. Otherwise the buffered data is sent when HUC knows how many bytes will be transferred. So in fact, getInputStream() tells HUC that you're finished, but before really reading the response, all the collected data has to be sent to the server.
I wouldn't recommend changing your code, but for those of you who don't know the exact size of the transferred data (in bytes, not characters!!), you can tell HUC that it should transfer the data in chunks without setting the exact content-length:
conn.setChunkedStreamingMode(-1); // use default chunk size
Right this code in your activity...
public class PublishPostToServer extends AsyncTask implements
ProgressListenerForPost {
public Context pContext;
public long totalSize;
private String response;
public PublishPostToServer(Context context) {
pContext = context;
}
protected void onPreExecute() {
showProgressDialog();
}
#Override
protected Boolean doInBackground(Void... params) {
boolean success = true;
try {
response = NetworkAdaptor.getInstance()
.upLoadMultipartImageToServer(
"",
"",
"", this, this); // Add file path, Authkey, caption
} catch (Exception e) {
success = false;
}
return success;
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
//validateResponse(result, response);
}
#Override
protected void onProgressUpdate(Integer... values) {
try {
if (mProgressDialog != null) {
mProgressDialog.setProgress(values[0]);
}
} catch (Exception exception) {
}
}
#Override
public void transferred(long num) {
publishProgress((int) ((num / (float) totalSize) * 100));
}
}
private void showProgressDialog() {
try {
String dialogMsg = "Uploading Image...";
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setMessage(dialogMsg);
mProgressDialog.setIndeterminate(false);
mProgressDialog.setMax(100);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(false);
mProgressDialog.show();
} catch (Exception exception) {
}
}
Now, Make a NetworkAdapter Class
public String upLoadMultipartImageToServer(String sourceFileUri,
String auth_key, String caption, ProgressListenerForPost listiner,
PublishPostToServer asyncListiner) {
String upLoadServerUri = "" + "upload_image";
HttpPost httppost = new HttpPost(upLoadServerUri);
File file = new File(sourceFileUri);
if (file.exists()) {
FileBody filebodyVideo = new FileBody(file);
CustomMultiPartEntity multipartEntity = new CustomMultiPartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE, listiner);
try {
multipartEntity.addPart("auth_key", new StringBody(auth_key));
multipartEntity.addPart("caption", new StringBody(caption));
multipartEntity.addPart("image", filebodyVideo);
asyncListiner.totalSize = multipartEntity.getContentLength();
httppost.setEntity(multipartEntity);
}
catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
DefaultHttpClient mHttpClient = new DefaultHttpClient();
String response = "";
try {
response = mHttpClient.execute(httppost,
new MovieUploadResponseHandler());
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return response;
} else {
return null;
}
}
#SuppressWarnings("rawtypes")
private class MovieUploadResponseHandler implements ResponseHandler {
#Override
public Object handleResponse(HttpResponse response)
throws ClientProtocolException, IOException {
HttpEntity r_entity = response.getEntity();
String responseString = EntityUtils.toString(r_entity);
// DebugHelper.printData("UPLOAD", responseString);
return responseString;
}
}
public static boolean isValidResponse(String resultData) {
try {
} catch (Exception exception) {
//DebugHelper.printException(exception);
}
return true;
}
public String upLoadVideoToServer(String currentFilePath, String string,
PublishPostToServer publishPostToServer,
PublishPostToServer publishPostToServer2) {
// TODO Auto-generated method stub
return null;
}
My android application always gets stuck when downloading a file until the downloading is finished. However,the downloading thread is inherited from AyncTask and it is in background. Can anyone have a look and see what is wrong and how can i modify the code in order for it to work?
private class DownloadFileTask extends AsyncTask<String, Integer, String> {
File destFile;
private boolean openAfterDownload;
private Exception failure;
public DownloadFileTask(boolean openAfterDownload) {
this.openAfterDownload = openAfterDownload;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
downloadDialog.setMessage(getString(R.string.downloading));
downloadDialog.show();
}
#Override
protected String doInBackground(String... params) {
try {
String url = params[0];
LOG.debug("Downloading: " + url);
String fileName = url.substring(url.lastIndexOf('/') + 1);
HttpParams httpParams = new BasicHttpParams();
DefaultHttpClient client = new DefaultHttpClient(httpParams);
client.getCredentialsProvider().setCredentials(
new AuthScope(null, -1),
new UsernamePasswordCredentials(user, password));
HttpGet get = new HttpGet(url);
HttpResponse response = client.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
File destFolder = new File(config.getDownloadsFolder());
if (!destFolder.exists()) {
destFolder.mkdirs();
}
/**
* Make sure we always store downloaded files as .epub,
* so they show up in scans later on.
*/
if ( ! fileName.endsWith(".epub") ) {
fileName = fileName + ".epub";
}
destFile = new File(destFolder, URLDecoder.decode(fileName));
if (destFile.exists()) {
destFile.delete();
}
// lenghtOfFile is used for calculating download progress
long lenghtOfFile = response.getEntity().getContentLength();
if(lenghtOfFile>=config.getAvailableSpace())
{
this.failure = new Exception("not enough space");
return null;
}
// this is where the file will be seen after the download
FileOutputStream f = new FileOutputStream(destFile);
try {
// file input is from the url
InputStream in = response.getEntity().getContent();
// here's the download code
byte[] buffer = new byte[1024];
int len1 = 0;
long total = 0;
while ((len1 = in.read(buffer)) > 0) {
// Make sure the user can cancel the download.
if (isCancelled()) {
return null;
}
total += len1;
publishProgress((int) ((total * 100) / lenghtOfFile));
f.write(buffer, 0, len1);
}
} finally {
f.close();
}
} else {
this.failure = new RuntimeException(response
.getStatusLine().getReasonPhrase());
LOG.error("Download failed: "
+ response.getStatusLine().getReasonPhrase());
}
} catch (Exception e) {
Toast.makeText(getActivity(), e.getMessage() + "1",
Toast.LENGTH_LONG).show();
LOG.error("Download failed.", e);
this.failure = e;
}
return null;
}
Although you are running your task in an AsyncTask but you have those lines of code:
downloadDialog.setMessage(getString(R.string.downloading));
downloadDialog.show();
in your onPreExecute() method, which basically will start a DialogBox before the task it self starts.
What more I don't see the onPostExecute() method in your implementation. so you are never .dismiss() the dialog. But even if you did you are application still would be 'stack' (normal behavior) with this dialog until the download finishes.