I am working with android 4.1.1, IDE= eclipse, and SQL Server 2008.
Device= Note 2
android:minSdkVersion="10"
When I run the code snippet on the UI thread It gives me the error "Unable to get information from SQL Server:", but if I run the code in a background thread or AsyncTask Thread it works. Any help in understanding the two processes would be greatly appreciated?
Note: "The issue occurred when I upgrade the minSDKVersion from 8 to 10."
public Boolean open() {
Boolean res = false;
try {
String s = "jdbc:jtds:sqlserver://" + "xx.xxx.x.xx" + "/" + "FOO" + ";instance=SQLEXPRESS";
Class.forName("net.sourceforge.jtds.jdbc.Driver");
con = DriverManager.getConnection(s, "UserFoo", "1234");
res = true;
} catch (SQLException sx) {
Log.e(TAG, "DB:Open - " + sx.toString());
} catch (ClassNotFoundException e) {
Log.e(TAG, "DB:Open - " + e.toString());
}
return res;
}
Starting with Android 3.0, trying to access the network on the main (UI) thread results in:
NetworkOnMainThreadException
I'm guessing that you didn't see it because somewhere higher in your call stack you have:
catch (Exception)
which leads to:
"Unable to get information from SQL Server:"
As you have already discovered, a separate thread is the solution.
Related
Im starting several background services that take a while to configure due to web services calls, etc...
However Im starting these services via AsyncTask in order to avoid locking the main thread & GUI, however the GUI stills becomes locked.
Im using AsyncTask to call start a BluetoothService in my Activity onCreate():
I only included relevant lines of code:
//asynchronously - start the bluetooth service
new BluetoothServiceStart().execute();
Then in the BluetoothServiceStart service class, Im using Callable & Future task to get bytes from a web service:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// stop the service when the notification bar is pressed
if (intent != null && ACTION_STOP_SERVICE.equals(intent.getAction())) {
Log.d(TAG, "Stopping bluetooth service...");
broadcastServiceState(false);
stopSelf();
return START_NOT_STICKY;
}
// in case of attempting to restart while already running
clearSubscriptions();
Util.logToast(this, TAG, "Bluetooth service starting", Toast.LENGTH_SHORT, Util.DEBUG);
setupNotification();
// find and load JSON config file
loadDevices();
}
/**
* Gets the UUIDs of devices to connect to from the bluetooth JSON file.
*/
private void loadDevices() {
devicesLoaded = false;
Byte [] bytesFromWebService = null;
InputStream is = null;
URL url = null;
try {
if (ConnectivityMonitoring.hasNetwork()) {
//lets get the path of rest service that has the config file
String address = NgfrApp.getContext().getResources().getString(R.string.address);
String configuration_restful_port = NgfrApp.getContext().getResources().getString(R.string.rest_port);
String client_name = NgfrApp.getContext().getResources().getString(R.string.client_name);
String protocol = NgfrApp.getContext().getResources().getString(R.string.protocol);
//construct bluetooth config path
String bluetooth_config_path = NgfrApp.getContext().getResources().getString(R.string.bluetooth_path);
url = new URL(protocol + "://" + address + ":" + configuration_restful_port + bluetooth_config_path + client_name);
//lets execute an FutureTask (async task with a result, that blocks until result is returned).
ExecutorService exService = Executors.newSingleThreadExecutor();
Log.i(TAG, "making call to URL:" + url.toString());
Future<byte []> future = exService.submit(new CallWebServiceAndGetBytes(url));
bytesFromWebService = Util.toObjects(future.get());
}
if (bytesFromWebService != null) {
devices = readDeviceConfigFromWebService(bytesFromWebService);
Log.i(TAG, "Loaded configuration from URL:" + url.toString());
} else {
// read in the device UUIDs from the file
is = Util.scanForJson(getString(R.string.file_path), getString(R.string.bt_config_file));
devices = Util.readJsonStream(is, localConfigReadFunc);
Log.i(TAG, "Read config file from PATH:" + getString(R.string.file_path)+getString(R.string.bt_config_file));
}
if (devices != null) {
if (devices.size() < 1)
Log.w(TAG, "No devices to load!");
devicesLoaded = true;
}
// devices successfully loaded
if (devices != null && devicesLoaded) {
Log.d(TAG, "" + devices.size() + " BLE device IDs retrieved");
Log.d(TAG, "Devices: " + devices.toString());
}
// failed to load devices or find the JSON file
else {
Log.e(TAG, "Unable to load devices! Creating empty list...");
devices = new ArrayList<>();
}
}
catch (MalformedURLException e1) {
e1.printStackTrace();
}
catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
catch (FileNotFoundException e) {
Log.d(TAG, "Unable to locate bluetooth config file: " + getString(R.string.bt_config_file));
} catch (IOException e) {
Log.d(TAG, "Error reading json file: " + e.getMessage());
}
}//end loadDevices
Im getting an ANR & later crash.
Android Thread dump:
"main#4817" prio=5 tid=0x2 nid=NA waiting
java.lang.Thread.State: WAITING
blocks main#4817
at java.lang.Object.wait(Object.java:-1)
at java.lang.Thread.parkFor$(Thread.java:2135)
- locked <0x1a72> (a java.lang.Object)
at sun.misc.Unsafe.park(Unsafe.java:358)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:190)
at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:450)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at ngfr.wams.controller.core.services.RuleEngineService.loadRules(RuleEngineService.java:358)
at ngfr.wams.controller.core.services.RuleEngineService.updateRules(RuleEngineService.java:462)
at ngfr.wams.controller.core.services.RuleEngineService.onCreate(RuleEngineService.java:131)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3542)
at android.app.ActivityThread.-wrap4(ActivityThread.java:-1)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1786)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6938)
at java.lang.reflect.Method.invoke(Method.java:-1)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
The error line points to future.get().
I understand that the future.get() blocks, which is intended behavior in order to wait for the web service to return the bytes otherwise in low network connectivity/bandwidth situations the code will continue to execute and miss the network response & data.
The future.get() blocks the Service, however since the BluetoothService is started using BluetoothServiceStart AsyncTask, then why is the UI blocked???
Thanks
It's a common mistake to assume, that a service is running on another thread than the starting activity. It will run on the main thread as well as stated here: Services
Caution: A service runs in the main thread of its hosting process; the service does not create its own thread and does not run in a separate process unless you specify otherwise. If your service is going to perform any CPU-intensive work or blocking operations, such as MP3 playback or networking, you should create a new thread within the service to complete that work. By using a separate thread, you can reduce the risk of Application Not Responding (ANR) errors, and the application's main thread can remain dedicated to user interaction with your activities.
The startService call will not change this behaviour, even if you call it in an AsyncTask. So if you want to reanimate your app, you should create a thread inside of your service, which is not blocking the service, thus not blocking the main thread.
Note that IntentServices offload the task to a worker thread but automatically stop when there is no further work to do.
Clients send requests through Context.startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
Maybe this is not what you want with a bluetooth service.
Lifecycle methods always run on the man application loop, since the system creates the Service object for you. So, it's onStartCommand won't run on a background thread like you intend. If you want the Service to run on a background thread, use an IntentService.
I have the following running at startup inside of an IntentService
threadManager.postBackgroundRunnableDelayed(() -> {
try {
// Calling getToken and getId must be on separate thread. Otherwise, it blocks UI thread.
String token = instanceID.getToken(SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE);
String id = instanceID.getId();
Timber.d("id: " + id);
Timber.d("token: " + token);
lazyRestQueue.get().sendGcmToken(new GcmPushRequest(id, token), getSendGcmTokenCallback());
setupAnalytics(token);
} catch (IOException e) {
Timber.e(e, "Exception during registration");
Crashlytics.logException(e);
setHasToken(false);
} catch (RuntimeException e) {
// This will be thrown if Localytics was not properly setup
Timber.e(e, "Exception during registration");
}
});
When I run it on anything below API 18 it causes the app to close (not crash oddly, just close)
can someone give me advice on this? I know it probably has to do with the service or something not timing properly
I'm trying to connect my android application to my oracle 10g DB, i'm using JDK 1.6, OJDBC14.jar and working on a 4.+ application. I used to have a few problem with the driver but here comes the best one : after excecuting this code :
String url="jdbc:oracle:thin:usr/pwd#r2d2.iut-orsay.u-psud.fr:1521:etudom";
Connection co = null;
try {
Class.forName("oracle.jdbc.OracleDriver");
popUp("Driver Ok");
}
// Should never happend
catch (ClassNotFoundException e){
popUp("ERROR: Driver's missing");
//System.exit(1);
}
// Unknow problem
catch (Exception e){
popUp("ERROR : " + e.getMessage() + "\nFrom: " + e.getCause());
}
try {
co = DriverManager.getConnection(url);
popUp("Connection ok");
}
// In case of internet problem
catch (SQLException e) {
popUp("Throw from SQLException\nERROR : " + e.getMessage());
//System.exit(1);
}
// unknown problem
catch (Exception e){
popUp("ERROR from getConnection :\nMessage: " + e.getMessage() + "\nFrom: " + e.getCause() + "\nMessage extra: "+e.getLocalizedMessage());
}
And I've got a popUp like that :
ERROR from getConnection :
Message: null
From: null
Message extra: null
No output in the log or in the console.
I'm literaly lost
Any help would be great!
Ps: sorry for my bad english.
The reason why you are not able to connect the device to your Oracle DB is, mobile devices are not equipped to carry out such actions as they are not built with drivers for the vast amount of Databases that are out there. However, in order to connect your app to the Oracle DB you have to create what is called a Web Service or an API to get the job done. Check out these tutorials they should get you rolling:
How to connect Android with PHP, MySQL (the concept here is the same, just use your Oracle DB instead)
Oracle Mobile Database server
Android to Oracle connectivity through java
In my application I need to scan the local subnet (192.168.1.*) to collect the list of MAC addresses of all connected devices.
I currently use the following strategy:
start simultaneously 255 ping commands with Runtime.exec("ping -c 1 <addr>")
use waitFor() on each of the returned process to collect the exit code
close input streams of processes and destroy them
read the /proc/net/arp file and parse the MAC addresses
In most cases, this works very well and provides a fast scan.
But on some devices (such as android 1.5, and sometimes on >=4.0), the execution gets stuck at process creation (after a few ones have been successfully started) and there's no way to kill the running thread.
Do you see anything I could try to solve this issue? Or any other strategy that would not take too long?
This can be solved by using a pool of thread running the INetAddress.isReachable() method (instead of running the ping command in native processes).
private static final int NB_THREADS = 10;
public void doScan() {
Log.i(LOG_TAG, "Start scanning");
ExecutorService executor = Executors.newFixedThreadPool(NB_THREADS);
for(int dest=0; dest<255; dest++) {
String host = "192.168.1." + dest;
executor.execute(pingRunnable(host));
}
Log.i(LOG_TAG, "Waiting for executor to terminate...");
executor.shutdown();
try { executor.awaitTermination(60*1000, TimeUnit.MILLISECONDS); } catch (InterruptedException ignored) { }
Log.i(LOG_TAG, "Scan finished");
}
private Runnable pingRunnable(final String host) {
return new Runnable() {
public void run() {
Log.d(LOG_TAG, "Pinging " + host + "...");
try {
InetAddress inet = InetAddress.getByName(host);
boolean reachable = inet.isReachable(1000);
Log.d(LOG_TAG, "=> Result: " + (reachable ? "reachable" : "not reachable"));
} catch (UnknownHostException e) {
Log.e(LOG_TAG, "Not found", e);
} catch (IOException e) {
Log.e(LOG_TAG, "IO Error", e);
}
}
};
}
I first want to get a list of files stored in an FTP directory and then get the name of last created file using timestamp. And I'm getting an alert box: Activity is not responding. After checking logcat entry, I notice that the code never reach line :
Log.e("FTP", "number of filenames: " + count);
But I get to Log.e("FTP", "Connexion successful "); So connexion to the server seems ok.
It Seems like something going wrong out there. Can someone help me deal with it. Or show me a simple way to get the last created file from an the FTP server director?
FTPClient ftpClient = new FTPClient();
try
{
ftpClient.connect(InetAddress.getByName(Fonctions.address), Integer.parseInt(Fonctions.port));
if (ftpClient.login(Fonctions.login, Fonctions.pass))
{
Log.e("FTP", "Connexion successful ");
String workDir = ftpClient.printWorkingDirectory();
//Log.e("FTP", "workdir:" + workDir);
int count = ftpClient.listNames().length;
Log.e("FTP", "number of filenames: " + count);
FTPFile [] dossier = new FTPFile[count];
FTPFile back = new FTPFile();
dossier = ftpClient.listDirectories("Sarelo_FTP");
back = dossier[0];
Log.e("FTP", "Avant boucle " + back);
int buf = 0;
for (int i=0;i<(dossier.length) - 1;i++)
{
for (int j=1;j<dossier.length;j++)
{
buf = back.getTimestamp().compareTo(dossier[j].getTimestamp());
if (buf == -1)
back = dossier[j];
}
}
Log.e("FTP", "fichier final le plus récent: " + back.getName());
}
else{
Log.e("Restore FTP", "Error while connecting to FTP server");
}
}
catch(IOException e)
{
String title = "Error connecting to FTP server";
String msg = "Please check your parameters and connexion info: login, password,port number";
f.alert(c, title, msg).show();
Log.e("Restore FTP", "Error while connecting to FTP server", e);
}
P.S: I can't get the list of files in the directory so, I don't know if my code to retrieve the last created file is working. Any help on that would also be appreciated.
[Edit] This is my AsyncTask to retrieve the list of files in the directory. But it's still not working. I'm not getting Application Not Responding anymore, but It not seems to do anything else. Execution get stuck at the same point (can't reach Log.e("FTP", "number of filenames: " + count); )
class getFilesFromFtp extends AsyncTask
{
#Override
protected String doInBackground(Object... params)
{
int count = 0;
try
{
Log.e("FTP", "avant names: " + count);
count = ftpClient.listNames().length;
Log.e("FTP", "names: " + count);
handler.sendMessage(handler.obtainMessage());
}
catch (IOException e) {
Log.e("FTP", "Error getting number of files ", e);
}
return null;
}
}
Thanks for help.
You must not execute long running code on UI thread. Thia blocks UI redraw and event handling. It also produces ANR.
You should run it in the background thread, preferably via 'AsyncTask'.
First problem solved. I just needed to activate FTP data connection passive mode like that:
ftpClient.enterLocalPassiveMode();
before line int count = ftpClient.listNames().length;.
Hope this will help other people. Thanks to #Peter Knego driving me to AsynkTask. I learned something new. :)