Android 9.0: HTTP request throws exception in "Minimize mode" - java

Every HTTP request throws failed to connect to Server wherever App goes in sleep or minimize mode. This only happens in Android Pie(9.0).
Please check my code below,
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AsyncReadConfig asyncReadConfig = new AsyncReadConfig();
asyncReadConfig.execute();
}
});
}
class AsyncReadConfig extends AsyncTask<Integer, Integer, Object> {
#Override
protected Object doInBackground(Integer... integers) {
try {
return callGetURLService(CONFIGURATION_URL);
} catch (Exception e) {
return e;
}
}
}
private Object callGetURLService(String path) {
try {
URL url = new URL(path);
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String text;
StringBuilder configParams = new StringBuilder();
while ((text = in.readLine()) != null) {
configParams.append(text);
}
JSONObject jsonObject = new JSONObject(configParams.toString());
//Doing my stuff
return null;
} catch (Exception e) {
e.printStackTrace();
}
}
In my manifeast.xml,
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:networkSecurityConfig="#xml/network_security_config"
.
.
In network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">MY_DOMAIN</domain>
</domain-config>
</network-security-config>
I'm just reading text file from server in sleep mode and I'm getting error,
java.net.ConnectException: Failed to connect to server
And as I'm switching my App from minimize mode to active mode, everything is working fine.

When your app is in the background you cant make network calls unless you are using a Foreground service to make the network call

Related

Why can't I send JSON from Android with this code?

I want to send JSON from Android to the server using HTTP (POST).
But stop at the following line:
OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream());
I use a thread for HTTP, and I added the following manifest:
<uses-permission android:name="android.permission.INTERNET" />
But the results did not change.
public class MainActivity extends AppCompatActivity {
private Handler handler = new Handler();
private String PostUrl = "http://localhost:3000";
private String JSON = "{\"test\":\"100\"}";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
callPost();
}
public void callPost() {
handler.post(new Runnable() {
#Override
public void run() {
HttpURLConnection con = null;
try{
URL url = new URL(PostUrl);
con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setRequestProperty("Content-Type","application/JSON; charset=utf-8");
Log.d("debug", "----- All right here -----");
OutputStreamWriter out = new
OutputStreamWriter(con.getOutputStream());
Log.d("debug", "----- This message is not displayed -----");
out.write(JSON);
out.flush();
con.connect();
} catch (Exception e){
}
}
});
}
}
There is no error, and only "----- All right here -----" is displayed.
Updated Answer
Verify that you've implemented below points and then use the code at the end which will work for you.
1. Use IP Address:
you can't use localhost in emulator because emulator refers local host to itself not to your laptop. Instead use IP address of your laptop i.e http://100.100.10.1:3000.
Read more here.
2. Cleartext Issue:
you need to add your server URL (IP address in your case) in cleartext network config.
for this create file res/xml/network_security_config.xml and add your IP address instead of Ip.Adress.here.
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">Ip.Adress.here</domain>
</domain-config>
</network-security-config>
Then add this file inside application tag manifest by android:networkSecurityConfig="#xml/network_security_config"
Your application tag in manifest will looks like this
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:networkSecurityConfig="#xml/network_security_config"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
Read more here.
3. Network in main thread
You will get Network in main thread issue. Since Network calls should be in background for that use Async Task. Below code is working fine for me just replace your.ip.address.here with your IP Address.
public class MainActivity extends AppCompatActivity {
private String PostUrl = "http://your.ip.address.here:3000";
private String JSON = "{\"test\":\"100\"}";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new PostTask().execute();
}
class PostTask extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... voids) {
HttpURLConnection con = null;
try {
URL url = new URL(PostUrl);
con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setDoInput(true);
con.setRequestProperty("Content-Type", "application/JSON; charset=utf-8");
Log.d("debug", "----- All right here -----");
OutputStream os = con.getOutputStream();
Log.d("debug", "----- This message is not displayed -----");
os.write(JSON.getBytes("UTF-8"));
os.close();
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());
}
return response.toString();
} catch (Exception e) {
return e.getMessage();
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if (s!=null) {
System.out.println(s);
} else {
System.out.println("Result not found");
}
}
}
}
Good Luck.
If still issue there try post the result of System.out from logcat.
Move the con.connect() line just after the con.setRequestProperty line and close the OutputStreamWriter after calling the flush method.
If you get a NetworkOnMainThreadException it's because you can't make network calls in main thread so you need to use AsyncTask.

Java Client Android On virtual device is working, on real device not

