Interrupt download which uses dataInputStream - android

Have a pretty simple code for download file.
class Downloader {
private static Downloader Dinstance = null;
private boolean isAborted = false;
void setAborted(boolean isAborted) {
isAborted = true;
}
int getAborted() {
return isAborted;
}
static Downloader getInstance(#NonNull Context context) {
if (Dinstance == null)
Dinstance = new Downloaderr(context.getApplicationContext());
return Dinstance;
}
private Downloader() {
...
}
function download() {
...
try {
URL url = new URL(RequestedURL);
InputStream inputStream = url.openStream();
DataInputStream dataInputStream = new DataInputStream(inputStream);
FileOutputStream fileOutputStream = new FileOutputStream(FileName);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = dataInputStream.read(buffer)) > 0) {
fileOutputStream.write(buffer, 0, bytesRead);
if (getAborted()) {
Log.d(static_variables.TAG, "Aborting 1");
fileOutputStream.close();
Log.d(static_variables.TAG, "Aborting 2");
dataInputStream.close();
Log.d(static_variables.TAG, "Aborting 3");
inputStream.close();
Log.d(static_variables.TAG, "All closed");
file.delete();
downloadFinished = true;
Log.d(static_variables.TAG, "Returning");
return false;
}
fileOutputStream.close();
dataInputStream.close();
inputStream.close();
} catch (IOException e) {
downloadFinished = true;
return false;
}
...
}
}
In MainActivity
First button listener(start download):
function onClick() {
new Thread(new Runnable() {
#Override
public void run() {
Downloader.getInstance().download(...);
}
}).start();
}
Second button listener:
function onClick() {
Downloader.getInstance().setAborted(true);
}
Download going in thread.
In logs time for dataInputStream.close(); is biggest. And other research shows that streams won't close before file will be fully downloaded.
How I can terminate InputStream in progress?

During research I found two things.
Download aborts with this approach, but there is a buffer and for small files(songs, in my case) it's almost untrackable. For 500Mb file download, when you press abort on 15Mb downloaded, then after 16-17 it will stop.
If you want(as I am) terminate download faster, then you should use another approach. When starting Thread, save pointer int variable.
Thread threadDownload = new Thread(...);
threadDownload.start();
then abort using
threadDownload.interrupt();
Beware. You'll need remove temporary file by yourself. File which you use in OutputStream.
You also will have some buffer overhead, but it will be not 1-2Mb, but 200-300Kb.

Related

how to and input files to apk that can be read from C++?

