Serve font/images with Nanohttpd from Android - android

I'm trying to host an Angular app with nanohttpd, so I put the files into a dist/ folder inside the assets folder of the android app. Now I want to serve the angular files but I keep getting this kind of errors in console (it only appears when trying to request fonts and images):
GET http://hostname/font.woff2 200 (OK)
This is the code that I use to serve the files:
public Response serve(IHTTPSession session) {
String filepath = getFilepath(session.getUri()); // Get filepath depending on the requested url
String mimeType = getMimeType(filepath); // Get mimetype depending on the extension of the filepath (font/woff, font/woff2, font/ttf, image/x-icon, text/html, application/javascript)
String content;
byte[] buffer;
Response res;
InputStream is;
try {
is = this.assetManager.open("dist/" + filepath);
int size = is.available();
buffer = new byte[size];
is.read(buffer);
is.close();
content = new String(buffer);
content = content.replace("old string", "new string");
if (typeText(mimeType)) { // If mimeType is text/html or application/json
res = newFixedLengthResponse(content);
}else{ // This is when I try to serve fonts or images
res = newFixedLengthResponse(Response.Status.OK, mimeType, is, size); // Not working
}
}catch(IOException e) {
res = newFixedLengthResponse("Error!");
}
return res;
}
I think that maybe the font files are getting compressed, or the size is not the real size of the InputStream. Also when loading the page, vendor.js takes a lot to download, and after that, it stops downloading the rest of the files.
I also get this error on the logcat:
Communication with the client broken, or an bug in the handler code

I fixed it like this:
public Response serve(IHTTPSession session) {
String filepath = getFilepath(session.getUri()); // Get filepath depending on the requested url
String mimeType = getMimeType(filepath); // Get mimetype depending on the extension of the filepath (font/woff, font/woff2, font/ttf, image/x-icon, text/html, application/javascript)
String content;
byte[] buffer;
Response res;
InputStream is;
try {
is = this.assetManager.open("dist/" + filepath);
if (!typeText(mimeType)) { // If mimeType is font/<something> or image/<something>
return newFixedLengthResponse(Response.Status.OK, mimeType, is, -1);
}
int size = is.available();
buffer = new byte[size];
is.read(buffer);
is.close();
content = new String(buffer);
content = content.replace("old string", "new string");
}catch(IOException e) {
content = "Error!";
}
return newFixedLengthResponse(content);
}
I really don't know what happend, but it works really well this way. It seems to me that is.available() was not returning the right file size.

Related

How to upload big videos files to server quickly in android

Hi I am uploading Large video files to server using Volley Multi-part Api but it takes much time for upload to server
Is it better to split my video files and send to server? If it is better please provide me code how can I do that, If not what is the best way to uploading big videos files to server quickly?
To split file into parts (chunks):
public static List<File> splitFile(File f) throws IOException {
int partCounter = 1;
List<File> result = new ArrayList<>();
int sizeOfFiles = 1024 * 1024;// 1MB
byte[] buffer = new byte[sizeOfFiles]; // create a buffer of bytes sized as the one chunk size
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
String name = f.getName();
int tmp = 0;
while ((tmp = bis.read(buffer)) > 0) {
File newFile = new File(f.getParent(), name + "." + String.format("%03d", partCounter++)); // naming files as <inputFileName>.001, <inputFileName>.002, ...
FileOutputStream out = new FileOutputStream(newFile);
out.write(buffer, 0, tmp);//tmp is chunk size. Need it for the last chunk, which could be less then 1 mb.
result.add(newFile);
}
return result;
}
This method will split your file to chunks of size of 1MB (excluding the last chunk). After words you can send all these chunks too the server.
Also if you need to merge these files:
public static void mergeFiles(List<File> files, File into)
throws IOException {
BufferedOutputStream mergingStream = new BufferedOutputStream(new FileOutputStream(into))
for (File f : files) {
InputStream is = new FileInputStream(f);
Files.copy(is, mergingStream);
is.close();
}
mergingStream.close();
}
Just in case if your server is in Java also

How can I properly send a Synced External Application Image to a RESTful WCF

