Issue
I'm following a CRUD tutorial on https://www.androidhive.info/2012/05/how-to-connect-android-with-php-mysql/.
I changed settings to my own need, but the runOnUiThread like the tutorial gives me an forced close on the app.
If I replace the code by something else, the activity will run but the fields won't populate.
My code:
package nl.app.app.recipefinder;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.StrictMode;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
public class EditIngredientActivity extends Activity {
// spinner text fields to select from
Spinner spinner;
String[] volume = {
"Liter",
"Mililiter",
"Kilogram",
"Gram",
"Stuk(s)"
};
EditText txtName;
EditText txtQuantity;
EditText txtDesc;
EditText txtCreatedAt;
Button btnSave;
Button btnDelete;
String pid;
// Progress Dialog
private ProgressDialog pDialog;
// JSON parser class
JSONParser jsonParser = new JSONParser();
// single product url
private static final String url_ingredient_details = "http://www.linktosite";
// url to update product
private static final String url_update_ingredient = "http://www.linktosite";
// url to delete product
private static final String url_delete_ingredient = "http://www.linktosite";
// JSON Node names
private static final String TAG_SUCCESS = "success";
private static final String TAG_INGREDIENT = "ingredients";
private static final String TAG_PID = "pid";
private static final String TAG_NAME = "name";
private static final String TAG_QUANTITY = "quantity";
private static final String TAG_DESCRIPTION = "description";
private static final String TAG_VOLUME = "volume";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.edit_ingredient);
// Get reference of SpinnerView from layout/current_layout.xml
spinner = (Spinner)findViewById(R.id.DropDownVolume);
ArrayAdapter<String> adapter= new ArrayAdapter<String>(this,android.
R.layout.simple_spinner_dropdown_item ,volume);
spinner.setAdapter(adapter);
// save button
btnSave = (Button) findViewById(R.id.btnSave);
btnDelete = (Button) findViewById(R.id.btnDelete);
// getting product details from intent
Intent i = getIntent();
// getting product id (pid) from intent
pid = i.getStringExtra(TAG_PID);
// Getting complete product details in background thread
new GetProductDetails().execute();
// save button click event
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// starting background task to update product
new SaveProductDetails().execute();
Log.d("good", "Created new ingredient");
}
});
// Delete button click event
btnDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// deleting product in background thread
new DeleteProduct().execute();
Log.d("good", "Deleted ingredient");
}
});
}
/**
* Background Async Task to Get complete product details
* */
class GetProductDetails extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(EditIngredientActivity.this);
pDialog.setMessage("Loading ingredient details. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
/**
* Getting product details in background thread
* */
protected String doInBackground(String... params) {
// updating UI from Background Thread
runOnUiThread(new Runnable() {
public void run() {
// Check for success tag
int success;
try {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("pid", pid));
// getting product details by making HTTP request
// Note that product details url will use GET request
JSONObject json = jsonParser.makeHttpRequest(
url_ingredient_details, "GET", params);
// check your log for json response
Log.d("Single Ingredient Det", json.toString());
// json success tag
success = json.getInt(TAG_SUCCESS);
if (success == 1) {
// successfully received product details
JSONArray productObj = json
.getJSONArray(TAG_INGREDIENT); // JSON Array
// get first product object from JSON Array
JSONObject product = productObj.getJSONObject(0);
// product with this pid found
// Edit Text
txtName = (EditText) findViewById(R.id.inputName);
txtQuantity = (EditText) findViewById(R.id.inputQuantity);
txtDesc = (EditText) findViewById(R.id.inputDesc);
spinner = (Spinner) findViewById(R.id.DropDownVolume);
// display product data in EditText
txtName.setText(product.getString(TAG_NAME));
txtQuantity.setText(product.getString(TAG_QUANTITY));
txtDesc.setText(product.getString(TAG_DESCRIPTION));
Log.d("good", "shows ingredient");
}else{
// product with pid not found
Log.d("bad", "ingredient not found");
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url) {
// dismiss the dialog once got all details
pDialog.dismiss();
}
}
/**
* Background Async Task to Save product Details
* */
class SaveProductDetails extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(EditIngredientActivity.this);
pDialog.setMessage("Saving ingredient ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
/**
* Saving product
* */
protected String doInBackground(String... args) {
// getting updated data from EditTexts
String name = txtName.getText().toString();
String price = txtQuantity.getText().toString();
String description = txtDesc.getText().toString();
String volume = spinner.getSelectedItem().toString();
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair(TAG_PID, pid));
params.add(new BasicNameValuePair(TAG_NAME, name));
params.add(new BasicNameValuePair(TAG_QUANTITY, price));
params.add(new BasicNameValuePair(TAG_DESCRIPTION, description));
params.add(new BasicNameValuePair("TAG_VOLUME", volume));
// sending modified data through http request
// Notice that update product url accepts POST method
JSONObject json = jsonParser.makeHttpRequest(url_update_ingredient,
"POST", params);
Log.d("good", "Posted ingredient");
// check json success tag
try {
int success = json.getInt(TAG_SUCCESS);
if (success == 1) {
// successfully updated
Intent i = getIntent();
// send result code 100 to notify about product update
setResult(100, i);
finish();
Log.d("good", "finished update");
} else {
// failed to update product
Log.d("bad", "Update ingredient failed");
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url) {
// dismiss the dialog once product uupdated
pDialog.dismiss();
}
}
/*****************************************************************
* Background Async Task to Delete Product
* */
class DeleteProduct extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(EditIngredientActivity.this);
pDialog.setMessage("Deleting ingredient...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
/**
* Deleting product
* */
protected String doInBackground(String... args) {
// Check for success tag
int success;
try {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("pid", pid));
// getting product details by making HTTP request
JSONObject json = jsonParser.makeHttpRequest(
url_delete_ingredient, "POST", params);
// check your log for json response
Log.d("Delete Product", json.toString());
// json success tag
success = json.getInt(TAG_SUCCESS);
if (success == 1) {
// product successfully deleted
// notify previous activity by sending code 100
Intent i = getIntent();
// send result code 100 to notify about product deletion
setResult(100, i);
finish();
Log.d("good", "Deleted ingredient");
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url) {
// dismiss the dialog once product deleted
pDialog.dismiss();
}
}
}
Solution
I am not sure what you are confused about. The exception is clear; You are performing a network operation on a UI thread. This is not permissible in Android. Move your HTTP request outside of your runonuithread block. Do all of your UI stuff in your post execute method. It seems to me that you do not quite understand what AsyncTask does. Here is a bit of info: https://developer.android.com/reference/android/os/AsyncTask
In short, the doInBackground() method runs on a non-UI thread and onPostExecute() method (which runs after doInBackground() method finishes) runs on the UI thread. That is why you should not put runonuithread block inside your doInBackground() method like you have done (where runonuithread is the only thing that you run in doInBackground() method). There is no point in using an AsyncTask if you do that.
Also I took a quick look at your tutorial link. The tutorial does not put runonUiThread block inside their asynctask's doInBackground() method. Is there a reason why you put it in?
Answered By - Steven
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.