I had written a crawler program in C# which used to crawl on a given url or url postfixed with page number and download all the image files from it.It worked fine.
Now I am a newbie in android programming and thought to write the same thing for my android device so that I can also use it on my phone.
The algorithm I followed was...
1) Take the base url,start page no(in case the url is postfixed by page number in query string),end page no,and location to store the images on sdcard.
2) If end page no is less than start page no(means if i only want to crawl a single page) pass it to getHtml method. or else make a loop from start to end page and pass each url to getHtml method.
3) In getHtml method I download web page source and broke it in pieces to find link to image files in it.
4) for each image url found, download the image file to the given save location.
The algo seems easy but when I made the whole program I had some pretty big performance issues. It is so so heavy that while running it in emulator all i could see was gc clearing objects in logcat.Another very common issue is that the UI hangs.But as the program is only for personal use i can do with it because I doesnt know multithreading in android. But atleast the program should be fast. Is there any way I can decrease the number of objects or destroy them myself.
Is there anything I can do to improve this. I wonder how those GBs worth of games works flawlessly and my 20KB app is so so slow.
The whole code is.
package com.dwnldr;
import java.io.*;
import java.net.*;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import android.app.Activity;
import android.os.*;
import android.util.Log;
import android.view.View;
import android.widget.*;
public class IMGDwnldrActivity extends Activity {
EditText res;
String str;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn = (Button) findViewById(R.id.button1);
File SDCardRoot = Environment.getExternalStorageDirectory();
EditText saveat = (EditText) findViewById(R.id.editText4);
saveat.setText(SDCardRoot.getAbsolutePath());
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
//Getting URL,Start pageno,End pageno and the save location on sdcard
EditText baseurl = (EditText) findViewById(R.id.editText1);
String url = baseurl.getText().toString();
EditText startpage = (EditText) findViewById(R.id.editText2);
int start = Integer.parseInt(startpage.getText().toString());
EditText endpage = (EditText) findViewById(R.id.editText3);
int end = Integer.parseInt(endpage.getText().toString());
EditText saveat = (EditText) findViewById(R.id.editText4);
String save = saveat.getText().toString();
if (start <= end) {
for (int i = start; i <= end; i++) {
str = "\n--------------------";
str += "\nPage No" + String.valueOf(i);
writemsg(str);
getHtml(url + String.valueOf(i), save);
}
} else
getHtml(url, save);
writemsg("Done");
} catch (Exception ee) {
writemsg("\nException fired::" + ee.getMessage());
}
}
});
}
//method to get the source of a particular url
public void getHtml(String url, String save) throws ClientProtocolException, IOException {
try {
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpGet = new HttpGet(url);
HttpResponse response = httpClient.execute(httpGet, localContext);
String result = "";
str = "\nDownloading Page....";
writemsg(str);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().
getContent()));
String line = null;
while ((line = reader.readLine()) != null) {
result += line + "\n";
}
str = "\nPage Downloaded...";
writemsg(str);
String[] pieces;
if (result.contains(".jpg") || result.contains(".jpeg")) {
pieces = result.split("\"");
Log.d("Events", String.valueOf(pieces.length));
for (int i = 0; i < pieces.length; i++) {
if (pieces[i].contains(".jpg") || pieces[i].contains(".jpeg")) {
if (pieces[i].contains("http")) {
Log.d("Events", pieces[i]);
downloadme(pieces[i], save);
} else {
URL u = new URL(url);
if (pieces[i].startsWith("."));
pieces[i] = pieces[i].substring(pieces[i].indexOf("/"), pieces[i].length());
writemsg(u.getProtocol() + "://" + u.getHost() + pieces[i]);
if (pieces[i].startsWith("/"))
downloadme(u.getProtocol() + "://" + u.getHost() + pieces[i], save);
else
downloadme(u.getProtocol() + "://" + u.getHost() + "/" + pieces[i], save);
}
}
}
}
} catch (Exception ee) {
writemsg("\nException fired::" + ee.getMessage());
}
}
//download each image url given
private void downloadme(String url1, String save) {
try {
str = "\nDownloading Image " + url1;
writemsg(str);
URL url = new URL(url1);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
urlConnection.connect();
File f = new File(save);
if (f.isDirectory() && !f.exists())
f.mkdirs();
String fileName = url1.substring(url1.lastIndexOf('/') + 1, url1.length());
File file = new File(save, fileName);
FileOutputStream fileOutput = new FileOutputStream(file);
InputStream inputStream = urlConnection.getInputStream();
int totalSize = urlConnection.getContentLength();
str = "\nImage Size " + String.valueOf(totalSize / 1024);
writemsg(str);
byte[] buffer = new byte[1024];
int bufferLength = 0; //used to store a temporary size of the buffer
while ((bufferLength = inputStream.read(buffer)) > 0) {
fileOutput.write(buffer, 0, bufferLength);
}
fileOutput.close();
str = "\nDownloaded Image " + url1;
writemsg(str);
catch some possible
errors // ...
} catch (MalformedURLException e) {
writemsg("\nException fired::" + e.getMessage());
} catch (IOException e) {
writemsg("\nException fired::" + e.getMessage());
} catch (Exception ee) {
writemsg("\nException fired::" + ee.getMessage());
}
}
//write certain text to the Result textbox
private void writemsg(String msg) {
res = (EditText) findViewById(R.id.result);
String str = res.getText().toString();
str += msg;
res.setText(str);
}
}
Related
i want to open ebub files either in webview or by something else but content click and images,videos should be there
-I have tried using webview but images cant display in that
textView.setText(Html.fromHtml(data, new Html.ImageGetter() {
#Override
public Drawable getDrawable(String source) {
String imageAsStr = source.substring(source.indexOf(";base64,") + 8);
byte[] imageAsBytes = Base64.decode(imageAsStr, Base64.DEFAULT);
Bitmap imageAsBitmap = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length);
int imageWidthStartPx = (pxScreenWidth - imageAsBitmap.getWidth()) / 2;
int imageWidthEndPx = pxScreenWidth - imageWidthStartPx;
Drawable imageAsDrawable = new BitmapDrawable(getResources(), imageAsBitmap);
imageAsDrawable.setBounds(imageWidthStartPx, 0, imageWidthEndPx, imageAsBitmap.getHeight());
return imageAsDrawable;
}
}, null));
-i tried this also but in this images are display but content click is no there
Use this code provided you have necessary libraries and sampleepubfile.epub in your assets...
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import nl.siegmann.epublib.domain.Book;
import nl.siegmann.epublib.domain.TOCReference;
import nl.siegmann.epublib.epub.EpubReader;
import android.app.Activity;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.text.Html;
import android.util.Log;
import android.webkit.WebView;
public class EPubDemo extends Activity {
WebView webview;
String line, line1 = "", finalstr = "";
int i = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
webview = (WebView) findViewById(R.id.webview);
AssetManager assetManager = getAssets();
try {
// find InputStream for book
InputStream epubInputStream = assetManager
.open("sampleepubfile.epub");
// Load Book from inputStream
Book book = (new EpubReader()).readEpub(epubInputStream);
// Log the book's authors
Log.i("author", " : " + book.getMetadata().getAuthors());
// Log the book's title
Log.i("title", " : " + book.getTitle());
/* Log the book's coverimage property */
// Bitmap coverImage =
// BitmapFactory.decodeStream(book.getCoverImage()
// .getInputStream());
// Log.i("epublib", "Coverimage is " + coverImage.getWidth() +
// " by "
// + coverImage.getHeight() + " pixels");
// Log the tale of contents
logTableOfContents(book.getTableOfContents().getTocReferences(), 0);
} catch (IOException e) {
Log.e("epublib exception", e.getMessage());
}
String javascrips = "";
try {
// InputStream input = getResources().openRawResource(R.raw.lights);
InputStream input = this.getAssets().open(
"poe-fall-of-the-house-of-usher.epub");
int size;
size = input.available();
byte[] buffer = new byte[size];
input.read(buffer);
input.close();
// byte buffer into a string
javascrips = new String(buffer);
} catch (IOException e) {
e.printStackTrace();
}
// String html = readFile(is);
webview.loadDataWithBaseURL("file:///android_asset/", javascrips,
"application/epub+zip", "UTF-8", null);
}
#SuppressWarnings("unused")
private void logTableOfContents(List<TOCReference> tocReferences, int depth) {
if (tocReferences == null) {
return;
}
for (TOCReference tocReference : tocReferences) {
StringBuilder tocString = new StringBuilder();
for (int i = 0; i < depth; i++) {
tocString.append("\t");
}
tocString.append(tocReference.getTitle());
Log.i("TOC", tocString.toString());
try {
InputStream is = tocReference.getResource().getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(is));
while ((line = r.readLine()) != null) {
// line1 = Html.fromHtml(line).toString();
Log.v("line" + i, Html.fromHtml(line).toString());
// line1 = (tocString.append(Html.fromHtml(line).toString()+
// "\n")).toString();
line1 = line1.concat(Html.fromHtml(line).toString());
}
finalstr = finalstr.concat("\n").concat(line1);
// Log.v("Content " + i, finalstr);
i++;
} catch (IOException e) {
}
logTableOfContents(tocReference.getChildren(), depth + 1);
}
webview.loadDataWithBaseURL("", finalstr, "text/html", "UTF-8", "");
}
}
I have tried this and its working for me
When I started coding my project I did not know the string resource. Now I would like to use this resource for all my string. How do you do it all of a sudden? Knowing that I have more than 10000 strings currently I do not want to do it one by one by hand ...
To automate this completely you need a special tool (I haven't found one), outside of Android Studio to:
Find the string (and replace with the reference)
Update strings.xml
optionally translate strings
For one at a time manual extract (See also link):Alt+Enter, Extract String Resource while the caret is inside the hardcoded string in code:
and in XML:
I don't think, that there is a slink workaround considering, that you need to name all string somehow with a unique and useful identifier. When you let this be done automatically, your code will get quite hard to read :/
Just highlight every instance of a string,then click on the yellow hint icon on the left of the statemnt to extract string resource.Then you can remove duplicated strings later.
I wrote a java script for xml layouts at least, for anyone who needs it... There might be some minor fixes required later.
package com.cameron.smelevel.lib;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class StringResourceCreator {
public static void main(String [] args){
String mainDirPath = "S:\\androidProject\\src";
String layoutDirPath = "\\main\\res\\layout";
String outputDirPath = mainDirPath+"-out";
String stringFilePath = outputDirPath+"\\strings.txt";
String line;
File layoutDir = new File(mainDirPath + layoutDirPath);
File layoutOutDir = new File(outputDirPath + layoutDirPath);
layoutOutDir.mkdirs();
HashMap<String, String> stringEnteries = new HashMap<>();
for (File file : layoutDir.listFiles()) {
String fileName = file.getName();
PrintWriter pr = null;
try {
// FileReader reads text files in the default encoding.
FileReader fileReader = new FileReader(file);
// Always wrap FileReader in BufferedReader.
BufferedReader bufferedReader = new BufferedReader(fileReader);
FileWriter outputStream = new FileWriter(layoutOutDir.getAbsolutePath() + "\\"+ fileName);
pr = new PrintWriter(outputStream);
while ((line = bufferedReader.readLine()) != null) {
line = getModifiedLine(line, stringEnteries);
pr.write(line);
pr.println();
}
} catch(FileNotFoundException ex) {
System.out.println("Unable to open file '" + fileName + "'");
} catch (IOException ex) {
System.out.println("Error reading file '" + fileName + "'");
// Or we could just do this:
// ex.printStackTrace();
}finally {
if(pr != null) pr.close();
}
}
PrintWriter pr = null;
try {
FileWriter outputStream = new FileWriter(stringFilePath);
pr = new PrintWriter(outputStream);
Iterator it = stringEnteries.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
String entry = "<string name=\"" + pair.getKey() + "\">" + pair.getValue() + "</string>";
it.remove(); // avoids a ConcurrentModificationException
pr.write(entry);
pr.println();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(pr != null) pr.close();
}
}
private static String getModifiedLine(String line, HashMap<String, String> stringEnteries) {
if (line.contains(":text=\"") || line.contains(":hint=\"")){
StringBuilder fieldName = new StringBuilder();
String text = line.substring(line.indexOf("\"")+1, line.lastIndexOf("\""));
String textTrimmed = text.replace("\\n","");
if (!textTrimmed.startsWith("#string")){
String[] words = textTrimmed.split(" ");
for (int j = 0; j < words.length; j++) {
String word = words[j];
for (int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
if (Character.isAlphabetic(c))
if (i == 0 && fieldName.length() != 0)
fieldName.append(Character.toUpperCase(c));
else
fieldName.append(Character.toLowerCase(c));
}
}
if (fieldName.length() > 1) {
String value = stringEnteries.get(fieldName.toString());
if(value != null) {
if (!value.equals(text)) {
fieldName.append("1");
stringEnteries.put(fieldName.toString(), text);
}
}else
stringEnteries.put(fieldName.toString(), text);
line = line.replace(text, "#string/"+fieldName);//replaceLast(line, text, "#string/"+fieldName);
}
}
}
return line;
}
}
I am relativly new to programming in java and android, so I wanted to ask you guys for a simple and understandable way of filtering two tables and their h3 headings of this website, possibly even cache it, and load it into a transparent WebView, so it doesnt look like a website. I thought of RegEx.. I do this to keep it up to date without having to service that thing.
With "simple and understandable" I mean comments, and possibly show what are just var names, method names or other custom names. And many explanations, comments and other things... Of course you can also just bomb the code in there, that would also work but I probably could not understand all of it.. ;)
Here's some code I tried:
package com.mrousavy.gemeindemuckendorfwipfing;
import android.os.AsyncTask;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by Marc on 15.10.2015.
*/
public class Table {
// found on stackoverflow
public static boolean exists2(String url) {
try {
URL u = new URL(url);
HttpURLConnection connection = (HttpURLConnection) u.openConnection();
connection.setRequestMethod("HEAD");
connection.connect();
return connection.getResponseCode() == HttpURLConnection.HTTP_OK;
} catch (Exception ex) {
return false;
}
}
/**
* must NOT be called in main thread!!!
*/
public static String getHTML2(String url) throws Exception {
try {
URL u = new URL(url);
BufferedReader in = new BufferedReader(new InputStreamReader(u.openStream()));
String tmp, html = "";
while ((tmp = in.readLine()) != null) {
html += tmp;
try {
Thread.sleep(10);
} catch (Exception e) {
}
}
return html;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* must NOT be called in main thread!!!
*/
public static List<String> getUrlsFromHTML2(String html) throws Exception {
List<String> urls = new ArrayList();
//init Patterns
Pattern divsPattern = Pattern.compile("<h3>.</table>");
//Pattern urlPattern = Pattern.compile("<a href=\"\\./files/(.*?)\"");
//search for right divs
Matcher divs = divsPattern.matcher(html);
while (divs.find()) {
//search for links
String innerDiv = divs.group(1);
Matcher url = urlPattern.matcher(innerDiv);
if (url.find()) {
if (!urls.contains(url.group(1)))
urls.add(url.group(1));
}
try {
Thread.sleep(10);
} catch (Exception e) {
}
}
return urls;
}
public static List<News> getNewsFromHTML(String html) {
List<News> ret = new ArrayList();
Pattern firstNewsPattern = Pattern.compile("<h3><strong>Aktuelle Meldungen</strong></h3>(.*?)<hr />");
Pattern newsPattern = Pattern.compile("<hr />(.*?)<hr />");
Pattern newsHeaderPattern = Pattern.compile("<h4>(.*?)</h4>");
Pattern hrefPattern = Pattern.compile("href=\"(.*?)\"");
Matcher newsHeader = null;
Matcher href = null;
Matcher firstNews = firstNewsPattern.matcher(html);
if(firstNews.find()) {
String content = firstNews.group(1).replace("./", "http://www.muckendorf-wipfing.at/");
href = hrefPattern.matcher(content);
while(href.find()) {
String url = href.group(1);
if(!url.contains("/")) {
content = content.replace("href=\"" + url + "\"", "href=\"" + "http://www.muckendorf-wipfing.at/" + url + "\"");
}
}
newsHeader = newsHeaderPattern.matcher(content);
if(newsHeader.find())
ret.add(new News(newsHeader.group(1).replaceAll("<(.*?)>", "").replaceAll("&#\\d{4};", ""), content));
}
Matcher news = newsPattern.matcher(html);
while(news.find()) {
String content = news.group(1).replace("./", "http://www.muckendorf-wipfing.at/");
href = hrefPattern.matcher(content);
while(href.find()) {
String url = href.group(1);
if(!url.contains("/")) {
content = content.replace("href=\"" + url + "\"", "href=\"" + "http://www.muckendorf-wipfing.at/" + url + "\"");
}
}
newsHeader = newsHeaderPattern.matcher(content);
if(newsHeader.find())
ret.add(new News(newsHeader.group(1).replaceAll("<(.*?)>", "").replaceAll("&#\\d{4};", ""), content));
}
return ret;
}
public static String listToString(List<String> list) {
String ret = "";
for(String str : list) {
ret += str + "§";
}
ret = ret.substring(0, ret.length()-1);
return ret;
}
public static List<String> stringToList(String str) {
String[] arr = str.split("§");
List <String> ret = new ArrayList();
for(String s : arr) {
if(!s.trim().equals(""))
ret.add(s);
}
return ret;
}
public static String extractContentFromHTML(String html) {
Pattern regex = Pattern.compile("<div id=\"content\">((.*?(<div.*?<\\/div>)*.*?)*)<\\/div>");
Pattern hrefPattern = Pattern.compile("href=\"(.*?)\"");
Matcher match = regex.matcher(html);
if(match.find()) {
String content = match.group(1).replace("./", "http://www.muckendorf-wipfing.at/");
Matcher href = hrefPattern.matcher(content);
while(href.find()) {
String url = href.group(1);
if(!url.contains("/")) {
content = content.replace("href=\"" + url + "\"", "href=\"" + "http://www.muckendorf-wipfing.at/" + url + "\"");
}
}
return content;
}
return "";
}
}
I hope someone can help me out! :)
Thank you! ^^
Don't use regex to parse html/xml, it's error prone. Try using specialized lib as the excellent Jsoup:
import org.jsoup.Jsoup;
import org.jsoup.Connection;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
[...]
final String url = "http://www.muckendorf-wipfing.at/25-0-Wirtschaft+und+Gastronomie.html";
String tablesHtml = parseHTML(url);
[...]
String parseHTML(String url) {
//Retrieve html of {url} via GET
Connection.Response response = Jsoup.connect(url).method(Connection.Method.GET).execute();
//Parse html
Document doc = response.parse();
//Select the div with id="content", where both tables are stored
Element contentDiv = doc.select("div#content").first();
//return the inner html of <div id="content"> selected above
return contentDiv.html();
}
The syntax of the select function can be found here
UPDATE: i've updated the code to parse the content of div too, creating a Table class that store <h3> text and table as 'html' and also as a bidimensional String array. It has a nice toString() method too useful to see what you get.
NB: The trick is in the jsoup select statement "h3:contains(" + h3Text + ") ~ table": it selects the tables after and h3 tag with h3Text (the title of the table) inside. Later we're taking only the first table of the list so we can be sure we're selecting the table coupled with the h3 title.
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
//[...]
/* //CASE 1: if you have to download the html
* String url = "http://www.muckendorf-wipfing.at/25-0-Wirtschaft+und+Gastronomie.html";
* //Retrieve html of "url" via GET
* Connection.Response response = Jsoup.connect(url).method(Connection.Method.GET).execute();
* //Parse html
*Document doc = response.parse();
*/
//CASE 2: If you already have the html in a String called htmlString
Document doc = Jsoup.parse(htmlString);
//Select the div with id="content", where both tables are stored
Element contentDiv = doc.select("div#content").first();
//Create a list for the data
List tables = new ArrayList<Table>();
//Loop on h3 titles and get the coupled table below
for ( Element h3 : contentDiv.select("h3") )
{
//get the text inside <h3> tag
String h3Text = h3.text();
//jsoup select statement to get the table
//immediately after the <h3></h3>
String select = "h3:contains(" + h3Text + ") ~ table";
//Actually get the jsoup table element jTable
Element jTable = contentDiv.select(select).first();
//Load the data on the list
tables.add(new Table(h3Text,jTable));
}
//print them
for ( Table t : tables )
System.out.println(t);
//[...]
class Table
{
String h3Title;
String htmlTable;
String[][] splittedTable;
Table(String h3Title, Element jTable)
{
this.h3Title = h3Title;
this.htmlTable = jTable.html();
this.splittedTable = getSplittedTable(jTable);
}
String[][] getSplittedTable(Element jTable)
{
//Get all the rows of the jTable
Elements trs = jTable.select("tr");
//Get the number of rows
int rows = trs.size();
//Get the columns of the first row (the same of all the rows)
int columns = trs.first().select("td").size();
//Allocate new bidimensional array table
String[][] table = new String[rows][columns];
int i = 0; int j = 0;
for ( Element tr : trs ) {
for ( Element td : tr.select("td") ) {
table[i][j++] = td.text();
}
j = 0; //reset column cursor
i++; //increment row cursor
}
return table;
}
#Override
String toString() {
StringBuilder sb = new StringBuilder();
String ln = System.lineSeparator();
sb.append(h3Title + ln);
sb.append("--" + ln);
sb.append(this.htmlTable + ln);
sb.append("--" + ln);
for (int i = 0; i < splittedTable.length; i++) {
for (int j = 0; j < splittedTable[i].length; j++) {
sb.append(splittedTable[i][j] + " | ")
}
sb.append(ln + "--" + ln);
}
return sb.toString();
}
}
I have a requirement where, i am sending a json file to the server and the parsing happens at the server side. I have created the entries to the json file, now i want to store an image stored in imageview as an entry to the json file. Searched several previous posts but could not find exactly what to do. Any pointers would be of great help for storing the image in json format for sending through server.
If you want to include Image in a JSON object which you will be sending in a request, convert Image into Base64 string and put this string into the JSON object.
For example:
String encodedImage = Base64.encodeToString(byteArrayImage, Base64.DEFAULT);
Check:
How to convert a image into Base64 string?
Convert png or jpg image to Base64 string in Android
Try base64-encoding the image (like below, where the Uri is your Image - but beware: ImageView has no Getter for the ImageUri, so you have to store it by yourself!):
Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
ContentResolver cr = getContentResolver();
InputStream is = cr.openInputStream(uri);
byte[] data = getBytesFromFile(is);
byte[] encoded_data = Base64.encodeBase64(data);
data_string = new String(encoded_data);
Now you have an base64-encoded String data_string that you can send with your JSON request. On the server-side you just have to decode the String and save the picture.
Well, it's kind of experimental, but you can create an array of bytes out of the bitmap, and then create a new string with that array of bytes, and then send it to the server.
However, why don't you just send a POST request to save the image directly, without any experimental processing or parsing?
you have an ImageView
<ImageView
android:layout_width = "300dp"
android:layout_height = "300dp"
android:id = "#+id/Plaatjeid"
android:scaleType = "centerCrop"
android:text = "#string/BerttxtPlaatje"
android:layout_alignParentEnd="true"
/>
and in the codebehind
String plaatje="";
ImageView iv1 = (ImageView)findViewById(R.id.Plaatjeid);
iv1.buildDrawingCache();
Bitmap bitmap = iv1.getDrawingCache();
ByteArrayOutputStream stream=new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 90, stream);
byte[] image=stream.toByteArray();
plaatje = Base64.encodeToString(image, 0);
then you create your Json string
String mailMessage;
mailMessage="<?xml version='1.0'?>";
mailMessage=mailMessage + "<RiscNotification xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'";
mailMessage=mailMessage + "xmlns:xsd='htp://www.w3.org/2001/XMLSchema'>";
mailMessage = mailMessage + " <mail To>" + Mailto() + "</mail To>" ;//server7
mailMessage = mailMessage + "</RiskNotification>";
I have a seperate Class in which I send it
Attach the variables to the Class
GetMethodDemo JsonConnect = new GetMethodDemo();
JsonConnect.MailTo= Mailto();
JsonConnect.Picture=plaatje;
JsonConnect.bertactivity=this;
JsonConnect.execute();//staat in AANHET BEGIN
and my Class
package nl.yentel.finekinney;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.view.Gravity;
import android.widget.Toast;
public class GetMethodDemo extends AsyncTask<String, Void, String> {
String MailTo;
String Picture;
Activity bertactivity;
Bitmap bm;
public void BitMapFoto(Bitmap bitmap) {
bm = bitmap;
}
//#Override
protected String doInBackground(String... strings) {
//http://geekonjava.blogspot.com/2014/03/upload-image-on-server-in-android-using.html
String dBresultaat = "start";
try {
URL url = new URL("http://10.0.2.2:64489/Risico/Risico.asmx/sendMail");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
con.setDoOutput(true);
String jsonInputString = "";
jsonInputString = "{";
jsonInputString = jsonInputString + "\"MailTo\": \"" + MailTo.toString() + "\",";
jsonInputString = jsonInputString + "\"Picture\": \"" + Picture.toString() + "\"";
//if you take the Picture.toString in debug mode and put it in https://base64.guru/converter/decode/image you see the picture
jsonInputString = jsonInputString + "}";
try (OutputStream os = con.getOutputStream()) {
byte[] input = jsonInputString.getBytes("utf-8");
os.write(input, 0, input.length);
int code = con.getResponseCode();
System.out.println(code);
try (BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "utf-8"))) {
StringBuilder response = new StringBuilder();
String responseLine = null;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
System.out.println(response.toString());
return response.toString();
}
} catch (Exception e) {
e.printStackTrace();
return "catch twee";
}
} catch (Exception e) {
e.printStackTrace();
return "catch";
}
}
#Override
protected void onPreExecute() {
}
#Override
protected void onPostExecute(String s) {
// super.onPostExecute(s);
Activity activity = new Bert().activity;
Toast toast = Toast.makeText(bertactivity, s, Toast.LENGTH_LONG);
toast.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 0);
toast.show();
}
}
You should have your webservice in Framework 4.0. Framework 3.5 does not work
and the web.config shows
<configuration>
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="50000000"/>
</webServices>
</scripting>
</system.web.extensions>
<system.web>
My webmethod looks like this
[WebMethod()]
public string sendMail(sstring MailTo, string Picture)
{
string Resultstring = "";
int i;
MailMessage theMessage;
theMessage = new MailMessage();
// look if there is an attempt to hack the server
if ((MailBody.ToUpper()).IndexOf("SELECT") > 0 | (MailBody.ToUpper()).IndexOf("UPDATE") > 0)
{
Resultstring = "illegal string";
}
else
{
theMessage.From = new System.Net.Mail.MailAddress(ConfigurationManager.AppSettings["sender"]); // '"no-reply#taakmonitor.nl")
try
{
theMessage.To.Add(new MailAddress(MailFrom)); // also send a mail to the sender
}
catch (Exception ex)
{
Resultstring = "Mail address "+ MailFrom + " not ok "; //ex.Message; // als het formaat van het mail adres niet goed is
theMessage = null;
}
String FransGetsCopy = WebConfigurationManager.AppSettings["FransGetsCopy"];
String[] ToWhom = NullSafeString(MailTo).Split(',');
for (i = 0; i <= ToWhom.Length - 1; i++)
{
try
{
theMessage.To.Add(new MailAddress(ToWhom[i]));
}
catch (Exception ex)
{
Resultstring = Resultstring + " mail address " + ToWhom[i] + " not ok "; //ex.Message; // als het formaat van het mail adres niet goed is
theMessage = null;
}
}
// there should also be a stylesheet
string StyleText="";
try
{
StyleText = "";
var data = File.ReadAllText(Server.MapPath("~/App_Data/TextFile.txt"));
StyleText = data.ToString();
}
catch (Exception)
{
Resultstring = Resultstring + " No StyleText available. ";
}
theMessage.Subject = MailSubject;
theMessage.IsBodyHtml = true;
//the message is created in HTML with the style in the <head> and the MailBody in the body
theMessage.Body = "<html>" + StyleText + "<body>" + MailBody + "</body></html>";
// code copied from
// https://www.codeproject.com/Tips/569532/Submit-Images-to-Web-Service-and-Get-Them-Back
//in this piece of code I convert the Json picture data to a picture and attach it to the mail
try
{
byte[] data = Convert.FromBase64String(Picture);
var stream = new MemoryStream(data, 0, data.Length);
System.Drawing.Image img = System.Drawing.Image.FromStream(stream);
stream.Seek(0L, SeekOrigin.Begin);
theMessage.Attachments.Add(new Attachment(stream, "Picture.png"));
Resultstring = Resultstring + " image OK";
}
catch (Exception ex)
{
Resultstring = Resultstring + " image not OK";
}
SmtpClient MessageObject = new SmtpClient();
MessageObject.Host = ConfigurationManager.AppSettings["Host"];
MessageObject.Port = Int32.Parse(ConfigurationManager.AppSettings["Port"]);
MessageObject.EnableSsl = false;
MessageObject.Credentials = new System.Net.NetworkCredential(ConfigurationManager.AppSettings["Username"], ConfigurationManager.AppSettings["Password"]);
try
{
MessageObject.Send(theMessage);
Resultstring = Resultstring + " mail has been send.";
}
catch (Exception ex)
{
Resultstring = Resultstring + " mail has NOT been send.";
}
MessageObject = null;
theMessage = null;
}
return Resultstring;
}
at last I have a stylesheet TestFile.txt in the App_data folder attached
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-=1">
<meta content="text/html; charset=us-ascii">
<style>
h1{color:blue;}
.EditText{
background:#ff0000;/*rood*/
height:100;
font-size:10px;
color:#0000ff;/*blauw*/
}
.EditTextVervolg{
background:#00cc00;/*groen*/
font-size:20px;
color:#ffff00;/*geel*/
}
</style>
</head>
Have fun
I am getting JSON data from a web service and would like to display a progress bar while the data is downloading. All the examples I have seen use a StringBuilder like so:
//Set up the initial connection
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
connection.setReadTimeout(10000);
connection.connect();
InputStream stream = connection.getInputStream();
//read the result from the server
reader = new BufferedReader(new InputStreamReader(stream));
StringBuilder builder = new StringBuilder();
String line = "";
while ((line = reader.readLine()) != null) {
builder.append(line + '\n');
}
result = builder.toString();
I got the ProgressBar to work by downloading the data as a byte array, then converting the byte array to a String, but I'm wondering if there is a 'more correct' way to do this. Since I've found no other way of doing this, the following class can also serve as a working example, seems a bit of a hack, but it does work well.
package com.royaldigit.newsreader.services;
import android.os.AsyncTask;
import android.util.Log;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.royaldigit.newsreader.controller.commands.CommandInterface;
import com.royaldigit.newsreader.model.data.SearchResultDO;
import com.royaldigit.newsreader.model.data.SearchTermDO;
/**
* Gets news results from Feedzilla based on the search term currently stored in model.searchTermDO
*
* Sends progress update and returns results to the CommandInterface command reference:
* * command.onProgressUpdate(progress);
* * command.serviceComplete(results);
*
*
*/
public class FeedzillaSearchService {
private static final String TAG = "FeedzillaSearchService";
private static final String SERVICE_URI = "http://api.feedzilla.com/v1/categories/26/articles/search.json?q=";
private static final int STREAM_DIVISIONS = 10;
private CommandInterface command;
private SearchTermDO currentSearchTermDO;
private Integer maximumResults;
private DownloadTask task;
private ArrayList<SearchResultDO> results;
public Boolean isCanceled = false;
public void getData(CommandInterface cmd, SearchTermDO termDO, Integer maxResults){
command = cmd;
currentSearchTermDO = termDO;
//Feedzilla only allows count to be 100 or less, anything over throws an error
maximumResults = (maxResults > 100)? 100 : maxResults;
results = new ArrayList<SearchResultDO>();
task = new DownloadTask();
task.execute();
}
public void cancel() {
isCanceled = true;
if(task != null) task.cancel(true);
}
/**
* Handle GET request
*
*/
private class DownloadTask extends AsyncTask<Void, Integer, String> {
#Override
protected String doInBackground(Void...voids) {
String result = "";
if(currentSearchTermDO == null || currentSearchTermDO.term.equals("")) return result;
BufferedReader reader = null;
publishProgress(0);
try {
String path = SERVICE_URI + URLEncoder.encode(currentSearchTermDO.term, "UTF-8") + "&count=" + maximumResults;
Log.d(TAG, "path = "+path);
URL url = new URL(path);
//Set up the initial connection
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
connection.setReadTimeout(10000);
connection.connect();
int length = connection.getContentLength();
InputStream stream = connection.getInputStream();
byte[] data = new byte[length];
int bufferSize = (int) Math.ceil(length / STREAM_DIVISIONS);
int progress = 0;
for(int i = 1; i < STREAM_DIVISIONS; i++){
int read = stream.read(data, progress, bufferSize);
progress += read;
publishProgress(i);
}
stream.read(data, progress, length - progress);
publishProgress(STREAM_DIVISIONS);
result = new String(data);
} catch (Exception e) {
Log.e(TAG, "Exception "+e.toString());
} finally {
if(reader != null){
try {
reader.close();
} catch(IOException ioe) {
ioe.printStackTrace();
}
}
}
return result;
}
protected void onProgressUpdate(Integer... progress) {
int currentProgress = progress[0] * 100/STREAM_DIVISIONS;
if(!this.isCancelled()) command.onProgressUpdate(currentProgress);
}
#Override
protected void onPostExecute(String result){
if(!this.isCancelled()) downloadTaskComplete(result);
}
}
/**
*
* #param data
*/
private void downloadTaskComplete(Object data){
if(!isCanceled){
try {
Log.d(TAG, data.toString());
JSONObject obj = new JSONObject(data.toString());
JSONArray array = obj.getJSONArray("articles");
for(int i = 0; i < array.length(); i++){
SearchResultDO dataObj = new SearchResultDO();
dataObj.title = array.getJSONObject(i).getString("title");
dataObj.url = array.getJSONObject(i).getString("url");
dataObj.snippet = array.getJSONObject(i).getString("summary");
dataObj.source = array.getJSONObject(i).getString("source");
dataObj.date = array.getJSONObject(i).getString("publish_date");
dataObj.termId = currentSearchTermDO.id;
//Reformat date
SimpleDateFormat format1 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
try {
Date date = format1.parse(dataObj.date);
SimpleDateFormat format2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dataObj.date = format2.format(date);
} catch(ParseException pe) {
Log.e(TAG, pe.getMessage());
}
results.add(dataObj);
}
command.serviceComplete(results);
} catch(JSONException e){
Log.e(TAG, e.toString());
command.serviceComplete(results);
}
}
}
}
UPDATE: Here is the finished version of the class using the suggestions from Nikolay. I ended up using the StringBuilder after all. The previous version would break because some times connection.getContentLength() returns -1. This version degrades gracefully for that case. Tested this implementation quite a bit and it seems bulletproof.
package com.royaldigit.newsreader.services;
import android.os.AsyncTask;
import android.util.Log;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.royaldigit.newsreader.controller.commands.CommandInterface;
import com.royaldigit.newsreader.model.data.SearchResultDO;
import com.royaldigit.newsreader.model.data.SearchTermDO;
/**
* Gets news results from Feedzilla based on the search term currently stored in model.searchTermDO
*
* Sends progress update and returns results to the CommandInterface command reference:
* * command.onProgressUpdate(progress);
* * command.serviceComplete(results);
*
*/
public class FeedzillaSearchService implements SearchServiceInterface {
private static final String TAG = "FeedzillaSearchService";
private static final String SERVICE_URI = "http://api.feedzilla.com/v1/categories/26/articles/search.json?q=";
private CommandInterface command;
private SearchTermDO currentSearchTermDO;
private Integer maximumResults;
private DownloadTask task;
private ArrayList<SearchResultDO> results;
private Boolean isCanceled = false;
public void getData(CommandInterface cmd, SearchTermDO termDO, Integer maxResults){
command = cmd;
currentSearchTermDO = termDO;
//Feedzilla only allows count to be 100 or less, anything over throws an error
maximumResults = (maxResults > 100)? 100 : maxResults;
results = new ArrayList<SearchResultDO>();
task = new DownloadTask();
task.execute();
}
public void cancel() {
isCanceled = true;
if(task != null) task.cancel(true);
}
/**
* Handle GET request
*
*/
private class DownloadTask extends AsyncTask<Void, Integer, String> {
#Override
protected String doInBackground(Void...voids) {
String result = "";
if(currentSearchTermDO == null || currentSearchTermDO.term.equals("")) return result;
BufferedReader reader = null;
publishProgress(0);
try {
String path = SERVICE_URI + URLEncoder.encode(currentSearchTermDO.term, "UTF-8") + "&count=" + maximumResults;
Log.d(TAG, "path = "+path);
URL url = new URL(path);
//Set up the initial connection
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
connection.setReadTimeout(20000);
connection.connect();
//connection.getContentType() should return something like "application/json; charset=utf-8"
String[] values = connection.getContentType().toString().split(";");
String charset = "";
for (String value : values) {
value = value.trim();
if (value.toLowerCase().startsWith("charset=")) {
charset = value.substring("charset=".length());
break;
}
}
//Set default value if charset not set
if(charset.equals("")) charset = "utf-8";
int contentLength = connection.getContentLength();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuilder builder = new StringBuilder();
/**
* connection.getContentLength() can return -1 on some connections.
* If we have the content length calculate progress, else just set progress to 100 and build the string all at once.
*
*/
if(contentLength>-1){
//Odd byte array sizes don't always work, tried 512, 1024, 2048; 1024 is the magic number because it seems to work best.
byte[] data = new byte[1024];
int totalRead = 0;
int bytesRead = 0;
while ((bytesRead = stream.read(data)) > 0) {
try {
builder.append(new String(data, 0, bytesRead, charset));
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Invalid charset: " + e.getMessage());
//Append without charset (uses system's default charset)
builder.append(new String(data, 0, bytesRead));
}
totalRead += bytesRead;
int progress = (int) (totalRead * (100/(double) contentLength));
//Log.d(TAG, "length = " + contentLength + " bytesRead = " + bytesRead + " totalRead = " + totalRead + " progress = " + progress);
publishProgress(progress);
}
} else {
String line = "";
while ((line = reader.readLine()) != null) {
builder.append(line + '\n');
publishProgress(100);
}
}
result = builder.toString();
} catch (Exception e) {
Log.e(TAG, "Exception "+e.toString());
} finally {
if(reader != null){
try {
reader.close();
} catch(IOException ioe) {
ioe.printStackTrace();
}
}
}
return result;
}
protected void onProgressUpdate(Integer... progress) {
if(!this.isCancelled()) command.onProgressUpdate(progress[0]);
}
#Override
protected void onPostExecute(String result){
if(!this.isCancelled()) downloadTaskComplete(result);
}
}
/**
*
* #param data
*/
private void downloadTaskComplete(Object data){
if(!isCanceled){
try {
Log.d(TAG, data.toString());
JSONObject obj = new JSONObject(data.toString());
JSONArray array = obj.getJSONArray("articles");
for(int i = 0; i < array.length(); i++){
SearchResultDO dataObj = new SearchResultDO();
dataObj.title = array.getJSONObject(i).getString("title");
dataObj.url = array.getJSONObject(i).getString("url");
dataObj.snippet = array.getJSONObject(i).getString("summary");
dataObj.source = array.getJSONObject(i).getString("source");
dataObj.date = array.getJSONObject(i).getString("publish_date");
dataObj.termId = currentSearchTermDO.id;
//Reformat date
SimpleDateFormat format1 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
try {
Date date = format1.parse(dataObj.date);
SimpleDateFormat format2 = new SimpleDateFormat(SearchResultDO.DATE_FORMAT_STRING);
dataObj.date = format2.format(date);
} catch(ParseException pe) {
Log.e(TAG, pe.getMessage());
}
results.add(dataObj);
}
} catch(JSONException e){
Log.e(TAG, e.toString());
}
command.serviceComplete(results);
}
}
}
Well, since content length is reported in bytes, there is really no other way. If you want to use a StringReader you could take the length of each line you read and calculate the total bytes read to achieve the same thing. Also, the regular idiom is to check the return value of read() to check if you have reached the end of the stream. If, for some reason, the content length is wrong, your code may read more/less data then available. Finally, when converting a byte blob to a string, you should explicitly specify the encoding. When dealing with HTTP, you can get that from the 'charset' parameter of the 'Content-Type' header.
I had similar problem. I tried the solution of Jeremy C, but it was inaccurate, because value of "Content-Length" from header can be very different than real data.
My solution is:
Send HTTP header from server (PHP):
$string = json_encode($data, JSON_PRETTY_PRINT | JSON_FORCE_OBJECT);
header("X-Size: ".strlen($string)); //for example with name: "X-Size"
print($string);
Read correct value "X-size" for contentLength variable from HTTP header before read from stream:
protected String doInBackground(URL... urls) {
if (General.DEBUG) Log.i(TAG, "WebAsyncTask(doInBackground)");
String result = "";
BufferedReader reader = null;
try {
HttpURLConnection conn = (HttpURLConnection) urls[0].openConnection();
conn.setConnectTimeout(General.TIMEOUT_CONNECTION);
conn.setReadTimeout(General.TIMEOUT_SOCKET);
conn.setRequestMethod("GET");
conn.connect();
if (General.DEBUG) Log.i(TAG, "X-Size: "+conn.getHeaderField("X-Size"));
if (General.DEBUG) Log.i(TAG, "getHeaderField: "+conn.getHeaderFields());
if(conn.getResponseCode() != General.HTTP_STATUS_200)
return General.ERR_HTTP;
int contentLength = -1;
try {
contentLength = Integer.parseInt(conn.getHeaderField("X-Size"));
} catch (Exception e){
e.printStackTrace();
}
InputStream stream = conn.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuilder builder = new StringBuilder();
//Pokud delku zname:
if(contentLength > -1){
byte[] data = new byte[16]; //TODO
int totalRead = 0;
int bytesRead = 0;
while ((bytesRead = stream.read(data)) > 0){
Thread.sleep(100); //DEBUG TODO
try {
builder.append(new String(data, 0, bytesRead, "UTF-8"));
} catch (UnsupportedEncodingException e) {
Log.i(TAG, "Invalid charset: " + e.getMessage());
//Append without charset (uses system's default charset)
builder.append(new String(data, 0, bytesRead));
}
totalRead += bytesRead;
int progress = (int) (totalRead * (100/(double) contentLength));
Log.i(TAG, "length = " + contentLength + " bytesRead = " + bytesRead + " totalRead = " + totalRead + " progress = " + progress);
publishProgress(progress);
}
} else {
String line = "";
while ((line = reader.readLine()) != null) {
builder.append(line + '\n');
publishProgress(100);
}
}
result = builder.toString();
} catch (SocketException | SocketTimeoutException e){
if (General.DEBUG) Log.i(TAG, "SocketException or SocketTimeoutException");
e.printStackTrace();
return General.HTTP_TIMEOUT;
} catch (Exception e){
e.printStackTrace();
return General.ERR_HTTP;
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}