I created a C# server that sends an Bitmap through a socket to android client. That Bitmap is constantly updating because it's a video feed.
Server C#
private void send_data() {
ImageConverter converter = new ImageConverter();
byte[] sendBytes = (byte[]) converter.ConvertTo(master.picturebox_master.Image, typeof(byte[]));
string_master_frame = System.Text.Encoding.UTF8.GetString(sendBytes);
string_master_frame = Convert.ToBase64String(sendBytes);
data = string_master_frame + "\n";
tcpServer1.Send(data);
}
Client Android
#Override
protected Void doInBackground(Void... arg0) {
Socket socket = null;
try {
socket = new Socket(dstAddress, dstPort);
Scanner r = new Scanner(new InputStreamReader(socket.getInputStream()));
while (true) {
valores[26] = r.nextLine();
publishProgress(valores[26]);
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
byte[] decodedString = Base64.decode(values[26], Base64.NO_WRAP);
Bitmap master_bitmap = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
master_frame.setImageBitmap(master_bitmap);
}
The first frame is sent and the Android client displays it correctly. But when the next frame comes, the Android Client Crashes.
Error:
Process: com.example.tiago.java_android, PID: 826
java.lang.IllegalArgumentException: bad base-64
at android.util.Base64.decode(Base64.java:161)
at android.util.Base64.decode(Base64.java:136)
at android.util.Base64.decode(Base64.java:118)
at com.example.tiago.java_android.Cliente.onProgressUpdate(Cliente.java:228)
at com.example.tiago.java_android.Cliente.onProgressUpdate(Cliente.java:28)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:656)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5431)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:914)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:707)
I though the valores[26] data was being corrupted but it's not. I get the data correctly.
I used http://codebeautify.org/base64-to-image-converter to check if I get the data correctly.
Any idea?
PS: I lost my account so I had to make this one.
Bitmap master_bitmap;
byte[] decodedString = Base64.decode(values[26],Base64.NO_WRAP);
master_bitmap = BitmapFactory.decodeByteArray(decodedString,0,decodedString.length);
if(master_bitmap != null)
{
try {
master_frame.setImageBitmap(master_bitmap);
}
catch (IllegalArgumentException e)
{
e.printStackTrace();
}
}
master_bitmap.recycle();
}
Didnt work. Error:
java.lang.RuntimeException: Canvas: trying to use a recycled bitmap
Did you try with try/catch block I explained previously?
Recall:
I had the same problem and I am almost sure this will solve your problem:
String[] safe = values[26].split("=");
byte[] decodedString = Base64.decode(safe[0],Base64.NO_WRAP);
Bitmap master_bitmap = BitmapFactory.decodeByteArray(decodedString,0,decodedString.length);
master_frame.setImageBitmap(master_bitmap);
master_bitmap.recycle(); //THIS LINE WAS ENOUGH TO FIX MY CODE
Also, don't forget to use try/catch blocks effectively.
try{ //code here}
catch(IllegalArgumentException e){ //code here if you want}
(Add more catch statements if necessary.)
My full code for further help:
byte[] bytearray = Base64.decode(dataIn);
Bitmap myBitmap = BitmapFactory.decodeByteArray(bytearray, 0,bytearray.length);
if (myBitmap!=null) {
//some irrelevant code here to turn bitmap to a PImage (a Processing image class)
}
myBitmap.recycle();
This works perfectly for me.
Try also this:
try {
Bitmap master_bitmap;
master_bitmap=BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
if (master_bitmap != null) { //might be an unnecessary if condidition
try {
if (((BitmapDrawable)master_frame.getDrawable()).getBitmap()!=null) {
((BitmapDrawable)master_frame.getDrawable()).getBitmap().recycle();
}
master_frame.setImageBitmap(master_bitmap);
//maybe try here: master_bitmap.recycle();
}
catch(RuntimeException e) {
e.printStackTrace();
}
}
}
catch (IllegalArgumentException e) {
e.printStackTrace();
}
Related
I am sending a screenshot from java server hosted on a machine. The screenshot would be send to an android device through sockets in form of a byte stream array. But the array which I am getting in the android device is not getting converted to bitmap. Below I am attaching the java server code, android code and the logcat.
Here is the java server code for sending the screenshot captured.
socket2 = serverSocket2.accept();
System.out.println("A client has connected");
Robot robot = new Robot();
String format = "jpg";
String fileName = "FullScreenshot." + format;
Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage screenFullImage = robot.createScreenCapture(screenRect); // captured image
ImageIO.write(screenFullImage, format, new File("C:\\Users\\User\\Desktop\\"+fileName));
ByteArrayOutputStream bao=new ByteArrayOutputStream();
ImageIO.write(screenFullImage,format,bao);//ye
byte[] ar=bao.toByteArray();
System.out.println("Parental block is executed");
mainWriter = new BufferedWriter(new OutputStreamWriter(socket2.getOutputStream()));
mainWriter.write(java.util.Arrays.toString(ar));
mainWriter.newLine();
mainWriter.flush();
System.out.println("A full screenshot saved!");
serverSocket2.close();
socket2.close();
mainWriter.close();
Testing t = new Testing();
Here is the android code where I am getting the byte stream array.
public void PCConnection(final View view) // just for this activity
{
new Thread()
{
public Socket socket;
public void run()
{
try
{
Log.i(DebuggString,"Attempting to connect to the server");
socket = new Socket(hostname,60120);
Log.i(DebuggString,"Connection established");
mivScreenShot = (ImageView) findViewById(R.id.ivScreenShot);
//Receive message from the server
//Message is stored in the br.readLine()
brr = new BufferedReader(new InputStreamReader(socket.getInputStream()));
img = brr.readLine();
Log.d("Image", img);//yeh byte[] display karta h
final ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(img.getBytes());
arrayInputStream.reset();
this.socket.close();
runOnUiThread(new Runnable() {
#Override
public void run() {
Glide.with(ParentalControl.this)
.load(bitmap)
.asBitmap()
.into(mivScreenShot);
}
});
if(bitmap!=null)
{
Log.d(DebuggString,"Bitmap is not null "); // oh ok koi nai
}
else
{
Log.d(DebuggString,"Bitmap is null");
}
}
catch (IOException e )
{
e.printStackTrace();
}
}
}.start();
}
Here I am attaching the logcat screenshot url: https://i.imgur.com/167Vje3.png
mainWriter = new BufferedWriter(new OutputStreamWriter(socket2.getOutputStream()));
mainWriter.write(java.util.Arrays.toString(ar));
You cannot use writers and strings to send a jpg image as those are for text only. Do away with them. Do away with the ByteOutputStream too as you can just directly compress the bitmap to the outputstream of the socket.
Further check how many bytes you send and how many are received.
That was for the server. Also on the receiving side you cannot use readers and strings.
I'm relatively new to android, and I'm trying to modify an android app such that it downloads a profile picture (preferably in PNG) from a URL, and saves it in the com.companyName.AppName.whatever/files. It should be noted that the app was initially created in Unity, and just built and exported.
Here's my initial code:
URL url = null;
try {
url = new URL(playerDO.getProfileURL());
} catch (MalformedURLException e) {
e.printStackTrace();
}
InputStream input = null;
try {
input = url.openStream();
} catch (IOException e) {
e.printStackTrace();
}
String fileName = playerDO.getId() + ".png";
FileOutputStream outputStream = null;
try {
outputStream = openFileOutput(fileName, Context.MODE_PRIVATE);
byte[] buffer = new byte[256];
int bytesRead = 0;
while ((bytesRead = input.read(buffer, 0, buffer.length)) >= 0) {
outputStream.write(buffer, 0, bytesRead);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
EDIT: Here's my other code, as suggested by #Ashutosh Sagar
InputStream input = null;
Bitmap image = null;
try {
input = url.openStream();
image = BitmapFactory.decodeStream(input);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
String fileName = playerDO.getId() + ".png";
FileOutputStream outputStream = null;
File myDir = getFilesDir();
try {
Log.wtf("DIRECTORY", myDir.toString());
File imageFile = new File(myDir, fileName);
if (!imageFile.exists()){
imageFile.createNewFile();
Log.wtf("ANDROID NATIVE MSG: WARN!", "File does not exist. Writing to: " + imageFile.toString());
}
outputStream = new FileOutputStream(imageFile, false);
image.compress(Bitmap.CompressFormat.PNG, 90, outputStream);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
input.close();
} catch (IOException e) {
e.printStackTrace();
Log.wtf("AWWW CRAP", e.toString());
}
}
(It doesn't write either).
Unfortunately, I've had several problems with this. My primary issue is that when it (on the cases that it does) runs, it actually doesn't save anything. I'll go and check com.companyName.AppName.whatever/files directory only to find no such .png file. I will also need it to overwrite any existing files of the same name, which is hard to check when it doesn't work.
My secondary issue is that it fails to take into account delays in internet connection. Although I've put in enough try-catch clauses to stop it from crashing (as it used to), the end result is that it also doesn't save.
How can I improve upon this? Anything I'm missing?
EDIT:
Printing out the directory reveals it should be in:
/data/user/0/com.appName/files/5965e9e4a0f0463853016e2b.png
However, using ES File explorer, the only thing remotely close to that is
emulated/0/Android/data/com.appName/files/
Are they the same directory?
try this first get bitmap image from url
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(url).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.d("Error", e.getStackTrace().toString());
}
and to save bitmap image please check the ans of GoCrazy
Try this
void getImage(String string_url)
{
//Generate Bitmap from URL
URL url_value = new URL(string_url);
Bitmap image =
BitmapFactory.decodeStream(url_value.openConnection().getInputStream());
//Export File to local Directory
OutputStream stream = new FileOutputStream("path/file_name.png");
/* Write bitmap to file using JPEG or PNG and 80% quality hint for JPEG. */
bitmap.compress(CompressFormat.PNG, 80, stream);
stream.close();
}
So I have an app which downloads certain files, dedicated to a client of mine who is hosting his files on a remote location, and i'm doing so using the code below:
public class DownloadService extends IntentService {
private int result = Activity.RESULT_CANCELED;
public DownloadService() {
super("DownloadService");
}
#Override
protected void onHandleIntent(Intent intent) {
String urlPath = intent.getStringExtra(URL);
String fileName = intent.getStringExtra(FILENAME);
File output = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
fileName);
if (output.exists()) {
output.delete();
}
URLConnection streamConnection = null;
InputStream stream = null;
FileOutputStream fos = null;
try {
URL url = new URL(urlPath);
streamConnection = url.openConnection();
stream = streamConnection.getInputStream();
streamConnection.connect();
long lengthofFile = streamConnection.getContentLength();
InputStream reader = stream;
bis = new BufferedInputStream(reader);
fos = new FileOutputStream(output.getPath());
int next = -1;
int progress = 0;
int bytesRead = 0;
byte buffer[] = new byte[1024];
while ((bytesRead = bis.read(buffer)) > 0) {
fos.write(buffer, 0, bytesRead);
progress += bytesRead;
int progressUpdate = (int)((progress * 100) / lengthofFile);
Intent testIntent = new Intent(".MESSAGE_INTENT");
testIntent.putExtra(PERCENTAGE, progressUpdate);
sendBroadcast(testIntent);
}
result = Activity.RESULT_OK;
fos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stream != null) {
try {
stream.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
publishResults(output.getAbsolutePath(), result);
}
private void publishResults(String outputPath, int result) {
Intent intent = new Intent(".MESSAGE_INTENT");
intent.putExtra(FILEPATH, outputPath);
intent.putExtra(RESULT, result);
sendBroadcast(intent);
}
}
and to call this service i would use:
Intent intent = new Intent(MainActivity.getAppContext(), DownloadService.class);
intent.putExtra(DownloadService.FILENAME, downloadFileName[item]);
intent.putExtra(DownloadService.URL, urlDownload[item]);
MainActivity.getAppContext().startService(intent);
now this allows user to download one file at a time, however if the user downloads another file, the second file will have to wait till the first file is done downloading.
now what is happening in my case is:
1- First download FILE_1 is downloading, and in the status is says FILE_1.
2- User clicks a new file download, the status changes the first file name to the second file name, and waits till FILE_1 finishes download to start with FILE_2 however the active download is changed from FILE_1 to FILE_2.
questions:
is there a way to call DownloadService multiple times for multiple files?
is it possible to fix the problem i'm facing? treating download intent services as two different intents?
UPDATE
I managed to solve this issue by assigning a unique Int ID per file, each ID will point to a position in the listview which displays the files being downloaded or queued, then i work with each file on it's own.
Following code uses commons-io-2.4.jar library to make your work easy by handling low level data movements as you would focus on method in hand
URL someUrl = new URL("your url String"); //
File someFile = new File("your file, where you want to save the data");
FileUtils.copyURLToFile(someUrl, someFile );
if you want to call this statement few time to download different files from the server following code might give you an idea what you might want to do, but you will have to write it's equivalent code to run in android which you want to probably AsyncTask
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.commons.io.FileUtils;
public class DownloadTest {
public static void main(String[] args) {
Thread thread = new Thread(){
#Override
public void run() {
// TODO Auto-generated method stub
super.run();
try {
dowanloadFile(new URL("some url"), new File("some file"));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
thread.start();
}
private static void dowanloadFile(URL url, File file){
try {
FileUtils.copyURLToFile(url, file );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I'm trying to load a gif from a url to be displayed in an Imageview, store it in the internal storage and then later read it again. But it refuses to either store the image or reading it, not sure which one because I get no exceptions. Loading the image to the imageview works. The first method below (loadImage())
public Bitmap loadImage(String url){
Bitmap bm = null;
URL request;
try {
if(url!=null){
request = new URL(url);
InputStream is = request.openStream();
bm = BitmapFactory.decodeStream(is);
is.close();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bm;
}
public String writeGifToInternalStorage (Bitmap outputImage) {
try {
String fileName = String.valueOf(Calendar.getInstance().getTimeInMillis());
ByteBuffer byteBuffer = ByteBuffer.allocate(outputImage.getByteCount());
outputImage.copyPixelsToBuffer(byteBuffer);
byteBuffer.flip();
byte[] data = new byte[byteBuffer.limit()];
byteBuffer.get(data);
FileOutputStream fos = ctx.openFileOutput(fileName, Context.MODE_PRIVATE);
fos.write(data);
fos.close();
return fileName;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public Bitmap readFileFromInternalStorage(String filename) {
if (filename == null) return null;
FileInputStream fis;
try {
fis = ctx.openFileInput(filename);
return BitmapFactory.decodeStream(fis);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
Any ideas of whats wrong?
Your method readFileFromInternalStorage read an encoded image from the file system. This image file should be what you receive from the server.
For that, you need to save the image when you receive it from the server, for example like so:
InputStream is = new BufferedInputStream(request.openStream());
String fileName = String.valueOf(Calendar.getInstance().getTimeInMillis());
FileOutputStream fos = ctx.openFileOutput(fileName, Context.MODE_PRIVATE);
byte[] buffer = new byte[1024];
int red = 0;
while ((red = is.read(buffer)) != -1) {
fos.write(buffer,0, red);
}
fos.close();
is.close();
Then, your image is saved to the disk, and you can open it using your readFileFromInternalStorage method.
Also, if you use HttpClient instead of URL, I wrote a one-liner for downloading a file: Android download binary file problems
i've an activity with a button and a label.
On button click my app must download several files ( about 9000 ).
If user clicks again on button, the download must stop and on another click it must start from the beginning.
So this is what i do:
In activity:
file.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Button b = (Button)v;
if(canFile){
b.setText("Stop download");
changeLabelInfo("Getting file list...");
labelFile.setVisibility(View.VISIBLE);
fileTask.start();
}else{
b.setText("Download files");
if(fileTask.isAlive()){
fileTask.interrupt();
fileTask = null;
fileTask = new UpdateFilesThread(this);
}
labelFile.setVisibility(View.INVISIBLE);
Kernel.setManualUpdate("file",false);
}
canFile = !canFile;
}
});
The thread that must download files is UpdateFilesThread:
public class UpdateFilesThread extends Thread{
private MainActivity activity;
private final String rootPath = "/mnt/local/";
public UpdateFilesThread(MainActivity activity){
this.activity = activity;
}
public void run(){
String json = getFilesURL();
JSONObject a = (JSONObject)JSONValue.parse(json);
boolean isZip = false,canDownload = true;
String[] keys = new String[]{"key1","key2","key3","key4"};
for(String key:keys){
Object folder = (Object)a.get(key);
if(folder instanceof JSONObject){
JSONObject fold = (JSONObject)folder;
for(Object path_o:fold.keySet()){
path = path_o.toString().replace(" ", "%20");
if(local.endsWith(".php")){
isZip = true;
try {
Jsoup.connect(mywebserviceURL).data("path",path).timeout(0).post(); // If php generate zip containing php file
} catch (IOException e) {
canDownload = false;
}
}
if(canDownload){
try{
if(downloadFromUrl(path,isZip))
//SAVE URL DOWNLOADED
}catch(Exception e){
e.printStackTrace();
}
}
canDownload = true;
isZip = false;
}
}
}
a.remove(key);
}
private String getFilesURL(){
try {
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("type", new StringBody("all"));
HttpPost post = new HttpPost("mywebserviceURL");
post.setEntity(entity);
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(post);
return EntityUtils.toString(response.getEntity());
} catch (UnsupportedEncodingException e) {
Support.writeError(e, null);
e.printStackTrace();
return "";
} catch (ClientProtocolException e) {
Support.writeError(e, null);
e.printStackTrace();
return "";
} catch (ParseException e) {
Support.writeError(e, null);
e.printStackTrace();
return "";
} catch (IOException e) {
Support.writeError(e, null);
e.printStackTrace();
return "";
}
}
public boolean downloadFromUrl(String path,boolean isZip){
InputStream is = null;
FileOutputStream fos = null;
String localFilename = rootPath+path;
String local = isZip?rootPath+"tmp.zip":localFilename;
boolean return_ = false;
try {
URL url = new URL(isZip?mywebserviceURLZip:mywebserviceURLZip+path);
URLConnection urlConn = url.openConnection();
urlConn.setReadTimeout(0);
is = urlConn.getInputStream();
fos = new FileOutputStream(local);
byte[] buffer = new byte[51200];
int len;
while ((len = is.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
is.close();
if(isZip){
ZipFile zip = new ZipFile(local);
zip.extractAll(rootPath);
new File(local).delete();
}
return_= true;
}catch(Exception e){
e.printStackTrace();
return false;
}
return return_;
}
}
My problem borns when user clicks two time the button ( stop downloading and start again ).
The prompt error says that the thread is already startend and in running.. how can i solve it? I know that asyncTask should be better but i've problem cause in my application there are so many thread running and the device is so poorly peforming..
It's possible to stop definitelly a thread? are there other better solution?
Try implementing an AsyncTask. When the user first taps the button call the task's execute (Params... params). On the second tap call the task's cancel (boolean mayInterruptIfRunning). Put the download functionality in the task's doInBackground (Params... params)
Your run thread needs to occasionally check isInterrupted() and exit if it returns true. Otherwise the thread will never be canceled.
I think your entire architecture is wrong though. Downloading 9000 files onto a mobile phone? Even if each file is only 1KB, that's a huge amount of memory for a mobile app. And at the very least you ought to zip up that data and download a zip, for your own sanity.