On virtual device is working, on real device not. Checked all ip, many ports, but nothing.
Android 7.1.1 Lenovopad TB-X304F
In manifest:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Code:
public class MainActivity extends AppCompatActivity {
EditText e1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
e1 = (EditText)findViewById(R.id.editText);
}
public void send_text(View v) {
String message = e1.getText().toString();
myTask mt = new myTask();
mt.execute(message);
Toast.makeText(getApplicationContext(),"Data sent: "+e1.getText().toString(), Toast.LENGTH_LONG).show();
}
class myTask extends AsyncTask<String, Void, Void>{
Socket s;
PrintWriter printWriter;
#Override
protected Void doInBackground(String... params){
try {
String message = params[0];
s = new Socket("192.168.1.5", 6001);
printWriter = new PrintWriter(s.getOutputStream());
printWriter.write(message);
printWriter.flush();
printWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Error:
W/System.err: java.net.ConnectException: Connection timed out
The mistake was that I did not know that I had to disable the firewall and open the port. I opened the port and it all worked.

Android telnet client, reading stops after a few seconds

I am trying to implement a telnet client in android that is going to continuously read data from a telnet server. I have verified that the server is sending data continuously by connecting to it from a telnet app from play store.
Now im trying to create an app to do the same and display the data on the screen using apache telnetclient. I have successfully connected to the telnet server, and I am able to read the correct lines for 5-10 seconds. The code is posted below.
What works:
Connecting to server.
Reading some lines for 5-10 seconds before the stream stops.
The problem:
The reading seems to stop after around 5-10 seconds, and hangs on readLine() with no new data coming in. Is this a problem with the code? Any help would be appreciated!
UPDATE:
I am trying to run this on an Android 4.2.2 device. I tried it on a newer android 7 device just now, and the code works as intended, I get continuous readings. Is there something in the android version that can be causing this?
--
This is the TestTelnetClient.class
public class TestTelnetClient extends Activity {
private TelnetClient telnet = new TelnetClient();
private InputStream in;
private PrintStream out;
private String server = "192.168.36.105";
TextView outputView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
outputView = (TextView)findViewById(R.id.output);
}
public void sendTelnet(View view) {
TelnetRead telnetRead = new TelnetRead();
telnetRead.execute();
}
private class TelnetRead extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
try {
// Connect to the specified server
telnet.connect(server, 8110);
// Get input and output stream references
in = telnet.getInputStream();
//out = new PrintStream(telnet.getOutputStream());
BufferedReader r = new BufferedReader(new InputStreamReader(in));
String aad = r.readLine();
while (true) {
publishProgress(aad);
aad = r.readLine();
}
//telnet.disconnect();
//finish();
//return aad;
//return "exit";
}
catch (Exception e) {
e.printStackTrace();
return e.toString();
}
}
#Override
protected void onPostExecute(String result) {
try {
outputView.setText(result);
Thread.sleep(10);
} catch (InterruptedException e) {
Thread.interrupted();
}
}
#Override
protected void onPreExecute() {
}
//#Override
protected void onProgressUpdate(String... result) {
outputView.setText(result[0]);
}
}
This is the android manifest
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".TestTelnetClient"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

Android Kryonet client wont connect to my PC server?

I made a basic server in eclipse:
Server server;
int tcp = 8885, udp = 8885;
public ServerMain() {
server = new Server();
server.addListener(new Listener() {
public void connected(Connection c) {
System.out.println("Connection made");
}
public void received(Connection c, Object p) {
}
public void disconnected(Connection c) {
System.out.println("Disconnection made");
}
});
server.start();
try {
server.bind(tcp, udp);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new ServerMain();
}
Then I created my client in android studio. I installed the library correctly. (According to google) I put the Kryonet jar into the libs folder and then rebuilt the project. I could then use Kryonet classes. Here is my code for my client:
Client client;
String ip = "MY.IP.ADDRESS";
int tcp = 8885, udp = 8885;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "Start");
client = new Client();
client.addListener(new Listener() {
public void received(Connection c, Object p) {
}
});
client.start();
try {
client.connect(5000, ip, tcp, udp);
Log.i(TAG, "conected");
} catch(IOException e) {
Log.i(TAG, "Error: " + e.getMessage());
}
}
It's the exact same code I would use in a normal Java client except now it's running directly from my android device. I get this error:
Error: Unable to connect to: /MY.IP.ADDRESS:8885
It cannot connect to my IP even though I port forwarded it and all. Why won't it connect? I have read online to add in this to my manifest file:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
So, I did:
<?xml version="1.0" encoding="utf-8"?>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Still to absolutely no avail. What am I doing wrong? (P.S. I have tried with both my network IP, and my public IP. I have no idea what I'm doing wrong, everything works fine with a normal Java program, but with an android app it bugs out.)
Try this code, it's working:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "Start");
client = new Client();
client.addListener(new Listener() {
public void received(Connection c, Object p) {
}
});
client.start();
new ConnectToServer.execute();
}
public class ConnectToServer extends AsyncTask<String, int[], String>
{
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
try {
client.connect(5000, ip, tcp, udp);
Log.i(TAG, "conected");
} catch(IOException e) {
Log.i(TAG, "Error: " + e.getMessage());
return null;
}
}
}