I'm newbie to Android, I'm trying to send some Images from Android to a RESTFul WCF.
By now I'm being able to select the Images from the Gallery and sending them to the Server.
the WCF is expecting the image as Stream
But I'm having problems with the Synced Images that get stored in the Tablet Like the Facebook or G+ photos. (I don't know if they are cached or something)
I'm using this function to get the path of the Image
public static String getRealPathFromURI(Context context, Uri contentUri) {
String path = null;
if (contentUri.getScheme().toString().compareTo("content")==0)
{
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
path = cursor.getString(column_index);
}
else
{
path = contentUri.getPath();
}
Log.i(TAG, path);
return path;
}
With that kind of images I get an internet path like:
https://fbcdn-sphotos-g-a.akamaihd.net/hphotos-ak-ash4/s2048x2048/432098_10151223392360790_398885469_n.jpg
Just for clarity and to remark. I get a "content" scheme.. so I get the path from the "if " something like:
content://com.sec.android.gallery3d.provider/picasa/item/5703464571893262194
To send it to the Server im using MultipartEntity, because I saw in others post here in SO to do so, like this:
((MultipartEntity) oInputEntity).addPart(
"fileContents",
new FileBody(new File(Utilities.getRealPathFromURI(context,
imageUri)),
"image/jpeg"));
With that kind of images I was getting a FileNotFoundEception I think it's because the image path is an Internet path, so the MultiPartEntity don't know how to retrieve it,
So I changed my method to download the image and now is working with this code
public static File getFileFromURI(Context context, Uri contentUri) {
String path = IntUtilities.getRealPathFromURI(context, contentUri);
Log.i(TAG, path);
final File file;
if (path.startsWith("http") || path.startsWith("/http") )
{
//if its an image form internet lets download it and save it in our directory and return that file
// Determine Uri of camera image to save.
final String fname = "BIR" + UUID.randomUUID() + ".jpg";
final File root = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "BIR");
root.mkdirs();
file = new File(root, fname);
try {
final URL url = new URL(path);
final HttpURLConnection urlConnection = (HttpURLConnection) url
.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(false);
urlConnection.connect();
final FileOutputStream fileOutput = new FileOutputStream(file);
final InputStream inputStream = urlConnection.getInputStream();
#SuppressWarnings("unused")
int downloadedSize = 0;
byte[] buffer = new byte[1024];
int bufferLength = 0;
while ((bufferLength = inputStream.read(buffer)) > 0) {
fileOutput.write(buffer, 0, bufferLength);
downloadedSize += bufferLength;
}
// close the output stream when done
fileOutput.close();
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else
{
file = new File(path);
}
return file;
}
((MultipartEntity) oInputEntity).addPart(
"fileContents",
new FileBody(Utilities.getFileFromURI(context,
imageUri),
"image/jpeg"));
But I'm not comfortable with this solution, seems like double effort, I turned off my Wifi and 3g in the tablet, also turned off and on the tablet iself and I still see those images, so I'm guessing they got copied locally or cached on the tablet when they were synced for the first time. I looked for them when attached to my computer (in Windows Explorer) to see if they were there, but I dont see them, maybe I'm doing something wrong or dont know the storage folder.
The main reason that I dont like this solution is that if you don't have Internet on the moment, obviously the image will not be downloaded, and the app I'm making is supposed to work offline, and well.. the Image is there, there shouldn't be a request to internet to guess a local image.
Being said this, is there a way to find the real/physical path of this Photos that were synced, that have an http or https scheme to send this images using the MultiPartEntity?
Or another proper way to send this Images to the Server?
I really appreciate your help
from the chooser dialog , you can always get a bitmap
chooser-->$Result->getData() = imageUri
from the imageUri, get a Bitmap by running the following code:
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
Once you get the bitmap..,
you can put it to a fileSink
you can use a Hashmap to cache it in Memory
mBitMap = BitmapFactory.decodeStream(
mCR.openInputStream(imageUri), null, options);
OutputStream os = new FileOutputStream(f);
mBitMap.compress(Bitmap.CompressFormat.JPG, minVal, os);
mload.memoryCache.putbig(file.toURI().toURL().toString(), mBitMap);
and you can http POST the Bitmap directly by loading its ByteArray to the Entity...
case POST:
HttpPost httpPost = new HttpPost(url);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
float tmp = (float) 1024 * 1024 / bmp.getByteCount();
int minVal = (Math.round(tmp * 100) < 101) ? Math.round(tmp * 100): 100;
if (bmp.compress(Bitmap.CompressFormat.JPEG, minVal, stream)){
httpPost.setEntity(new ByteArrayEntity(stream.toByteArray()));
}else{ //TODO need to format actual message
handler.sendMessage(Message.obtain(handler,
HttpConnection.DID_ERROR, new Exception("ERR bitmap NG")));
}
background on the POST method is here
lazyloader project is a good template to use.
So why use mimeMultipartEntity with a file when you can operate directly on the bytes in the bitMap? As soon as you have a Uri, get a Bitmap and use the bitmap/ Uri pair for the basis of your interface to memCache, interface to HTTP POST, interface to fileSink used to retrieve local file when you have CacheMiss. This will help minimize doing everything on the basis of a file.
Think about using a Map [hashON(Uri.toString() :: bitMap] to store the images that you process locally. Then when you want to POST an image , you can just retrieve it from the map and POST its bytes directly in a "ByteArrayEntity".

Android get data from json file (.txt)

I have Json file (test.txt) and I wanna get data from that file to Android App. My code is:
private static String url = "file:///AndroidJSONParsingActivity/res/raw/test.txt";
But it is not working. Error I get is:
error opening trace file: No such file or directory (2)
Somebody help me? Thanks!
Put the test.txt file into assets folder
public class Utility {
public static String readXMLinString(String fileName, Context c) {
try {
InputStream is = c.getAssets().open(fileName);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
String text = new String(buffer);
return text;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Then you can get test.txt using the following code
JSONObject json = new JSONObject(Utility.readXMLinString("test.txt",getApplicationContext()));
You have an answere Using JSON File in Android App Resources
You need to put the file intro raw folder and you can acces with this:
getResources().openRawResource(resourceName)
use getResources().openRawResource(RawResource_id) for reading an text file from res/raw folder as:
InputStream inputStream = Current_Activity.this.
getResources().openRawResource(R.raw.test);
//put your code for reading json from text file(inputStream) here
use following code to open input stream for the file stored in the raw folder:
getResources().openRawResource(R.raw.text_file)
Please see below code for that, it will solve your problem.
public void mReadJsonData() {
try {
InputStream is = getResources().openRawResource(R.raw.textfilename)
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
String mResponse = new String(buffer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

android add filename to bytestream

im trying to send a file in android through sockets. i want to add the filename with the bytestream and then send it to the server. how do i do that? and then how do i seperate the filename on the receiving side?
this is the code to send file :
Log.i("SocketOP", "sendFILE-1");
File f = new File(path);
String filename=path.substring(path.lastIndexOf("/")+1);
System.out.println("filename:"+filename);
fin.filename = "~"+filename;
BufferedOutputStream out = new BufferedOutputStream( socket.getOutputStream() );
FileInputStream fileIn = new FileInputStream(f);
Log.i("SocketOP", "sendFILE-2");
byte [] buffer = new byte [(int)f.length()];
System.out.println("SO sendFile f.length();" + f.length());
int bytesRead =0;
while ((bytesRead = fileIn.read(buffer)) > 0) {
out.write(buffer, 0, buffer.length);
System.out.println("SO sendFile" + bytesRead +filename);
}
out.flush();
out.close();
fileIn.close();
Log.i("SocketOP", "sendFILE-3");
If this is your own protocol then you create a data packet that separate the two sections (filename and data). You need to denote clearly the separation via a particular boundary.
On the server, since you understand the protocol, the server will read back the whole data packet and it will separate the filename and data based on the given boundary.
MIME data format use exactly this kind of data exchange and widely use with HTTP protocol. If you use the same MIME Data Format, another advantage is you could use third party library to encode and decode your data such as HttpMime
Below is the rough code to format the data using MIME data and send it through Socket
File f = new File(path);
BufferedOutputStream out = new BufferedOutputStream( socket.getOutputStream() );
String filename=path.substring(path.lastIndexOf("/")+1);
// create a multipart message
MultipartEntity multipartContent = new MultipartEntity();
// send the file inputstream as data
InputStreamBody isb = new InputStreamBody(new FileInputStream(f), "image/jpeg", filename);
// add key value pair. The key "imageFile" is arbitrary
multipartContent.addPart("imageFile", isb);
multipartContent.writeTo(out);
out.flush();
out.close();
Note that you would need org.apache.http.entity.mime.MultipartEntity and org.apache.http.entity.mime.content.InputStreamBody from HttpMime project. On the server, you need MIME parser that would get back the filename and all the bytes content
To read the inputstream back on the server, you would need a class to parse the MIME message. You shouldn't have to write the parser yourself as MIME is a popular message format already unless you want to learn about the MIME message structure.
Below is the sample code using MimeBodyPart that is part of JavaMail.
MimeMultipart multiPartMessage = new MimeMultipart(new DataSource() {
#Override
public String getContentType() {
// this could be anything need be, this is just my test case and illustration
return "image/jpeg";
}
#Override
public InputStream getInputStream() throws IOException {
// socket is the socket that you get from Socket.accept()
BufferedInputStream inputStream = new BufferedInputStream(socket.getInputStream());
return inputStream;
}
#Override
public String getName() {
return "socketDataSource";
}
#Override
public OutputStream getOutputStream() throws IOException {
return socket.getOutputStream();
}
});
// get the first body of the multipart message
BodyPart bodyPart = multiPartMessage.getBodyPart(0);
// get the filename back from the message
String filename = bodyPart.getFileName();
// get the inputstream back
InputStream bodyInputStream = bodyPart.getInputStream();
// do what you need to do here....
You could download JavaMail from Oracle Website which also has dependency on Java Activation Framework

Opening a 12kb text file takes WAY too long....?

The following code works, but takes way too long (over a minute) to open a small file. The LogCat shows a lot of instances of "GC_FOR_MALLOC freed #### objects / ###### bytes in ##ms". Any suggestions?
File dirPath = new File(Environment.getExternalStorageDirectory(), "MyFolder");
String content = getFile("test.txt");
public String getFile(String file){
String content = "";
try {
File dirPathFile = new File(dirPath, file);
FileInputStream fis = new FileInputStream(dirPathFile);
int c;
while((c = fis.read()) != -1) {
content += (char)c;
}
fis.close();
} catch (Exception e) {
getLog("Error (" + e.toString() + ") with: " + file);
}
return content;
}
Update:
This is what it looks like now:
File dirPath = new File(Environment.getExternalStorageDirectory(), "MyFolder");
String content = getFile("test.txt");
public String getFile(String file){
String content = "";
File dirPathFile = new File(dirPath, file);
try {
StringBuilder text = new StringBuilder();
BufferedReader br = new BufferedReader(new FileReader(dirPathFile));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append('\n');
}
content = new String(text);
} catch (Exception e) {
getLog("Error (" + e.toString() + ") with: " + file);
}
return content;
}
Thank you all!!
Using += on a String is extremely inefficient - it will constantly allocate and deallocate memory, something you need to avoid!
If you need to constantly add characters, use a StringBuilder and give it a sufficiently big buffer up front.
However, it's even better to just read the entire file as a byte array and then create a string from that byte array. Use the String(byte[]) constructor.
content += (char)c;
Well, here's your problem. String concatenation is slow if you have to do it repeatedly. And you're reading the file one character at a time, which is also really slow.
You want to be using the read(byte[] buffer) method to read the file into a buffer efficiently. And then you can stringify the buffer if need be.
Rather than reading a single byte at a time, you should read multiple using read(byte[]).
Also, Strings are immutable, so every time you do String s = s + "a"; there is the possibility that you are creating a new String object. You can use StringBuilder instead to build up a larger string.
Schlemiel the painter strikes again!
try to read with buffer read(byte[] buff)
The reasons are:
You are creating too many String objects with content += (char)c; - use StringBuilder instead to append with read data, then in the end call toString() on the StringBuilder.
You don't use a byte[] (or char[], it depends on implementation) buffer to read from file. Usually 1KB buffer is optimal instead of reading one by one byte.

Categories

Resources