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.
Related
I have an android app that is connected to an API through retrofit, ive succesfully logged in, if i press back button to return back to the login activity again, if i try re-logging in again, the app crashes and give me a NullPointerException.
here's connection code
private void loginUser(String email, String password) {
UnifyAuthenticationApiInterface service = this.client.create(UnifyAuthenticationApiInterface.class);
Call<UnifyAuthenticationApiResponse> call = service.staffLogin(email, password);
call.enqueue(new Callback<UnifyAuthenticationApiResponse>() {
#Override
public void onResponse(Call<UnifyAuthenticationApiResponse> call,
Response<UnifyAuthenticationApiResponse> response) {
UnifyAuthenticationApiResponse result = response.body();
School school = new School();
com.peterstev.unify.login.Data data = result.getData();
mySchoolsList = new ArrayList<School>();
mySchoolsList = data.getSchools();
staff = data.getStaff();
gotoHomeActivity();
}
#Override
public void onFailure(Call<UnifyAuthenticationApiResponse> call, Throwable t) {
progressDialog.dismiss();
Toast.makeText(MainActivity.this, "Login Failed # onFailure", Toast.LENGTH_SHORT).show();
}
});
}
and the goToHomeActivity() is
private void gotoHomeActivity() {
progressDialog.dismiss();
if (mySchoolsList.size() > 1) {
schoolsListView = new ListView(MainActivity.this);
schoolsArrayAdapter = new SchoolListAdapter(MainActivity.this, android.R.layout.simple_list_item_1, mySchoolsList);
schoolsListView.setAdapter(schoolsArrayAdapter);
dialog = new Dialog(MainActivity.this);
dialog.setContentView(schoolsListView);
dialog.setTitle("Welcome " + staff.getFullName());
dialog.show();
} else {
Intent intent = new Intent(MainActivity.this, NavMainActivity.class);
startActivity(intent);
}
}
the NullPointerException gets thrown at
com.peterstev.unify.login.Data data = result.getData();
at first, it gets the data n succesfully logs in, but when i use the back button n try to log in again it crashes.
Debugger is your answer - check if you aren't loosing any data when going back - maybe you're storing login params somewhere in activity class but you're not saving instance state properly and second request is triggered without necessary data. Check state of variables just before calling your request first and second time.
In situation like that always best bet to place breakpoint and trigger your work step by step. You cannot be good developer without debugger skills.
I think for some reason, the data object wasn't receiving the result when i used the back button to navigate to the parent activity. so i used and if condition to make it get the required data.
private void loginUser(String email, String password) {
UnifyAuthenticationApiInterface service = this.client.create(UnifyAuthenticationApiInterface.class);
Call<UnifyAuthenticationApiResponse> call = service.staffLogin(email, password);
call.enqueue(new Callback<UnifyAuthenticationApiResponse>() {
#Override
public void onResponse(Call<UnifyAuthenticationApiResponse> call,
Response<UnifyAuthenticationApiResponse> response) {
if(response.isSuccessful()) {
UnifyAuthenticationApiResponse result = response.body();
School school = new School();
data = result.getData();
if(data == null) {
try{
this.onResponse(call, response);
}catch(NullPointerException NPE){
Log.d("NPE", NPE.getMessage());
}
}
mySchoolsList = new ArrayList<School>();
mySchoolsList = data.getSchools();
staff = data.getStaff();
gotoHomeActivity();
}
}
#Override
public void onFailure(Call<UnifyAuthenticationApiResponse> call, Throwable t) {
progressDialog.dismiss();
Toast.makeText(MainActivity.this, "Login Failed # onFailure", Toast.LENGTH_SHORT).show();
}
});
}
as the tittle indicates just want to get data from my php file & check whether entered email , password are of a registered user . If yes then redirect to Success page(TimelineActivity)
Hence had look on this :- How to get values from mysql database using php script in android
This my LoginBasicActivity.java
public class LoginBasicActivity extends AppCompatActivity {
public AutoCompleteTextView uemail;
public EditText upassword;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login_basic);
uemail = (AutoCompleteTextView) findViewById(R.id.emailBasic);
upassword = (EditText) findViewById(R.id.passwordBasic) ;
Button buttonLog = (Button) findViewById(R.id.buttonLog);
buttonLog.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
String tem;
String email = uemail.getText().toString();
String result = null;
String password = upassword.getText().toString() ;
// HttpClientBuilder.create();
// As HttpClient client = new DefaultHttpClient(); is not used anymore
HttpClient client = HttpClients.createDefault();
tem = "http://www.example_domain.com/app_folder/verify-user.php?username="+email+"&password="+password;
HttpGet request = new HttpGet(tem);
try {
HttpResponse response = client.execute(request);
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(isr);
result = reader.readLine();
} catch (Exception e) {
e.printStackTrace();
}
if (result.equals("0") == true) {
Toast.makeText(getApplicationContext(), "Sorry try again", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), "Welcome Client", Toast.LENGTH_LONG).show();
Intent myIntt = new Intent(view.getContext(), TimelineActivity.class);
startActivityForResult(myIntt, 0);
}
}
});
}
}
This is verify-user.php
<?php
mysql_connect("localhost","user_name","user_password") or die(mysql_error());
mysql_select_db("db_name") or die(mysql_error());
$username=$_REQUEST['username'];
$password=$_REQUEST['password'];
$SelectQuery="select * from table_name where C_Username='$username' and C_Password='$password'";
$result=mysql_query($SelectQuery) or die(mysql_error());
$count=mysql_num_rows($result);
$row=mysql_fetch_array($result);
if($count==0)
echo "0";
else
echo $row['c_id'];
?>
After this i got some file duplication issue in build.gradle , so added this in build.gradle
android {
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/NOTICE'
}
}`
Now , when Login button is pressed dialogbox says "Unfourtunately app_name has stopped "
Logcat :- https://www.dropbox.com/s/63cv806z4y8h9my/2015-11-10-05-01-44%5B1%5D.txt?dl=0
Im little bit new to Android-Java.
How to fix this issue ? Can someone explain correct syntax , where its going wrong ?
You are making the network(api) request over main thread which is causing problem.Make the api hit from a thread or use the AsyncTask or Loader for it.
Also check if you have added internet permission to your manifest file or not.if not than add the following line in your manifest file.
<uses-permission android:name="android.permission.INTERNET"/>
Edit: You can make a inner class like as follows in your activity and call it on button click using new LoginAsyncTask().execute();
public class LoginAsyncTask extends AsyncTask<Void, Void, String> {
protected String doInBackground(Void... params) {
//Run in background thread(can not access UI and not able to perform UI related operations here).
//make your network hit here and return the result which is string in your case.
//The onPostExecute Method is get called automatically after this method returns.
...
}
protected void onPreExecute() {
//run on main thread(can access UI)
//do some initialization here,if needed, before network hit.
...
}
protected void onPostExecute(String result) {
//Method run on main thread,can access UI.result is the value returned by doInBackground method.
//Put a check over result and perform the further operation accordingly.
.....
}
}
I have an activity that when started makes a call to a "json" for get data categories of songs, after that I make a call to the method "AsyncTask" for the list of songs that category from another "JSON "the problem is that when I start the activity, this is locked , after 2 seconds, the activity opens the layout and I can see the categories on the action bar and not because the songs are looking for in the background.
main activity (onCreate):
java.io.InputStream source = null;
source = retrieveStream(UrlApi.URL_BASE + UrlApi.URL_STORE + _bundle.getString("_id") + UrlApi.CATEGORY_SONG);
Log.i("URL - KARAOKE", UrlApi.URL_BASE + UrlApi.URL_STORE + _bundle.getString("_id") + UrlApi.CATEGORY_SONG);
Reader reader = new InputStreamReader(source);
Type happyCollection = new TypeToken<Collection<String>>() {}.getType();
_karaoke_category_response = new Gson().fromJson(reader, happyCollection);
if(_karaoke_category_response.size() < 1){
finish();
Toast.makeText(getApplicationContext(), "Local sin karaokes", Toast.LENGTH_SHORT).show();
}else{
Log.i("Category - response", _karaoke_category_response.toString());
_karaoke_category_adapter = new ArrayAdapter<String>(getSupportActionBar().getThemedContext(), R.layout.spinner_item,_karaoke_category_response);
getSupportActionBar().setListNavigationCallbacks(_karaoke_category_adapter, this);
}
The follow code is of search the songs of that categori and set it
class AsyncKaraoke extends AsyncTask<Void, Void, Void> {
String category;
public AsyncKaraoke(String category) {
this.category = category;
}
protected void onPreExecute(){
super.onPreExecute();
setSupportProgressBarIndeterminateVisibility(true);
}
#Override
protected Void doInBackground(Void... params) {
java.io.InputStream source = null;
try {
source = retrieveStream(UrlApi.URL_BASE + UrlApi.URL_STORE + _bundle.getString("_id") + UrlApi.KARAOKE_URL + UrlApi.FILTER_CATEGORY + URLEncoder.encode(category, "UTF-8"));
Log.i("URL - KARAOKE", UrlApi.URL_BASE + UrlApi.URL_STORE + _bundle.getString("_id") + UrlApi.KARAOKE_URL + UrlApi.FILTER_CATEGORY + URLEncoder.encode(category, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Reader reader = new InputStreamReader(source);
Type karaokeCollection = new TypeToken<Collection<KaraokeModel>>() {}.getType();
_response = new Gson().fromJson(reader, karaokeCollection);
Log.i("Response - KaraokeCategory" , _karaoke_category_response.toString());
return null;
}
protected void onPostExecute(Void Void){
super.onPostExecute(Void);
setSupportProgressBarIndeterminateVisibility(false);
_karaoke_adapter = new KaraokeAdapter(KaraokeActivity.this, _bundle.getString("_id"), _response);
if(_response.size() == 0){
Toast.makeText(getApplicationContext(), "Categoria sin karaoke", Toast.LENGTH_SHORT).show();
}
_list_view.setAdapter(_karaoke_adapter);
_karaoke_adapter.notifyDataSetChanged();
}
}
How should I do to call 2 times to "AsyncTask" method and prevent the activity is engaged by a few seconds?
The primary rule of AsyncTask is that it must always be create and run on the main thread. You will get an exception if you start another AsyncTask inside the doInBackground() method. Your options are to start the next AsyncTask in one of the callbacks. Generally, some people will chain AsyncTask in the onPostExecute() method, but you can also start them in onPreExecute() and onProgressUpdate().
EDIT:
Additionally, you can run AsyncTask in sequence of each other using AsyncTask#executeOnExecutor(). From HoneyComb on, you don't need to do this. All AsyncTask run in a serial thread pool in the order they are executed. Though it may be easier to understand that the code is running serially if you use it. You do need to chain if using Android Android 1.6 - 2.3.x though.
You should build the URL in the main activity, then run an AsyncTask to download the content and finally process the result back in your activity.
The syntax to run an AsyncTask is:
String category = "...";
new AsyncKaraoke().execute(category);
You can also remove the onPostExecute() method from your AsyncKaraoke class and put it in the activity:
String category = "...";
new AsyncKaraoke() {
#Override
protected void onPostExecute(Void Void){
// do stuff (and moving the third type of the AsyncKaraoke to something else
// than Void will allow you to get the result here.
}.execute(category);
Generally, we use AsyncTask to perform an action in another thread than the UI thread to prevent the user from being halt while performing some actions. SO, it does not make any sense to create an additional AsyncTask inside the outer one. Try to manage your code to do it all the those method soInBackground(), onPreExecution() and onPostExecution() and make use of their order of execution
int count = 0;
protected void onPostExecute(Void Void){
super.onPostExecute(Void);
// call same asynctask
if (count == 0)
{
execute asynctask
count++;
}
}
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);
}
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!