Google Drive Returning Error 400 in my Android app

I'm following all information about Drive v2 in developers.google.com in order to build a simple app in Android API 15 just to upload a txt file. After many hours spent in all around it like the right java build path for libraries (1.11.0 in my case), enable and set up Drive SDK, API access for client ID, etc, etc. I found a nice example in this post Google Drive Returning Error 400 or 403 to my Android App? where I found the same error description that now I'm getting on my app. This is my full code (hope useful to others):
public class DrivexampleActivity extends Activity {
Context activity = null;
boolean alreadyTriedAgain;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AccountManager am = AccountManager.get(this);
activity = this.getApplicationContext();
Bundle options = new Bundle();
Account[] acc = am.getAccounts();
am.getAuthToken(
(am.getAccounts())[8], // #8 just in my phone case. you can debugg the acc variable to find your #gmail account index.
"oauth2:" + DriveScopes.DRIVE,
options,
true,
new OnTokenAcquired(),
null);
}
private class OnTokenAcquired implements AccountManagerCallback<Bundle> {
#Override
public void run(AccountManagerFuture<Bundle> result) {
try {
final String token = result.getResult().getString(AccountManager.KEY_AUTHTOKEN);
HttpTransport httpTransport = new NetHttpTransport();
JacksonFactory jsonFactory = new JacksonFactory();
Drive.Builder b = new Drive.Builder(httpTransport, jsonFactory, null);
b.setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {
#Override
public void initialize(JsonHttpRequest request) throws IOException {
// TODO Auto-generated method stub
DriveRequest driveRequest = (DriveRequest) request;
driveRequest.setPrettyPrint(true);
driveRequest.setKey("xxxxxxxxxxxx.apps.googleusercontent.com"); // I replaced the number with x's. for your Client ID from Google API Console
driveRequest.setOauthToken(token);
}
});
final Drive drive = b.build();
final com.google.api.services.drive.model.File body = new com.google.api.services.drive.model.File();
body.setTitle("My Test File");
body.setDescription("A Test File");
body.setMimeType("text/plain");
java.io.File fileContent = new java.io.File("document.txt");
final FileContent mediaContent = new FileContent("text/plain",fileContent);
new Thread(new Runnable() {
public void run() {
com.google.api.services.drive.model.File file;
try {
file = drive.files().insert(body, mediaContent).execute();
Log.i("Hi", "File ID: " + file.getId());
alreadyTriedAgain = false; // Global boolean to make sure you don't repeatedly try too many times when the server is down or your code is faulty... they'll block requests until the next day if you make 10 bad requests, I found.
} catch (IOException e) {
if(!alreadyTriedAgain){
alreadyTriedAgain = true;
Log.i("Hi", "The upload/insert was caught, which suggests it wasn't successful...");
e.printStackTrace();
}
}
}
}).start();
Intent launch = null;
launch = (Intent)result.getResult().get(AccountManager.KEY_INTENT);
if (launch != null) {
Log.i("Hi", "Something came back as a KEY_INTENT");
startActivityForResult(launch, 3025);
return;
}
} catch (OperationCanceledException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (AuthenticatorException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 3025) {
switch (resultCode) {
case RESULT_OK:
AccountManager am = AccountManager.get(activity);
Bundle options = new Bundle();
am.getAuthToken(
(am.getAccounts())[8], // #8 just in my phone case. you can debugg the acc variable to find your #gmail account index.
"oauth2:" + DriveScopes.DRIVE,
options,
true,
new OnTokenAcquired(),
null);
break;
case RESULT_CANCELED:
// This probably means the user refused to log in. Explain to them why they need to log in.
break;
default:
// This isn't expected... maybe just log whatever code was returned.
break;
}
} else {
// Your application has other intents that it fires off besides the one for Drive's log in if it ever reaches this spot. Handle it here however you'd like.
}
}
Also manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.drivexample"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="14" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".DrivexampleActivity"
android:label="#string/app_name"
android:exported="true">
<meta-data android:name="com.google.android.apps.drive.APP_ID" android:value="id=xxxxxxxxxxxx"/>
<intent-filter>
<action android:name="com.google.android.apps.drive.DRIVE_OPEN" />
<data android:mimeType="application/vnd.test.type"/>
</intent-filter>
</activity>
</application>
</manifest>
But allways get the following error:
com.google.api.client.http.HttpResponseException: 400 Bad Request
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "keyInvalid",
"message": "Bad Request"
}
],
"code": 400,
"message": "Bad Request"
}
}
Seems that no errors with DRIVE SDK and Drive API in my case. Any suggestion?? please!!
You are passing the Client ID you got from the APIs Console to driveRequest.setKey, however that method is used to set an API Key and not the Client ID. Check the first answer to the other question you mentioned for more details.

Categories

Resources