Best way to request data from server - android

I need to fetch some data from my server in order to make my app work. In order to do that, I will be using POST. As far as I know, I have to request that data in a thread which can not be the main thread. I am finding it a little bit difficult to put the data I am receiving in a variable defined in the UI thread. So, my question is, which is the best way to do it?
Is it correct to set the value of a variable defined, for example, in my main activity, with a setter called inside an AsyncTask? Or is there a better option than this?
Thread nt = new Thread(){
#Override
public void run(){
try{
//get data with POST and then something like main.setValue(data);
}catch(Exception e){
e.printStackTrace();
}
}
};
nt.start();
I have read that I may use Interfaces in order to archive that, but it is a concept that I do not understand very well yet. I would like to directly use a method which returns the data, but as far as I know, it is not possible.
EDIT: new code according to NoChinDeluxe answer:
public class LoginHandler {
public static class Login extends AsyncTask<String, String, Integer> {
LoginCallback listener;
#Override
protected Integer doInBackground(String... params) {
URL url;
postDataParams.put("name", params[0]);
HashMap<String, String> postDataParams = new HashMap<String, String>();
postDataParams.put("password", params[1]);
try {
url = new URL("http://mashiron.xyz/_03z/gmpia/proc.php");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(15000);
conn.setConnectTimeout(15000);
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
writer.write(HttpHandler.getPostDataString(postDataParams));
writer.flush();
writer.close();
os.close();
System.out.println("Respuesta: "+conn.getResponseCode());
return conn.getResponseCode();
} catch (Exception e) {
e.printStackTrace();
return 404;
}
}
protected void onPostExecute(int result){
System.out.println("Respuesta 2: "+result);
listener.onResultReceived(result);
}
}
public interface LoginCallback {
void onResultReceived(int result);
}
}
EDIT: added exception for NoChinDeluxe:
03-24 17:38:09.072 13312-13312/com.pitazzo.geomoments E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.pitazzo.geomoments, PID: 13312
java.lang.NullPointerException: Attempt to invoke interface method 'void com.pitazzo.geomoments.Handlers.LoginHandler$LoginCallback.onResultReceived(int)' on a null object reference
at com.pitazzo.geomoments.Handlers.LoginHandler$Login.onPostExecute(LoginHandler.java:65)
at com.pitazzo.geomoments.Handlers.LoginHandler$Login.onPostExecute(LoginHandler.java:17)
at android.os.AsyncTask.finish(AsyncTask.java:636)
at android.os.AsyncTask.access$500(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:653)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5300)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)
EDIT: more code for NoChainDeluxe
public class LoginActivity extends AppCompatActivity implements LoginHandler.LoginCallback{
EditText name;
EditText password;
Button login;
int code;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login_activity);
/*
if(logueado){
}
*/
name = (EditText) findViewById(R.id.loginuser);
password = (EditText) findViewById(R.id.loginpassword);
login = (Button) findViewById(R.id.loginlogin);
login.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String params[] = {name.getText().toString(), password.getText().toString()};
System.out.println("Params: "+params.toString());
new LoginHandler.Login().execute(params);
System.out.println("Respuesta 4: "+code);
if(code == 200){
Toast toast1 =
Toast.makeText(getApplicationContext(),
"Iniciado sesión", Toast.LENGTH_SHORT);
toast1.show();
}else{
Toast toast1 =
Toast.makeText(getApplicationContext(),
"Nombre de usuario y/o contraseña incorrectos: "+code, Toast.LENGTH_SHORT);
toast1.show();
}
}
});
}
public void onResultReceived(int resultado) {
code = resultado;
System.out.println("Respuesta 3: "+code);
}
}

