In my android app, i want to let the user fetch data from a website (by sending an http request). The http-response is then sent to another activtiy which shows the data. (i made this a bit simplier in this example code. In real, the data is parsed into an object and the object is sent).
This all works good with my code. But when the user goes back to the main activity by pressing the back key, and trys another request, the application throws an java.io.FileNotFoundException while getting the input stream from the URLConnection. If the app is closed (by pressing back again) and then reopend, all works well again.
Im pretty sure its a problem with a connection not being closed properly or something like that but i cant find the error in my code.
Any idea whats wrong here?
MainActivity.java
*no interessting code here.
it just calls the static function from MainMethods.java
when a button is pressed*
MainFunctions.java - I want to call the methods from several classes so its in an extra class
class MainFunctions {
public static void search(final Activity, final String searchString) {
new AsyncTast<String, String, String>() {
protected void onPreExecute() {
// im opening a progress dialog for the activity here
}
protected String doInBackground(String... searchString) {
try{
return new HttpUtils().sendRequest(searchString)
} catch (Exception e) {
// print a dialog, stacktrace and stuff
return null;
}
}
protected void onPostExecute(String result) {
if(result != null) {
// dismiss the dialog etc..
Intent i = new Intent("packagename");
i.putExtra("key", result);
activity.startActivity(i);
}
}
}.start(searchString)
}
}
HttpUtils.java
public class HTTPUtils {
public String sendRequest(String data)
throws IOException {
String answer = "";
URL url = new URL("http://myURL.com/" + data);
URLConnection conn = url.openConnection();
conn.setReadTimeout(5000);
BufferedReader in = new BufferedReader(new InputStreamReader(
conn.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
answer += inputLine;
in.close();
return answer;
}
}
The Stacktrace shows that the Exception is thrown while conn.getInputStream() is called.
java.io.FileNotFoundException: http://myURL.com/danijoo
at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java)
at com.elophant.utils.HTTPUtils.sendRequest(HTTPUtils.java:20)
at com.elophant.Elophant.getSummoner(Elophant.java:183)
at com.lolsummoners.datacollector.Collecter.getSummonerInfo(Collecter.java:39)
at com.lolsummoners.utils.MainFunctions$1.doInBackground(MainFunctions.java:106)
at com.lolsummoners.utils.MainFunctions$1.doInBackground(MainFunctions.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java)
at java.util.concurrent.FutureTask.run(FutureTask.java)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java)
at java.lang.Thread.run(Thread.java)
The Methods getSummoner() and getSummonerInfo() are methods to parse objects out of the response string. i let that out to make the problem easier to undearstand.
Thanks!
Related
So I'm really new in android, and going to make an application which get the device id of a device, store it on database server, and then check it if the device are the same with the one already registered, if yes, then go to main activity, if not then they need to registered again.
My method :
public class SigninActivity extends AsyncTask<String, String, String> {
private Context context;
public SigninActivity(Context context, int flag) {
this.context = context;
}
protected void onPreExecute(String result) {
}
//#Override
protected String doInBackground(String... arg0) {
try {
String dev = (String) arg0[0];
String link = "http://10.20.2.14/service_antrian/get_data.php?device_id=" + dev;
URL url = new URL(link);
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet();
request.setURI(new URI(link));
HttpResponse response = client.execute(request);
BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
while ((line = in.readLine()) != null) {
sb.append(line);
break;
}
in.close();
Log.d("RETURN", "return");
return sb.toString();
} catch (Exception e) {
Log.d("EXCEPTION", "EXP");
//return "failed";
return new String("Exception: " + e.getMessage());
}
}
// #Override
protected void onPostExecute(String result) {
if (result.equalsIgnoreCase("false")) {
Intent mainIntent = new Intent(UserActivity.this, RegisterActivity.class);
UserActivity.this.startActivity(mainIntent);
} else {
Intent mainIntent = new Intent(UserActivity.this, MainActivity.class);
UserActivity.this.startActivity(mainIntent);
}
}
}
and this is my service in php code:
<?php
ini_set('display_errors', 1);
require_once 'database.php';
if(isset($_GET['device_id'])) {
$device_id = $_GET['device_id'];
$sql = " SELECT * FROM `pasien`.`antrian_mobile` WHERE `device_id`=
'$device_id' ";
$rs = $mysqli->query($sql);
$data = array();
while ($row = $rs->fetch_object()) {
$data[] = $row;
}
if ($mysqli->affected_rows > 0) {
echo "successfull";
} else {
echo "false";
}
echo json_encode($data);
}
?>
but that code only make the app go to the main activity, while there are no records on the database yet. Is it because of my service?
You are returning successfull or failed from your service
if ($mysqli->affected_rows > 0) {
echo "successfull";
} else {
echo "failed";
}
but you are comparing the result with false in your mobile app, hence it always takes the else route and open MainActivity
if (result.equalsIgnoreCase("false")) {
Intent mainIntent = new Intent(UserActivity.this, RegisterActivity.class);
UserActivity.this.startActivity(mainIntent);
} else {
Intent mainIntent = new Intent(UserActivity.this, MainActivity.class);
UserActivity.this.startActivity(mainIntent);
}
I see a few issues in your code:
issue #1
Activity shouldn't extend AsyncTask. AsyncTask should be dedicated to a single asynchronous task (like sending HTTP request) and Activity is representing single user screen (UI layer). You should create AsyncTask separately and call it within an Activity like this:
class SigninActivity extends Activity {
// this method should be called in the place where you want to execute your task
// it could be onResume() method, onClick listener for the button or whatever
private void executeAsyncTask() {
new MyTask().execute(...) // put your params here...
}
private class MyTask extends AsyncTask<String, String, String> {
... // your task code goes here...
}
}
issue #2
Nowadays, using AsyncTask is considered as a bad practice in Android applications, because it has poor error handling and is not aware of the Activity lifecycle. Recommended solution for asynchronous operations on Android is RxJava (version 2).
issue #3
You are using HttpClient. It's recommended to use more mature solutions like Retrofit Http REST client or OkHttp library. They can be easily integrated with RxJava.
issue #4
You're passing Context, but you're not using it
issue #5
You don't have to comment #Override annotations.
issue #6
Your code is messy, hard to debug and read. Once you make it clean, it will be easier to solve problems related to it.
issue #7
In the PHP code, you're mixing responsibilities.
Summary
Make sure you're using the existing code correctly and then try to improve it.
I created an android app. I try to get content from a PHP file. I wrote the logic in below getCont() method, but it doesn't work. It always returns null in Android. When I do the same with Java it returns the PHP content. How to solve this, so no exception is thrown.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String dbcont = getCont();
tone = (TextView)findViewById(R.id.textView1);
tone.setText("usean :-)"+dbcont);
}
public String getCont() {
String mit = null;
try {
URL oracle = new URL("http://localhost/grace/conn.php");
BufferedReader in = new BufferedReader(
new InputStreamReader(oracle.openStream()));
StringBuilder sb = new StringBuilder();
String inputLine;
while ((inputLine = in.readLine()) != null) {
sb.append(inputLine);
}
mit = sb.toString();
System.out.println(mit);
}
catch(Exception e){
e.printStackTrace();
}
return mit;
}
You're saying you're not getting an exception? You're opening a URL connection on the UI Thread. This is restricted on android. I'm surprised the app isn't crashing.
http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html
You have to use a separate thread to perform network functions. Read this
http://developer.android.com/reference/android/os/AsyncTask.html
You need to create a class that extends ASyncTask, then in the doInBackground() method, you can open the connection to fetch your PHP file.
You can then return the results which will be passed on to the onPostExecute() method. That will allow you to pass the data from the connection (i.e. the PHP file) back to your UI thread.
Let me know if this helps.
I'm having trouble figuring out how to make this work.
I'm developing an app in which I download data from a online txt, parse it and add it to my database. This is taking +-30 seconds, and there is only one part of the updater implemented.
When I try to use a Thread or Asynctask, I have problems when trying to pass the arguments to the void which is updating the Database.
How can I implement it on the good way?
Here is my code:
Main activity class:
public class Androideye_principal extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
//WhazzupUpdate.DownloadWhazzup(AllUsers, TotalConnections);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_androideye_principal);
PilotsSQLiteHelper pdbh = new PilotsSQLiteHelper(this, "PilotsDB", null, 1);
SQLiteDatabase dbPilots = pdbh.getWritableDatabase();
Context context = getApplicationContext();
String TotalConnections = new String();
WhazzupUpdate.DownloadWhazzup(dbPilots, TotalConnections, context);
dbPilots.close();
CharSequence text = "Total Users: " + TotalConnections;
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
[Continues with Buttons stuff and so on...]
Parser class:
public class WhazzupUpdate {
public static void DownloadWhazzup (SQLiteDatabase PilotsDB, String TotalConnections, Context context) {
try {
// Create a URL for the desired page
URL url = new URL("This is my url/whazzup.txt");
// Read all the text returned by the server
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String str;
for (int i = 0; i<=4; i++) {
in.readLine(); } // Go to the number of connections
TotalConnections = in.readLine();
for (int i = 0; i<=3; i++) {
in.readLine(); } // Go to !CLIENTS
PilotsDB.execSQL("DELETE FROM Pilots");
while (((str = in.readLine()) != null) && !(in.readLine().contains("!AIRPORTS"))) {
// str is one line of text; readLine() strips the newline character(s)
String[] dataRow = str.split(":");
if (str.contains("PILOT")) {
ContentValues NewValue = new ContentValues();
NewValue.put("VID", dataRow[1]);
[More NewValue puts...]
PilotsDB.insert("Pilots", null, NewValue);
} //End IF Pilot
} // End While
in.close();
} catch (MalformedURLException e) {
} catch (IOException e) {
}
}}
As you see, I call WhazzupUpdate.DownloadWhazzup Method in the main activity, and this is when all is getting frozen, but don't know how to derivate it to another threat and keep the references to the Data Bases and so on...
Hope anyone can help me. Thanks in advance.
A Thread or AsyncTask would be fine here. I prefer using AsyncTask for most of my heavy-lifting. You can create an AsyncTask and do your work in doInBackground() as it works on a background Thread. Then you can update your UI elements if needed in any of its other methods.
onPostExecute() will run after a result is passed from doInBackground()
onProgressUpdate() will run if you need to update UI during doInBackground() operations by calling publishProgress(). Here you can show a ProgressBar if you need to
and
onPreExecute() will run when you first call your task before doInBackground() runs.
Running the code in a background thread using Thread or AsyncTask will allow your UI to be free while the heavy work is being done.
Example of AsyncTask
Using interface with AsyncTask to post data back yo UI
AsyncTask Docs
I am using the an asynchronous task to run a JSON downloader as thus: (abridged)
public class JSONDownloader extends AsyncTask<Object, Object, Object>{
#Override
protected Object doInBackground(Object... params) {
if(JSONstate == false){
try {
final URL url = new URL([REDACTED]);
final URLConnection urlConnection = url.openConnection();
urlConnection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
urlConnection.connect();
final InputStream inputStream = urlConnection.getInputStream();
final StringBuilder sb = new StringBuilder();
while (inputStream.available() > 0) {
sb.append((char) inputStream.read());
}
String result = sb.toString();
JSONObject jsonOrg = new JSONObject(result);
String ok = "ok";
Response = jsonOrg.getString("response");
System.out.println(Response);
if(Response.equals(ok)){
Settingsresponse = true;
orgName = jsonOrg.getString("orgName");
System.out.println("orgName" + orgName);
accessPointName = jsonOrg.getString("attendanceRecorderName");
System.out.println("accessPointName" + accessPointName);
lat = jsonOrg.getString("latitude");
System.out.println("lat" + lat);
longi = jsonOrg.getString("longitude");
System.out.println("longi" + longi);
floor = jsonOrg.getString("floor");
System.out.println("floor" + floor);
orgId = jsonOrg.getString("orgId");
System.out.println("orgId" + orgId);
}
else{
System.out.println("Data sent was erroneous");
Settingsresponse = false;
}
} catch (Exception e) {
System.err.print(e);
}
}
else if(JSONstate == true){
try {
[redacted]
}
else{
System.out.println("Data sent was erroneous");
Settingsresponse = false;
}
} catch (Exception e) {
System.err.print(e);
}
}
return null;
}
protected void onPostExecute(Void result){
if(JSONstate == false){
System.out.println("This piece of code is definitely being run");
setfields();
}
else if(JSONstate == true){
settestfields();
//This method does not run upon the completion of the JSON request, as it supposedly should
}
}
}
Once the JSONRequest has been completed, the 'onPostExecute' method doesn't run. I have been attempting to use this method so that a set of fields can be updated as soon as the request is complete, instead of having to set a definite wait time. Am I simply utilizing the code wrong? Or is there something I've missed?
You aren't overriding the correct method for onPostExecute.
You have:
protected void onPostExecute(Void result)
You need:
protected void onPostExecute(Object result)
Notice the third generic parameter you supplied was of type Object. That's the type that onPostExecute uses as an argument. So, the method signature for onPostExecute needs to accept an Object, not Void.
You should probably use a result type of boolean here rather than object, and remove the Json state class variable. This keeps your AsyncTask more flexible, and could allow you to display some indication the operation completed to the user after execution.
I have to say you codes in AsyncTask is nothing matches the point.
AsyncTask is designed as another thread running out from the UI-thread. So you should either use it as a inner class which is in a running UI-thread, then the onPostExecute() part can do something to show the result, or you as your codes, if you leave it as a stand alone class. You should design an interface, other class, like activity or fragment, which run new AsyncTask.execute() should implements that interface.
Also, java is not javascript. Your variables in doInBackground() is only limited in the function. So what you did in onPostExecute() will get nothing.
You should either use
JSONObject jsonOrg
as a class variable or you should return that at the end of doInBackground() and gain it back in onPostExecute()
After all, I suggest you look at the api document's example. Although it is a little complex, but it shows everything perfect.
try to use override methods
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Log.i("in on ", "entered");
hideProgress();
}
As suggested by william the type should match with the override methods. I have edited the answer below
public class JSONDownloader extends AsyncTask<Object, Object, Object>
#Override
protected void onPostExecute(Object result) {
super.onPostExecute(result);
}
So, I'm trying to write code for a search JTextField that retrieves results from the web (kinda like Google's fancy search tips). The only problem is... probably my lack of programming experience. More specifically, I have it set up to whenever a user hits a key, it sends out a request with the JTextField input through an HttpURLConnection and retrieves the results then updates. But whenever the HttpURLConnection is running, it freezes the program for a couple seconds while it does its thing, which mainly prohibits entering in more characters into the search field if I didn't mind anything else. I've considered using separate threads, but I'm not sure how I would properly interrupt a thread and have it start over using new data while having everything else wait on it but still accepting new data. I've considered using
thread.stop();
to help manage the issue, but from what I've read, that seems taboo (am I right?). Anyways, here's pretty much what I'm using:
public class SearchField extends JTextField implements KeyListener {
public SearchField() {
addkeyListener(this);
}
public void updateData(ArrayList<String results) {
/*Pass the data off the the GUI*/
{
#Override
public void keyTyped(KeyEvent e) {
SearchQuery query = new SearchQuery(this.getText());
updateData(query.getResults());
}
}
public class SearchQuery {
ArrayList<String> results = new ArrayList<String>();
public SearchQuery(String search) {
String search_path = "http://www.whatever.com/" + search;
URL url = new URL(search_path);
conn = (HttpURLConnection) url.openConnection();
conn.addRequestProperty("User-Agent", "Mozilla/4.76");
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
StringBuffer buf = new StringBuffer();
int i;
while((i = in.read()) != -1) {
buf.append((char) i);
}
String data = buf.toString();
parse(data);
}
public void parse(String data) {
/*Parse a bunch of JSON, return the results in an array*/
results.add(data);
}
public ArrayList<String> getResults() {
return results;
}
}
I'm just at a loss for how to synchronise recieving continuous input while getting new results for each key stroke and dismissing unfinished connections and their respective data processing when it becomes invalid at the next key stroke.
You are doing the download in the same thread that responds to user events. You need to do the download in another thread, perhaps by making SearchQuery extend Thread and doing the query in the run method. When it comes time to update the text field, you can use SwingUtilities.invokeLater to update the text field. Here’s an example:
public class SearchQuery extends Thread {
private SearchField f;
public SearchQuery(JTextField f) {
this.f = f;
}
public void run() {
// do the query here
SwingUtilities.invokeLater(new Runnable() {
public void run() {
f.updateData(results);
}
});
}
}
Then change the line:
SearchQuery query = new SearchQuery(this.getText());
to this:
SearchQuery query = new SearchQuery(this);