I use JNI to develop my app, and there are two .dat files used as input files in C++ layer. At present, I push these two files into mobile devices through adb before open related app. I think there is a better solution to prevent from pushing two files into mobile devices.
after trying several solutions, I have solved it by combining three solutions, and the code shown below. Before using the code, you need to create a folder called "assets" parallel to "res" folder. Through this way, you can attach the input file you may use to the apk, and when installing the apk first time, it will automatically store the files to specific path in the target device.
public class CameraPreviewActivity extends AppCompatActivity
implements CameraPermissionHelper.CameraPermissionCallback {
SharedPreferences prefs = null;
public static String TAG = "CameraPreviewActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prefs = getSharedPreferences("com.yourcompany.yourapp", MODE_PRIVATE);
}
#Override
protected void onDestroy() {
super.onDestroy();
}
#Override
protected void onResume() {
super.onResume();
if(prefs.getBoolean("firstrun", true)){
prefs.edit().putBoolean("firstrun", false).commit();
try {
final InputStream input = getResources().getAssets().open("face_model.dat");
try {
File UPLOAD_DIR = new File("/sdcard");
File file = new File(UPLOAD_DIR, "face_model.dat");
OutputStream output = new FileOutputStream(file);
try {
try {
byte[] buffer = new byte[4 * 1024]; // or other buffer size
int read;
while ((read = input.read(buffer)) != -1) {
output.write(buffer, 0, read);
}
output.flush();
} finally {
output.close();
}
} catch (Exception e) {
e.printStackTrace(); // handle exception, define IOException and others
}
} finally {
input.close();
}
}catch (IOException e){
e.printStackTrace();
}
try {
final InputStream input = getResources().getAssets().open("shape_pred.dat");
try {
File UPLOAD_DIR = new File("/sdcard");
File file = new File(UPLOAD_DIR, "shape_pred.dat");
OutputStream output = new FileOutputStream(file);
try {
try {
byte[] buffer = new byte[4 * 1024]; // or other buffer size
int read;
while ((read = input.read(buffer)) != -1) {
output.write(buffer, 0, read);
}
output.flush();
} finally {
output.close();
}
} catch (Exception e) {
e.printStackTrace(); // handle exception, define IOException and others
}
} finally {
input.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
}

Socket recieves Images with delay of 1

I have a socket that recieves images via one InputStream that doesnt get closed. I want to send images continiously that way. But now the images get recieved with a delay of 1 image (the first one after I sent the second one, the second one after I sent the third one, ....). What am I doing wrong?
Server
public static void readImages(InputStream stream) throws IOException {
stream = new BufferedInputStream(stream);
BufferedImage image = null;
int j = 0;
while (true) {
stream.mark(MAX_IMAGE_SIZE);
ImageInputStream imgStream = ImageIO.createImageInputStream(stream);
Iterator<ImageReader> i = ImageIO.getImageReaders(imgStream);
if (!i.hasNext()) {
System.out.println("No more image readers");
break;
}
ImageReader reader = i.next();
reader.setInput(imgStream);
image = reader.read(0);
ImageIO.write(image,"jpg",new File("current" + j + ".jpg"));
System.out.println("Save an image " + j);
if (image == null) {
System.out.println("Image is null");
break;
}
long bytesRead = imgStream.getStreamPosition();
stream.reset();
stream.skip(bytesRead);
j++;
}
}
Client
new Thread(new Runnable() {
#Override
public void run() {
try {
OutputStream outputStream = server.getOutputStream();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmapToSend = Bitmap.createScaledBitmap(bitmapToSend, 900, 800, true);
bitmapToSend.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] byteArray = stream.toByteArray();
outputStream.write(byteArray);
outputStream.flush();
} catch (IOException e) {
System.out.println("Socket not created");
e.printStackTrace();
}
}
}).start();
Note I dont close the output stream of the client, so I can send pictures all the time.
Using ImageIO.getImageReaders(imgStream) doesn't seem logical for socket streams, since it probably expects all images to be available at once. That may be the reason of your delay.
Secondly, for decompressing images there is a simple method BitmapFactory.decodeStream().
Thirdly, since client already creates a "JPG" format, the server just needs to store it. You only need to send at start the number of bytes and zero after all files have been sent.
Client:
new Thread(new Runnable() {
#Override
public void run() {
try {
ByteArrayOutputStream memoryStream = new ByteArrayOutputStream();
Bitmap bitmapToSend =
Bitmap.createScaledBitmap(bitmapToSend, 900, 800, true);
bitmapToSend.compress(
Bitmap.CompressFormat.JPEG,100, memoryStream);
byte[] byteArray = memoryStream.toByteArray();
memoryStream = null;
DataOutputStream outputStream =
new DataOutputStream(server.getOutputStream());
outputStream.writeInt(byteArray.length);
outputStream.write(byteArray);
outputStream.flush();
} catch (IOException e) {
System.out.println("Socket not created");
e.printStackTrace();
}
}
}).start();
Server:
public static void readImages(InputStream stream) {
DataInputStream imgInput = new DataInputStream(stream);
int index = 0;
int byteLength;
try {
while ((byteLength = imgInput.readInt())>0) {
byte[] buffer = new byte[byteLength];
imgInput.readFully(buffer);
OutputStream imgOutput = new FileOutputStream("current" + (index++) + ".jpg");
imgOutput.write(buffer);
imgOutput.close();
}
} catch (IOException ex) {
// .............
} finally {
try {
imgInput.close();
} catch (IOException ex1) {
//...........
}
}
}

restore database file from dropbox to local memory

I have implemented a database backup on dropbox, i would like to restore the DB from dropbox to the internal memory (data\data\\database),
i think is forbidden to write directly, is possible to read by stream the file on dropbox, and open the local file, clear the data inside , and flush the stream into the file?
If yes, anyone have a code for example?
I hope to be clear.
this is my code...
private boolean downloadDropboxFile(String dbPath, File localFile) throws IOException{
BufferedInputStream br = null;
BufferedOutputStream bw = null;
try {
if (!localFile.exists()) {
localFile.createNewFile(); //otherwise dropbox client will fail silently
}
byte[] buffer = new byte[4096];
DropboxInputStream fd = mApi.getFileStream (dbPath, null);
br = new BufferedInputStream(fd, buffer.length);
bw = new BufferedOutputStream(new FileOutputStream(localFile));
int read;
while (true) {
read = br.read(buffer);
if (read <= 0) {
break;
}
bw.write(buffer, 0, read);
}
} catch (DropboxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
//in finally block:
if (bw != null) {
bw.close();
}
if (br != null) {
br.close();
}
}
return true;
}

Android, downloading and using a .db file

(I'm deeply sorry for my poor english)
For a school project, i have to realize an Android Application. It uses an intern SQLite Database which is a copy from a website MySQL database. (The android application is a search engine for an Electrical Engineering database)
Since it has to be independant from the website (offline), i have to create an update option.
For this purpose, i've made a special DownloadHelper class :
#SuppressLint("SdCardPath")
public final class DownloadHelper extends AsyncTask<Void,Void,Void>
{
Context context;
File cheminBdd = new File("/data/data/com.example.btc_pe/databases/basesqlite.db");
public DownloadHelper(Context ctxt)
{ this.context = ctxt; }
#Override
protected Void doInBackground(Void... params)
{
// TODO Auto-generated method stub
try
{
downloadDatabase(cheminBdd);
//copyServerDatabase(this.context);
}
catch (Exception ex)
{
Log.e("BTC","Failed to download database !",ex);
}
return null;
}
private static void downloadDatabase(File destFile) throws IOException
{
URLConnection ucon;
InputStream is = null;
OutputStream os = null;
try
{
Log.d("BTC","start DL");
URL url = new URL("adresse" + "basesqlite.db");
ucon = url.openConnection();
Log.d("BTC","Connection open");
is = ucon.getInputStream();
Log.d("BTC","Stream In got");
os = new FileOutputStream(destFile);
Log.d("BTC","Debut copy()");
copy(is,os);
Log.d("BTC","end DL");
}
finally
{
if (os != null) try { os.close(); } catch (Exception ex) { Log.e("BTC","Failed to gracefully close output stream",ex); }
if (is != null) try { is.close(); } catch (Exception ex) { Log.e("BTC","Failed to gracefully close input stream",ex); }
}
}
public static int copy(InputStream input, OutputStream output) throws IOException
{
byte[] buffer = new byte[8192];
int count = 0;
int n = 0;
while (-1 != (n = input.read(buffer)))
{
output.write(buffer, 0, n);
count += n;
}
output.flush();
return count;
}
#SuppressLint("SdCardPath")
private void copyServerDatabase(Context context)
{
BtcDb db = new BtcDb(context,"clean.db",null,0);
// by calling this line an empty database will be created into the default system path
// of this app - we will then overwrite this with the database from the server
db.getReadableDatabase();
db.close();
OutputStream os = null;
InputStream is = null;
try {
// Log.d("BTC", "Copying DB from server version into app");
is = context.openFileInput("basesqlite.db");
os = new FileOutputStream("/data/data/com.example.btc_pe/databases/");
copyFile(os, is);
}
catch (Exception e)
{
Log.e("BTC", "Server Database was not found - did it download correctly?", e);
}
finally
{
try
{
//Close the streams
if(os != null)
{
os.close();
}
if(is != null)
{
is.close();
}
}
catch (IOException e)
{
Log.e("BTC", "failed to close databases");
}
}
Log.d("BTC", "Done Copying DB from server");
}
private static void copyFile(OutputStream os, InputStream is) throws IOException
{
byte[] buffer = new byte[1024];
int length;
while((length = is.read(buffer))>0)
{
os.write(buffer, 0, length);
}
os.flush();
}
}
I call the update by an Actionbar button, using DownloadHelper.execute() method from an instanciated object.
Then i get an exception after passed the "is = ucon.getInputStream();", i get this LogCat :
http://www.dump-it.fr/btcpng/7865ef3fef44de25fd62f01dad23d02d.png.html
Of course, i checked this file on the server, my URL, my Android Devices. Nothing to do.
If somebody could give me a hand, i'm getting lost :/

Transfer InputStream to another Service (across process boundaries) with ParcelFileDescriptor.createPipe() failes with "EBADF (Bad file number)"

I want to "send" an InputStream from one Android Service to another service running within a different process by using ParcelFileDescriptor.createPipe(), a stream-to-stream copy thread and a ParcelFileDescriptor, representing the read side of the pipe, which is given to the other service with means of Binder IPC.
Sending Code (Process A)
I want to send a given InputStream to the receiving service:
public sendInputStream() {
InputStream is = ...; // that's the stream for process/service B
ParcelFileDescriptor pdf = ParcelFileDescriptorUtil.pipeFrom(is);
inputStreamService.inputStream(pdf);
}
The ParcelFileDescriptorUtil is a helper class, with a classic java.io. stream-to-stream copy Thread:
public class ParcelFileDescriptorUtil {
public static ParcelFileDescriptor pipeFrom(InputStream inputStream) throws IOException {
ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
ParcelFileDescriptor readSide = pipe[0];
ParcelFileDescriptor writeSide = pipe[1];
// start the transfer thread
new TransferThread(inputStream, new ParcelFileDescriptor.AutoCloseOutputStream(writeSide)).start();
return readSide;
}
static class TransferThread extends Thread {
final InputStream mIn;
final OutputStream mOut;
TransferThread(InputStream in, OutputStream out) {
super("ParcelFileDescriptor Transfer Thread");
mIn = in;
mOut = out;
setDaemon(true);
}
#Override
public void run() {
byte[] buf = new byte[1024];
int len;
try {
while ((len = mIn.read(buf)) > 0) {
mOut.write(buf, 0, len);
}
mOut.flush(); // just to be safe
} catch (IOException e) {
LOG.e("TransferThread", e);
}
finally {
try {
mIn.close();
} catch (IOException e) {
}
try {
mOut.close();
} catch (IOException e) {
}
}
}
}
}
Receiving Service Code (Process B)
The receiving service's .aidl:
package org.exmaple;
interface IInputStreamService {
void inputStream(in ParcelFileDescriptor pfd);
}
The receiving service, called by Process A:
public class InputStreamService extends Service {
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final IInputStreamService.Stub mBinder = new IInputStreamService.Stub() {
#Override
public void inputStream(ParcelFileDescriptor pfd) throws RemoteException {
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
OutputStream os = ...;
int len;
byte[] buf = new byte[1024];
try {
while ((len = is.read(buf)) > 0) {
os.write(buf, 0, len);
}
} catch (IOException e) {
// this catches the exception shown below
}
}
};
But in.read() in inputStream() always throws a IOException
java.io.IOException: read failed: EBADF (Bad file number)
at libcore.io.IoBridge.read(IoBridge.java:442)
at java.io.FileInputStream.read(FileInputStream.java:179)
at java.io.InputStream.read(InputStream.java:163)
It seems like the EBADF errno is set by read() when the file descriptor is closed. But I don't know what is causing it and how to fix it.
And yes, I know that a ConentProvider would also be a possibility. But shouldn't it also work with my approach? Are there any other ways to hand an InputStream stream to a different service in Android?
On a side note: CommonsWare created a similar project using a ContentProvider (related SO questions 1, 2). It's where I got most of the ideas for my approach from
It seems like the cause was the ParcelFileDescriptor being an argument of the service method. If the service does return the ParcelFileDescriptor it works as expected.
Sending Service (Process A)
public void sendInputStream() {
InputStream is = ...; // that's the stream for process/service B
ParcelFileDescriptor pfd = inputStreamService.inputStream();
OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(pfd);
int len;
byte[] buf = new byte[1024];
try {
while ((len = is.read(buf)) > 0) {
os.write(buf, 0, len);
}
} catch (IOException e) {
} finally {
try { is.close(); } catch (IOException e1) {}
try { os.close(); } catch (IOException e1) {}
}
}
Receiving Service Code (Process B)
The receiving service's .aidl:
package org.exmaple;
interface IInputStreamService {
ParcelFileDescriptor inputStream();
}
The receiving service, called by Process A:
public class InputStreamService extends Service {
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final IInputStreamService.Stub mBinder = new IInputStreamService.Stub() {
#Override
public void ParcelFileDescriptor inputStream() throws RemoteException {
// one can read the contents of the Processes A's InputStream
// from the following OutputStream
OutputStream os = ...;
ParcelFileDescriptor pfd = ParcelFileDescriptorUtil.pipeTo(os);
return pfd;
}
};
The ParcelFileDescriptorUtil is a helper class, with a classic java.io. stream-to-stream copy Thread. Now we have to use the pipeTo() method.
public class ParcelFileDescriptorUtil {
public static ParcelFileDescriptor pipeTo(OutputStream outputStream) throws IOException {
ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
ParcelFileDescriptor readSide = pipe[0];
ParcelFileDescriptor writeSide = pipe[1];
// start the transfer thread
new TransferThread(new ParcelFileDescriptor.AutoCloseInputStream(readSide), outputStream).start();
return writeSide;
}
static class TransferThread extends Thread {
final InputStream mIn;
final OutputStream mOut;
TransferThread(InputStream in, OutputStream out) {
super("ParcelFileDescriptor Transfer Thread");
mIn = in;
mOut = out;
setDaemon(true);
}
#Override
public void run() {
byte[] buf = new byte[1024];
int len;
try {
while ((len = mIn.read(buf)) > 0) {
mOut.write(buf, 0, len);
}
mOut.flush(); // just to be safe
} catch (IOException e) {
LOG.e("TransferThread", e);
}
finally {
try {
mIn.close();
} catch (IOException e) {
}
try {
mOut.close();
} catch (IOException e) {
}
}
}
}
}
This allows you to transfer InputStreams across process boundaries, one drawback is that there is some CPU time involved in the stream-to-stream copies.

Categories

Resources