The best way to achieve this is to use an HttpURLConnection to make your web calls inside an AsyncTask and then pass the result back to your calling Activity through a callback. Here's some code to help you get started:
The first thing you should understand is how to properly use a callback with an AsyncTask. Here is an example AsyncTask that defines a callback interface:
import android.os.AsyncTask;
public class TestTask extends AsyncTask<String, Void, String> {
TestTaskCallback listener;
public TestTask(TestTaskCallback listener) {
this.listener = listener;
}
protected String doInBackground(String... args) {
String input = args[0];
String output = "simulated return value";
return output;
}
protected void onPostExecute(String result) {
listener.onResultReceived(result);
}
public interface TestTaskCallback {
void onResultReceived(String result);
}
}
The way this works is, you define a public interface that you then implement in your Activity. This acts as a "listener" that is waiting for any data that is sent through to it. We define the interface TestTaskCallback because we are going to be sending our data from our AsyncTask to our calling Activity.
Then in the Activity, we need to implement this interface, and pass in a reference to our implementation to the task when we create it. That way, when the task fires, it knows where to send the result, which is back to our Activity. An example implementation might look like this:
public class TestActivity extends AppCompatActivity implements TestTask.TestTaskCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
new TestTask(this).execute("Some input");
}
public void onResultReceived(String result) {
Log.d("TEST TASK RESULT", result);
}
}
So our Activity implements the interface that we defined inside our AsyncTask, and notice that our AsyncTask takes the reference to this implementation (passed in through the constructor) and sends data to it in the onPostExecute() method. This will allow your result to be sent to the main UI thread so that you can update your Activity appropriately.
The only thing left is to actually make the web calls. I would recommend using an HttpURLConnection for this. You would put this code inside the doInBackground() method of your AsyncTask.
I'll show you an example web service call I have set up. This shows how to make a web service call to retrieve a JSON response. It looks something like this:
//The JSON we will get back as a response from the server
JSONObject jsonResponse = null;
//Http connections and data streams
URL url;
HttpURLConnection httpURLConnection = null;
OutputStreamWriter outputStreamWriter = null;
try {
//open connection to the server
url = new URL("your_url_to_web_service");
httpURLConnection = (HttpURLConnection) url.openConnection();
//set request properties
httpURLConnection.setDoOutput(true); //defaults request method to POST
httpURLConnection.setDoInput(true); //allow input to this HttpURLConnection
httpURLConnection.setRequestProperty("Content-Type", "application/json"); //header params
httpURLConnection.setRequestProperty("Accept", "application/json"); //header params
httpURLConnection.setFixedLengthStreamingMode(jsonToSend.toString().getBytes().length); //header param "content-length"
//open output stream and POST our JSON data to server
outputStreamWriter = new OutputStreamWriter(httpURLConnection.getOutputStream());
outputStreamWriter.write(jsonToSend.toString());
outputStreamWriter.flush(); //flush the stream when we're finished writing to make sure all bytes get to their destination
//prepare input buffer and get the http response from server
StringBuilder stringBuilder = new StringBuilder();
int responseCode = httpURLConnection.getResponseCode();
//Check to make sure we got a valid status response from the server,
//then get the server JSON response if we did.
if(responseCode == HttpURLConnection.HTTP_OK) {
//read in each line of the response to the input buffer
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(),"utf-8"));
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
bufferedReader.close(); //close out the input stream
try {
//Copy the JSON response to a local JSONObject
jsonResponse = new JSONObject(stringBuilder.toString());
} catch (JSONException je) {
je.printStackTrace();
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
if(httpURLConnection != null) {
httpURLConnection.disconnect(); //close out our http connection
}
if(outputStreamWriter != null) {
try {
outputStreamWriter.close(); //close our output stream
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
//Return the JSON response from the server.
return jsonResponse;
This is pretty much all you need to know to do exactly what it is you are trying to do. I realize this is a ton of info to throw at you all at once, but if you take your time and work through it piece by piece, you'll find it's not too difficult after all and is actually a VERY powerful tool that you'll use all the time programming Android apps!
Hope this helps. Feel free to ask questions for any parts you don't fully understand yet!

Better use an AsyncTask to propagate the data to your UI thread, just use onPostExecute() to set the result on your activity's class.

The error you are getting is because of accessing UI elements from background thread.
AsyncTask is a Thread pool based api that runs your task in a seperate thread
,but your UI part runs in a thread usually called UI thread,
to update any changes to ui put the logic onPostExecute()
NOTE: Use okhttp to get consistent http api, it also supports http2.Their github wiki is very helpful, check here for examples.

Related

With Android you can transfer data to any site's form and trigger the send button

hello any site you want to log in form with an Android app in the background. How I can do this process, but I did not find a result if you can help me, thank you in advance.
more examples
Any educational institution has a student add form. I want to send my student information from my own database to this form
You can create AsyncTask class to submit the form data to the URL either using POST or GET.
for example:
`
class NetworkActivity extends AsyncTask<String,Void,String>{
#Override
protected String doInBackground(String.. params)
{
try{
Url url = new URL("Your URL Here");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.requestMethod("POST");
connection.setInstanceFollowRedirects(false);
connection.setDoOutput(true);
OutputStream os = connection.getOutputStream();
os.write("Form data here"+params[0]); // write form data here e.g. studentname=XYZ&rollno=123
InputStream is = connection.getInputStream();
BuffredReader br = new BufferedReader(new InputStreamReader(is));
//Fetch the output into a String
StringBuilder output = new StringBuilder();
while((line=br.readLine())!=null)
{
output.append(line);
}
return output.toString();
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
protected OnPostExecute(String result)
{
//Process the output here.
}
}
`
Now create a new object of this class and call the execute function the initiate the Network activity.
new NetworkActivity().execute("form data");

Android App crashes but the code shows no error

Okay so I'm trying to make an app that is able to retrieve data from a web server and then show it on a textView and constantly update it if the data changes from the web server. And what I got so far after many rounds of trying is this as shown
public class HttpTest extends AppCompatActivity {
TextView text = (TextView) this.findViewById(R.id.textView3);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_http_test);
HttpURLConnection urlConnection = null;
try {
URL url = new URL("http://IPGOESHERE/");
HttpURLConnection urLConnection = (HttpURLConnection) url.openConnection();
InputStream in = urLConnection.getInputStream();
BufferedReader data = new BufferedReader(new InputStreamReader(in));
StringBuilder total = new StringBuilder();
String line;
while ((line = data.readLine()) != null) {
total.append(line).append('\n');
}
String result = total.toString();
text.setText(result);
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
}
I don't think what i have written allows for constant update, but I at least want to be able to show some kind of data on a textView and make sure it doesn't crash first. So if someone could point out what I'm doing wrong it will be much appreciated.
The app crash because you are making HTTP request on main thread. Use an AsyncTask instead
you need to this kind of work on a different thread. try using an AsyncTask.
you create a class that extends AsyncTask, than make the url connection in the doInBackground method (a method that gets called on a worker thread). you can then update the textview in the onPostExecute method which is called on the ui thread. good luck :)

Accessing REST API in Android Using Request Headers

I have a question about the proper syntax and order of code in regards to accessing a REST API.
I am trying to access a database that I made on an mBaas called backendless.com. (The following data information is specific to this mBaas but my question is more about the general process of accessing REST API's in Android)
According to their tutorial to bulk delete (https://backendless.com/documentation/data/rest/data_deleting_data_objects.htm) I need a URL that queries my database for a specific value and then deletes it. I have that value. They also need 3 request headers (application-id, secret key, application type).I have those as well.
I utilized all of this information in an ASyncTask class that technically should open the url, set the request headers, and make the call to the REST API. My only issue is, I have no idea if I'm missing some kind of code here? Is my current code in proper order? Every time my class is executed, nothing happens.
I also get a log cat exception in regards to my URL: java.io.FileNotFoundException: api.backendless.com/v1/data/bulk/...
The URL does not lead to anything when I place it in my browser but I'm told that it shouldn't since the browser sends it as a GET request.
Anyway, here is my ASyncTask Class with all of the info. Does anyone know if this code looks correct or am I missing something here? I'm new to making these type of calls and don't really understand the roll that request-headers play in accessing REST APIs. Please let me know. Thank you!
class DeleteBulkFromBackEnd extends AsyncTask<Void,Void,String>{
final String API_URL = "https://api.backendless.com/v1/data/bulk/LocalPhoneNum?where%3DuserEmailID%3Dmark#gmail.com";
#Override
protected String doInBackground(Void... params) {
HttpURLConnection urlConnection = null;
try {
URL url = new URL(API_URL);
urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestProperty( "application-id","12345678" );
urlConnection.setRequestProperty( "secret-key","12345678" );
urlConnection.setRequestProperty( "application-type", "REST" );
urlConnection.connect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
Log.d("Contact","ERROR " + e.toString() );//IO Exception Prints in log cat not recognizing URL
e.printStackTrace();
}finally {
urlConnection.disconnect();
}
return null;
}
}
I recommend you to use okhttp for easy network access.
And check the response code and response body.
In your build.gradle:
compile 'com.squareup.okhttp3:okhttp:3.4.1'
Your AsyncTask will be like this:
class DeleteBulkFromBackEnd extends AsyncTask<Void, Void, String> {
final String API_URL = "https://api.backendless.com/v1/data/bulk/LocalPhoneNum?where%3DuserEmailID%3Dmark#gmail.com";
final OkHttpClient mClient;
public DeleteBulkFromBackEnd(OkHttpClient client) {
mClient = client;
}
#Override
protected String doInBackground(Void... params) {
try {
Request request = new Request.Builder()
.url(API_URL)
.delete()
.header("application-id", "12345678")
.header("secret-key", "12345678")
.header("application-type", "REST")
.build();
Response response = mClient.newCall(request).execute();
Log.d("DeleteBulkFromBackEnd", "Code: " + response.code());
Log.d("DeleteBulkFromBackEnd", "Body: " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Execute the AsyncTask like this:
OkHttpClient client = new OkHttpClient();
void someMethod() {
...
new DeleteBulkFromBackEnd(client).execute();
...
}
As I've commented, here's the solution:
class DeleteBulkFromBackEnd extends AsyncTask<Void,Void,String>{
final String API_URL = "https://api.backendless.com/v1/data/bulk/LocalPhoneNum?where%3DuserEmailID%3Dmark#gmail.com";
#Override
protected String doInBackground(Void... params) {
HttpURLConnection urlConnection = null;
try {
URL url = new URL(API_URL);
urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestProperty( "application-id","12345678" );
urlConnection.setRequestProperty( "secret-key","12345678" );
urlConnection.setRequestProperty( "application-type", "REST" );
urlConnection.setRequestMethod("DELETE");
urlConnection.connect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
Log.d("Contact","ERROR " + e.toString() );//IO Exception Prints in log cat not recognizing URL
e.printStackTrace();
}finally {
urlConnection.disconnect();
}
return null;
}
}

Android HttpUrlConnection response object

Hey i'm using HttpUrlConnection in my app. And it's seems to me that every time when I'm making call as .getInputStream() or urlConnection.getResponseCode() etc it makes another request, so it is not good for me, when i'm making POST request. Is there a way to get some kind of response object which encapsulates response data and can be accessible from UI thread, something like this:
private class RegisterAsync extends AsyncTask<String, Void, HttpResponse> {
protected String doInBackground(String... strings) {
HttpURLConnection urlConnection = null;
String message = null;
try {
URL url = new URL(REGISTER_URL);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setDoOutput(true);
urlConnection.setChunkedStreamingMode(0);
OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
out.write(strings[0].getBytes("UTF-8"));
out.flush();
out.close();
HttpResponse response = urlConnection.getResponse();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
urlConnection.disconnect();
}
return Response;
}
protected void onPostExecute(HttpResponse response) {
//Do some with response object: get status, headers, content etc?
}
}
you can do the following steps:
Create the webservice call in a singleton class
Parse the response and encapsulate it in a custom object(made by you) and save the parsed object into the singleton as instance object.
After this, you can simply send a broadcast message to your activity to let it know that the parsed data is available in the singleton
the onReceive() method of BroadcastReceiver runs on UI thread so you can quickly update your UI there..
After you implement that you can simply call the singleton webservice call method from your activity right after you register to the intent that will be sent from the singleton...

How and where to call my Task when extending AsyncTask

I am having difficulties understanding AsyncTask, even after reading everything about it on Developer.Android. I am looking for some insight in how I should proceed. This is the situation :
I have an Activity which, on an onClick event calls the LoginCheck() method of an underlying LoginController class. The LoginController class then proceeds to fetch whatever information is nescesarry from a UserInfo class or from the Activity(User and Password) and creates an instance of a RestClient which then makes the call to the web service and attempts to log in. RestClient has a private class CallServiceTask that extends AsyncTask.
I have a few design problems here that I hope you can be of assistance with.
Am I doing it right? Is this a proper way to make sure that any calls to the web service are being done asynchronously?
How do use onProgressUpdate or whatever to notify the user that the application is in the process of logging in?
How would I go about getting the data that is saved in DoinBackground() ?
Below you'll find snippets of the project in question :
RestClient
// From the constructor...
rtnData = new Object[]{ new JSONObject() , Boolean.TRUE };
public void ExecuteCall(RequestMethod method) throws Exception
{
Object[] parameters = new Object[]{ new HttpGet() , new String("") };
switch(method) {
case GET:
{
//add parameters
String combinedParams = "";
if(!params.isEmpty()){
combinedParams += "?";
for(NameValuePair p : params)
{
String paramString = p.getName() + "=" + URLEncoder.encode(p.getValue());
if(combinedParams.length() > 1)
{
combinedParams += "&" + paramString;
}
else
{
combinedParams += paramString;
}
}
}
HttpGet request = new HttpGet(url + combinedParams);
//add headers
for(NameValuePair h : headers)
{
request.addHeader(h.getName(), h.getValue());
}
parameters[0] = request;
parameters[1] = url;
new CallServiceTask().execute(request, url);
jsonData = ((JSONObject) rtnData[0]).optJSONObject("data");
connError = (Boolean) rtnData[1];
break;
}
case POST: ....
}
}
private Object[] executeRequest(HttpUriRequest request, String url)
{
HttpClient client = new DefaultHttpClient();
client = getNewHttpClient();
HttpResponse httpResponse;
try {
httpResponse = client.execute(request);
HttpEntity entity = httpResponse.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
String response = convertStreamToString(instream);
try {
rtnData[0] = new JSONObject(response);
rtnData[1] = false;
} catch (JSONException e1) {
rtnData[1] = true;
e1.printStackTrace();
}
// Closing the input stream will trigger connection release
instream.close();
}
} catch (ClientProtocolException e) {
client.getConnectionManager().shutdown();
e.printStackTrace();
} catch (IOException e) {
client.getConnectionManager().shutdown();
e.printStackTrace();
}
return rtnData;
}
CallServiceTask
private class CallServiceTask extends AsyncTask<Object, Void, Object[]>
{
protected Object[] doInBackground(Object... params)
{
HttpUriRequest req = (HttpUriRequest) params[0];
String url = (String) params[1];
return executeRequest(req, url);
}
#Override
protected void onPostExecute(Object[] result)
{
rtnData = result;
}
}
It's absolutely right that any possibly long running operations should be executed in separate threads. And the AsyncTask is a good way to solve this kind of problems, since it also gives you an easy way to synchronize your task with the UI thread. This is the answer to your first question.
Now, concerning the UI thread updating to show your users that your application is not stuck. Since an AsyncTask's onPreExecute() and onPostExecute() methods are running inside the UI thread, you can easily create, run and stop ProgressDialogs or ProgressBars there. If you want to show the current progress of the task, you should call publishProgress(int) method inside the doInBackground(), and then make use of it inside the AsyncTask's onProgressUpdate() method. There you can, for example, update your ProgressDialog.
And to get the result out of your AsyncTask you can either call its get() method (this a synchronous call), or implement some kind of callback interface that will tell the activity that the task has finished.
I hope the answer is clear enough, if no - feel free to ask more questions. Hope this helps.
EDIT
Create an interface called, for example, onFetchFinishedListener with one method - void onFetchFinished(String). Your activity, that starts the AsyncTask, must implement this interface. Now create a constructor inside your AsyncTask that takes an OnFetchFinishedListener object as an argument, and when instantiating the AsyncTask inside your activity send a reference to the Activity as the argument (since it implements OnFetchFinishedListener). Then when your task is finished inside doInBackground() call onFetchFinished() on the activity. Now inside the onFetchFinished(String) method of your Activity you can make use of the String (or another object) that's brought with the callback. Again, hope I was clear enough.

Categories

Resources