In my android application I am trying create persistent connection for downloading images. Here is my code
public class PersActivity extends Activity {
ImageView img;
String imageUrl="http://192.168.1.4/JRec/";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button bt3= (Button)findViewById(R.id.download);
bt3.setOnClickListener(getImgListener);
img = (ImageView)findViewById(R.id.image);
}
View.OnClickListener getImgListener = new View.OnClickListener()
{
#Override
public void onClick(View view) {
for (int i = 0; i<4;i++){
downloadFile(i,imageUrl+"images/"+i+".png");
}
}
};
Bitmap bmImg;
void downloadFile(int i, String fileUrl){
URL myFileUrl =null;
try {
myFileUrl= new URL(fileUrl);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
System.out.println("Opening connection");
HttpURLConnection conn= (HttpURLConnection)myFileUrl.openConnection();
conn.setRequestProperty("Connection", "keep-alive");
conn.setDoInput(true);
conn.connect();
System.out.println("Downloading"+fileUrl);
InputStream is = conn.getInputStream();
bmImg = BitmapFactory.decodeStream(is);
img.setImageBitmap(bmImg);
if (i ==3){
System.out.println("Disconnected");
conn.disconnect();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
When I start download the file every time it should open connection for download, I want to open connection only one time and when the application end downloading all files the connection must be disconnected. Is there any way to do this.
Thanks anyone who get attention on this.
Http connections are "stateless" so there is no connection to be kept open like say in an SSH connection;
So each image you download will be done in a separate request/connection. (that's also the web browser do it).
Also, why did you put the creation of the URL in a separate try/catch ?
That makes no sense because if you fail to create the URL object, you will get a null pointer when you will try to open the connection.
Related
In my app, when I press a button, a buffered reader should read a line of a text from a text file online.
As a test, if the text is read correctly, I want a toast to appear saying "success". If the read fails, such as because the phone has no connection to the internet, I want a toast to appear saying "failed".
However, if I turn on airplane mode, and then press the button, it simply seems to "hang" forever, and the "failed" toast never appears -- or it just crashes the app entirely.
This is the code I am using:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
new NotePadFileFromServer().execute();
}
});
public class NotePadFileFromServer extends AsyncTask<Void, Void, Void>{
#Override
protected Void doInBackground(Void... params) {
try {
url = new URL(TextFileURL);
bufferReader = new BufferedReader(new InputStreamReader(url.openStream()));
TextHolder = bufferReader.readLine();
bufferReader.close();
} catch (Exception e) {
Toast.makeText(MainActivity.this, "Fail!", Toast.LENGTH_SHORT).show();
}
return null;
}
#Override
protected void onPostExecute(Void finalTextHolder) {
Toast.makeText(MainActivity.this, "Success!", Toast.LENGTH_SHORT).show();
super.onPostExecute(finalTextHolder);
}
}
I tried adding in a pre-check using ConnectivityManager to test if there is an internet connection as per this code: https://stackoverflow.com/a/58146646/4250107, but that only works if the phone user has specifically turned off the internet, and the crashes occur again if the wifi function is turned on, but there is no internet. I then tried checking the internet connection, as per this code: https://stackoverflow.com/a/58146896/4250107, but this also crashes the app, as apparently (?) attempting to ping a server does not work on Samsung phones.
EDIT: Final fixed code.
public class NotePadFileFromServer extends AsyncTask<Void, Void, String>{
#Override
protected String doInBackground(Void... params) {
try {
URLConnection url = new URL(TextFileURL).openConnection());
url.setConnectTimeout(1000);
url.setReadTimeout(1000);
bufferReader = new BufferedReader(new InputStreamReader(url.getInputStream()));
TextHolder = bufferReader.readLine();
bufferReader.close();
return "Success!";
} catch (Exception e) {
return "Fail!";
}
}
#Override
protected void onPostExecute(String success) {
Toast.makeText(MainActivity.this, success, Toast.LENGTH_SHORT).show();
super.onPostExecute(success);
}
}
The app is crashing because you are trying to perform UI related task in the Background Thread when there is an exception. So, the following is responsible for the crash,
catch (Exception e) {
Toast.makeText(MainActivity.this, "Fail!", Toast.LENGTH_SHORT).show();
}
So, you can avoid the crash by refactoring you code in the following way,
public class NotePadFileFromServer extends AsyncTask<Void, Void, String>{
#Override
protected String doInBackground(Void... params) {
try {
url = new URL(TextFileURL);
bufferReader = new BufferedReader(new InputStreamReader(url.openStream()));
TextHolder = bufferReader.readLine();
bufferReader.close();
return "Success!";
} catch (Exception e) {
return "Fail!";
}
}
#Override
protected void onPostExecute(String finalTextHolder) {
Toast.makeText(MainActivity.this, finalTextHolder, Toast.LENGTH_SHORT).show();
super.onPostExecute(finalTextHolder);
}
}
And in case of timeout issue which you described here as hang, I would recommend you to use openConnection() (which returns a UrlConnection) instead of openStream(). So that you can set shorter connection and read timeout.
Yes, as you say ConnectivityManager will not help you because if you have wifi but no internet it will crash.
However, it is possible to check internet connection. I couldn't do it with ping (same as you), but i could when i try to open a socket to some of the opened ports (80 or 443). Here is a code using rxjava but you can adapt it to what you are using.
fun isOnline(context: Context?): Single<Boolean> {
return Single.fromCallable {
try {
// Connect to Google DNS to check for connection
val timeoutMs = 2500
val socket = Socket()
val address = InetAddress.getByName("www.google.com")
val socketAddress = InetSocketAddress(address, 443)
socket.connect(socketAddress, timeoutMs)
socket.close()
true
} catch (e: Exception) {
false
}
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
In my case i opened the socket with my backend so also i can check if it is working. I put www.google.com in case you don't have a backend.
The way to use it is:
isOnline(context).subscribe { hasInternet ->
//Conditional check
}
I new to android programming and I had some problem that needs help, I'm stuck at this part for quite some time.
Problem: the code is successfully compiled, but making the connection to check make it crash. Can you help me by telling what is causing the issue and suggest me the solution or help improve my code. Thank you.
Process: the app check whether the app it wants to check is exist in google play store or not by checking its package name by sending simple HTTP connection. If the connection success to the app page in google play store, it will output a string that the page exists and it's a legit app.
Here is a snippet of my code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
output3 = findViewById(R.id.output3);
output3.setMovementMethod(ScrollingMovementMethod.getInstance());
connection();
}
public void connection(){
try {
String packagename = "com.facebook.katana";
URL url = new URL("http://play.google.com/store/apps/details?id="+packagename+"&hl=en");
URLConnection urlConn = url.openConnection();
HttpURLConnection con = (HttpURLConnection) urlConn;
con.setUseCaches(false);
con.setAllowUserInteraction(false);
con.setRequestMethod("GET");
con.connect();
int status = con.getResponseCode();
if (status == HttpURLConnection.HTTP_NOT_FOUND){
output3.append("not from google play store");
}
if (status == HttpURLConnection.HTTP_OK) {
output3.append("google App Store");
}
if (status != HttpsURLConnection.HTTP_NOT_FOUND && status != HttpsURLConnection.HTTP_OK)
output3.append("Other Response");
con.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
First of all HTTP requests are no longer support on the main thread so you must use a parallel Thread, or simple use an AsyncTask. Check below code for AsyncTask.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
output3 = findViewById(R.id.output3);
output3.setMovementMethod(ScrollingMovementMethod.getInstance());
AsyncTask.execute(new Runnable() {
#Override
public void run() {
connection();
}
});
}
Second thing is make sure Internet permission is added in your manifest.
in manifest:
<uses-permission android:name="android.permission.INTERNET">
in the onCreate method:
webImage = (ImageView) findViewById(R.id.webimage);
String urlImage = "https://thetab.com/blogs.dir/91/files/2017/01/maxresdefault-1.jpg";
// Set setImageBitmap to Bitmap created by getURLBitmap method
webImage.setImageBitmap(getURLBitmap(urlImage));
in the getURLBitmap method:
if(!urlString.isEmpty() || urlString != null) {
InputStream inputStream = null;
// pass the string into a URL object
try {
URL urlForImage = new URL(urlString);
// cast url openConnection into HttpURLConnection
HttpURLConnection connection = (HttpURLConnection) urlForImage.openConnection();
// Set HttpURLConnection setDoInput to true
connection.setDoInput(true);
// Start HttpURLConnection connection
connection.connect();
if(connection.getResponseCode() == 200) {
// Start reading Http inputStream (getInputStream) and use it to initialize a InputStream object
inputStream = connection.getInputStream();
// pass InputStream object into a BitmapFactory's decodeStream (is a static method)
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
// set Bitmap object to decodedStream
return bitmap;
}
// return Bitmap
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
I keep getting this error:
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.EX.perfectmoment, PID: 26747
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.EX.perfectmoment/com.example.EX.perfectmoment.MemeMainActivity}: android.os.NetworkOnMainThreadException
You are getting this error because you are running a network operation on the UI thread, which is something that is very looked down upon in Android Dev as it often results in an unresponsive UI and thus, a bad user experience. I recommend either creating your own ASyncTask, which would do the network operations in another thread and feed it back to the UI thread, or use one of the many popular image libraries there are for Android, such as Picasso or Glide.
As said in above comment running network task on UI thread in android no longer supported so you have to do UI blocking task on separate thread either using AsyncTask or some other thread mechanism available.
So by using AsynTask you can do it like mention below code snippet.
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class MainActivity extends AppCompatActivity{
ImageView webImage;
private static final String TAG = MainActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webImage = (ImageView) findViewById(R.id.imageView1);
new SetImage().execute();
}
private class SetImage extends AsyncTask<Void, Void, Bitmap>{
final String urlImage = "https://thetab.com/blogs.dir/91/files/2017/01/maxresdefault-1.jpg";
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Bitmap doInBackground(Void... params) {
Bitmap image = getURLBitmap(urlImage);
return image;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
webImage.setImageBitmap(bitmap);
}
}
private Bitmap getURLBitmap(String urlString){
if(!urlString.isEmpty() || urlString != null) {
InputStream inputStream = null;
// pass the string into a URL object
try {
URL urlForImage = new URL(urlString);
// cast url openConnection into HttpURLConnection
HttpURLConnection connection = (HttpURLConnection) urlForImage.openConnection();
// Set HttpURLConnection setDoInput to true
connection.setDoInput(true);
// Start HttpURLConnection connection
connection.connect();
if(connection.getResponseCode() == 200) {
// Start reading Http inputStream (getInputStream) and use it to initialize a InputStream object
inputStream = connection.getInputStream();
// pass InputStream object into a BitmapFactory's decodeStream (is a static method)
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
// set Bitmap object to decodedStream
return bitmap;
}
// return Bitmap
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
I want to send a simple string to a server on my desktop PC. Here is what I have on my PC:
public static void main(String[] args) {
System.out.println("Server Started");
Server server = new Server();
server.start();
}
public void start(){
try {
ServerSocket SRVSOCK = new ServerSocket(333);
Socket SOCK = SRVSOCK.accept();
InputStreamReader ir = new InputStreamReader(SOCK.getInputStream());
BufferedReader bf = new BufferedReader(ir);
String MESSAGE = bf.readLine();
System.out.println(MESSAGE);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
For my android tablet I have this in the onCreate():
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Thread tthread = new Thread(new Runnable(){
#Override
public void run() {
Connect();
}});
}
public void Connect(){
try {
Socket SOCK = new Socket("10.0.0.3", 333);
PrintWriter pw = new PrintWriter(SOCK.getOutputStream());
pw.println("FROM ANDROID!");
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I have seen you can create a new thread which you need (otherwise the app UI freezes), but it still does not send the text to my server, I have added the incoming and outgoing port in my windows firewall, and even tried to turn off the firewall, but still no luck..
The android code is running on a real physical tablet (Nexus 7 2013) and not an emulator.
What is wrong here?
This whats in my log cat when the app is opened
03-24 13:43:59.695: I/ActivityManager(768): START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.hashimo.mcpeworldconverter/.MainActivity bnds=[200,1314] [400,1590] (has extras)} from uid 10022 on display 0
03-24 13:43:59.780: I/ActivityManager(768): Start proc com.hashimo.mcpeworldconverter for activity com.hashimo.mcpeworldconverter/.MainActivity: pid=6724 uid=10140 gids={50140, 9997, 1028, 1015, 3003} abi=armeabi-v7a
03-24 13:44:00.338: I/ActivityManager(768): Displayed com.hashimo.mcpeworldconverter/.MainActivity: +592ms
You are declaring a Thread but you forgot to .start() it. So your code is not executed.
I've been trying to create a function in my app that consist in a bluetooth RFID scanner, it's paired to my device and I have it working and all.
I can receive the text and log it in the console, when I compile the activity, everything goes fine, the stick reads the code, and then appends the text into an EditText, but if I go back and enter the activity again, I can see the code in the log, but the text doesn't go to the Edittext.
I tried a lot of different approaches, but nothing seems to work :/
here's the code I have:
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bluetooth);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> bondedSet = mBluetoothAdapter.getBondedDevices();
if (mBluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth is not available.", Toast.LENGTH_LONG).show();
}
if (!mBluetoothAdapter.isEnabled()) {
Toast.makeText(this, "Please enable your BT and re-run this program.", Toast.LENGTH_LONG).show();
finish();
}
if (mBluetoothAdapter.isEnabled()) {
if(bondedSet.size() == 1){
for(BluetoothDevice device : bondedSet){
address = device.getAddress();
Log.d("bt:", address);
}
}
}
String address = "00:A0:96:2A:0A:1B";
out = (EditText) findViewById(R.id.output);
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
Log.d(TAG, device.getName() + " connected");
myConnection = new ConnectThread(device);
myConnection.start();
}
private class ConnectThread extends Thread {
private final BluetoothSocket mySocket;
Message msg;
public ConnectThread(BluetoothDevice device) {
BluetoothSocket tmp = null;
try {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.d(TAG, "CONNECTION IN THREAD DIDNT WORK");
}
mySocket = tmp;
}
Handler uiThreadHandler = new Handler() {
public void handleMessage(Message msg) {
out = (EditText) findViewById(R.id.output);
Object o = msg.obj;
out.append(o.toString().trim());
Log.d("handler", o.toString());
}
};
public void run() {
out = (EditText) findViewById(R.id.output);
Log.d(TAG, "STARTING TO CONNECT THE SOCKET");
setName("My Connection Thread");
InputStream inStream = null;
boolean run = false;
mBluetoothAdapter.cancelDiscovery();
try {
mySocket.connect();
run = true;
} catch (IOException e) {
Log.d(TAG, this.getName() + ": CONN DIDNT WORK, Try closing socket");
try {
mySocket.close();
Log.d(TAG, this.getName() + ": CLOSED SOCKET");
} catch (IOException e1) {
Log.d(TAG, this.getName() + ": COULD CLOSE SOCKET", e1);
this.destroy();
}
run = false;
}
synchronized (BluetoothActivity.this) {
myConnection = null;
}
byte[] buffer = new byte[1024];
int bytes;
// handle Connection
try {
inStream = mySocket.getInputStream();
while (run) {
try {
bytes = inStream.read(buffer);
readMessage = new String(buffer, 0, bytes);
msg = uiThreadHandler.obtainMessage();
msg.obj = readMessage;
uiThreadHandler.sendMessage(msg);
Log.d(TAG, "Received: " + readMessage);
} catch (IOException e3) {
Log.d(TAG, "disconnected");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
My guess is that this has something to do with the Thread itself. When you start your Activity for the first time, you also call .start() on the Thread, that would work fine.
The problem is when you leave your Activity and open it up again. In that case, one of onStop() or onPause() is called (depending on situation), and onRestart() or onResume() will be called afterwards respectively.
The trick comes now: Meanwhile all that process, your Thread is still running. As you show your code, it has not been stopped/paused, and keeps running all the time. So basically my tip is that there's something you do within your onCreate() method of your Activity that should also be done in your onPause() and onStop() events, and my another tip it's somewhere within your ConnectThread(BluetoothDevice device) method.
To know how to procceed, I'd firstly define both onStop() and onPause() methods within your Activity and see which is fired, log every attribute to see its value/state, and that way you'll be able to debug what is failing.
There's a diagram of the Activity lifecycle.
Problem was solved, the code works, and the TextView get the inputstream, the problem was when i left the activity, the thread continued to work, so far, no problem at all, after TONS of hours spent on this, i turn the TextView a static var and it worked :)
If anyone reads this, i hope it helps.