I have a service running that uploads photos. I have a progressbar that is updated by NotificationManager, however its being called multipletimes.
IntentService[n identical 127 lines
How can I make it so that the manager only notifies when increments of 10% are uploaded?
#Override
public void writeTo(#NonNull BufferedSink sink) throws IOException {
long fileLength = mFile.length();
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
FileInputStream in = new FileInputStream(mFile);
long uploaded = 0;
int read;
while (is_uploading && (read = in.read(buffer)) != -1) {
int percent = 10* (int) (10 * uploaded / fileLength);
mManager.notify(NOTIFICATION_ID, uploadingProgressNotification(String.valueOf(current_image_uploading+1), percent + 10));
uploaded += read;
sink.write(buffer, 0, read);
}
}
Edit:
#Override
public void writeTo(#NonNull BufferedSink sink) throws IOException {
long fileLength = mFile.length();
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
FileInputStream in = new FileInputStream(mFile);
long uploaded = 0;
int read;
while (is_uploading && (read = in.read(buffer)) != -1) {
int percent = 10* (int) (10 * uploaded / fileLength);
if(percent % 10 == 0){
Log.d(TAG, "writeTo: test");
mManager.notify(NOTIFICATION_ID, uploadingProgressNotification(String.valueOf(current_image_uploading+1), percent + 10));
}
uploaded += read;
sink.write(buffer, 0, read);
}
}
The Log.d(TAG, "writeTo: test"); is still being called many times even though it should only be 10 times.
IntentService[n identical 346 lines
Use below code:
int percent = (int) (100 * uploaded / fileLength);
if(percent % 10 == 0 && lastPercent != percent){
lastPercent = percent;
mManager.notify(NOTIFICATION_ID, uploadingProgressNotification(String.valueOf(current_image_uploading+1), percent));
}
also create globle variable public int lastPercent = 0;
Related
I'm using NanoHttpd library in order to serve video files of type .mkv and .mp4 on Mi Video.
As the reading of the input stream was too slow, I changed NanoHttpd's reading buffer size to 1M:
private void sendBody(OutputStream outputStream, long pending) throws IOException {
long BUFFER_SIZE = 1048576L; // Instead of 16384
byte[] buff = new byte[(int)BUFFER_SIZE];
boolean sendEverything = pending == -1L;
while(pending > 0L || sendEverything) {
long bytesToRead = sendEverything ? BUFFER_SIZE : Math.min(pending, BUFFER_SIZE);
int read = this.data.read(buff, 0, (int)bytesToRead);
if (read <= 0) {
break;
}
outputStream.write(buff, 0, read);
if (!sendEverything) {
pending -= (long)read;
}
}
}
I changed inputStream.skip() the same way:
public long skip(long n) throws IOException {
long remaining = n;
int nr;
if (n <= 0) {
return 0;
}
int size = (int)Math.min(1048576L, remaining); \\ Instead of 2048
byte[] skipBuffer = new byte[size];
while (remaining > 0) {
nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
if (nr < 0) {
break;
}
remaining -= nr;
}
return n - remaining;
}
I override NanoHttpd.serve():
#Override
public Response serve(IHTTPSession session) {
... // Getting the inputStream, length and mimeType
String range = null;
for (String key : session.getHeaders().keySet()) {
if ("range".equals(key)) {
range = session.getHeaders().get(key);
}
}
if (null != range) {
return createPartialResponse(mimeType, inputStream, length, range);
} else {
return createFullResponse(mimeType, inputStream, length);
}
}
private Response createFullResponse(String mimeType, InputStream inputStream, long length) {
return newFixedLengthResponse(Response.Status.OK, mimeType, inputStream, length);
}
private Response createPartialResponse(String mimeType, InputStream inputStream, long length, String rangeHeader) throws IOException {
Response response = null;
String rangeValue = rangeHeader.trim().substring("bytes=".length());
long lastIndex = length - 1;
long startIndex, endIndex;
if (rangeValue.startsWith("-")) { // Range: bytes=-<suffix-length>
endIndex = lastIndex;
startIndex = lastIndex - Long.parseLong(rangeValue.substring("-".length()));
} else { // Range: bytes=<range-start>- OR bytes=<range-start>-<range-end> OR bytes=<range-start>-<range-end>, <range-start>-<range-end>
String[] range = rangeValue.split("-");
startIndex = Long.parseLong(range[0]);
endIndex = range.length > 1 ? Long.parseLong(range[1]) : lastIndex;
}
if (endIndex > lastIndex) {
endIndex = lastIndex;
}
if (startIndex <= endIndex) {
long newLength = endIndex - startIndex + 1;
inputStream.skip(startIndex);
response = newFixedLengthResponse(Response.Status.PARTIAL_CONTENT, mimeType, inputStream, newLength);
response.addHeader("Content-Length", String.valueOf(newLength));
response.addHeader("Content-Range", "bytes " + startIndex + "-" + endIndex + "/" + length); // "bytes start-end/length"
} else {
response = newFixedLengthResponse(Response.Status.RANGE_NOT_SATISFIABLE, MIME_PLAINTEXT, rangeHeader);
response.addHeader("Content-Range", "bytes 0-0/" + length); // "bytes 0-0/length"
}
response.addHeader("Accept-Ranges", "bytes"); // Announce that the file server accepts partial content requests
return response;
}
With Mi Video, small sizes of .mkv (98.5 MB) and .mp4 (77.9 MB) had to be read completely before they could be played (~15 seconds). But, large file sizes of nearly 1GB were played without reading the whole file.
I want to play both .mp4 and .mkv files with Mi Video without reading the whole file at the beginning no matter the size of the file.
I have a service running that uploads photos. Currently it's updating the progressbar every one percent. 1%...2%..3%...
How would I update it only at increments of 10%?
#Override
public void writeTo(#NonNull BufferedSink sink) throws IOException {
long fileLength = mFile.length();
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
FileInputStream in = new FileInputStream(mFile);
long uploaded = 0;
int read;
while ((read = in.read(buffer)) != -1) {
int percent = (int) (100 * uploaded / fileLength);
//Update progress bar
mManager.notify(NOTIFICATION_ID, uploadingProgressNotification(String.valueOf(current_image_uploading), percent));
uploaded += read;
sink.write(buffer, 0, read);
}
}
you can try this piece of code
int percent = 10 * (int) (10 * uploaded / fileLength);
dividing by 10 and casting to int will discard the decimal place for the digits.
you then multiply it by 10 to give you increments in steps of 10s.
This is my code, but the second split of the video is different, therefore when combining the split parts the video plays the first split but the second part it does not.
int bufferSize = (int) video_size_bytes;
byte[] buffer = new byte[bufferSize];
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
int len = 0;
try {
while ((len = inputStream.read(buffer)) != -1)
{
byteBuffer.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
Log.i(PostsActivity.TAG, "IOException: " + e.getMessage());
}
int offset = 0;
int addition = 100000;
int length = 100000;
int limit = (int) video_size_bytes;
boolean stop_loop = false;
boolean loop_mock = true;
do{
//Converting bytes into base64
String video_string_raw = Base64.encodeToString(byteBuffer.toByteArray(), offset, length, Base64.DEFAULT);
String video_string_raw_refined = video_string_raw.trim();
video_string = video_string_raw_refined.replaceAll("\n", "");
video_parts_array_string.add(video_string);
if(stop_loop){
break;
}
offset = offset + addition;
if((offset+addition) > limit){
length = limit-offset;
stop_loop = true;
}else{
offset = offset + addition;
}
}while(loop_mock);
Scenario :
Create request
**Interface**
#GET("someurl.mp4")
#Streaming
Call<ResponseBody> downloadFile(); // retrofit2.Call
**call**
RetrofitInterface retrofitInterface = retrofit.create(RetrofitInterface.class);
//okhttp3.ResponseBody
Call<ResponseBody> request = retrofitInterface.downloadFile();
try {
downloadFile(request.execute().body());
} catch (IOException e) {
e.printStackTrace();
}
Download bytes by bytes
private void downloadFile(ResponseBody body) throws IOException {
int count;
byte[] data;
data = new byte[1024 * 4];
long fileSize = body.contentLength();
Log.i("Download", "downloadFile: " + fileSize);
InputStream bis = new BufferedInputStream(body.byteStream(), 1024 * 8);
File outputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), System.currentTimeMillis() + ".mp4");
try (OutputStream output = new FileOutputStream(outputFile)) {
long total = 0;
long startTime = System.currentTimeMillis();
Log.i("Download", "downloadFile size: " + fileSize);
int timeCount = 1;
while ((count = bis.read(data)) != -1) {
total += count;
totalFileSize = (int) (fileSize / (Math.pow(1024, 2)));
double current = Math.round(total / (Math.pow(1024, 2)));
int progress = (int) ((total * 100) / fileSize);
long currentTime = System.currentTimeMillis() - startTime;
Download download = new Download();
download.setTotalFileSize(totalFileSize);
if (currentTime > 1000 * timeCount) {
download.setCurrentFileSize((int) current);
download.setProgress(progress);
sendNotification(download);
timeCount++;
}
if (download.getProgress() != 0)
Log.i("Download", "progress: " + download.getProgress());
output.write(data, 0, count);
}
onDownloadComplete();
output.flush();
//output.close();
}
bis.close();
}
Problem
I am not able to port above code in RxJava using Observable/Single interface.
All i want is to download file bytes by bytes for some purpose.
I tried to call downloadFile(request.execute().body()); inside ongoing async operation(RxJava) but didn't work as expected.
There is no good reason to declare method as returning Call<ResponseBody> if you are using RxJava anyway. Declare it as Single<ResponseBody> and use its result directly.
I'm using this code to download from a URL ,it works great with android 4,but in the other hand it doesn't work with android 2.3. Can someone tell what have i done wrong ?
URL url = new URL(sUrl);
URLConnection connection = url.openConnection();
connection.connect();
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(pathFolder+"/"+fileName);
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
publishProgress((int) (total * 100 / fileLength));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
It works for me. Here is my method:
private boolean dowloadFile(String url, File saveFile) {
int BUFF_SIZE = 1024 * 1024; //1Mo
long length = 0;
long current = 0;
if(saveFile.exists())
current = saveFile.length();
try {
DefaultHttpClient http = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
if(current>0)
request.addHeader("Range", "bytes=" + current + "-");
HttpResponse response = http.execute(request);
if (response.getStatusLine().getStatusCode() != 200 && response.getStatusLine().getStatusCode() != 206) {
return false;
}
Header[] headers = response.getHeaders("Content-Range");
if(headers.length>0) {
String s = headers[0].getValue();
length = Integer.valueOf(s.subSequence(s.indexOf("/")+1, s.length()).toString());
} else {
Header[] headers2 = response.getHeaders("Content-Length");
if(headers2.length>0)
length = Integer.valueOf(headers2[0].getValue());
if(current>0) {
saveFile.delete();
current = 0;
}
}
BufferedInputStream ls = new BufferedInputStream(response.getEntity().getContent());
long nexttime = 0;
RandomAccessFile fos = new RandomAccessFile(saveFile, "rw");
fos.seek(current);
byte[] buffer = new byte[BUFF_SIZE];
while (current < length) {
boolean buffFull = false;
int currentBuff = 0;
int readSize = 0;
while (buffFull == false) {
readSize = ls.read(buffer, currentBuff, BUFF_SIZE - currentBuff);
if (readSize == -1)
buffFull = true;
else {
currentBuff += readSize;
if (currentBuff == BUFF_SIZE)
buffFull = true;
}
}
fos.write(buffer, 0, currentBuff);
current += currentBuff;
long time = SystemClock.elapsedRealtime();
if (nexttime < time) {
// Progress
nexttime = time + 1000;
}
}
fos.close();
// Progress Finish
} catch(Exception e) {
e.printStackTrace();
return false;
}
return true;
}
I hope I have helped you !