So I have been trying to workout an authentication system for my app. I have a REST API running, which is tested to work with Oauth2 authentication using CURL from my laptop, so that I can get tokens for the API.
My result variable within the doInBackground does get a JSON response from my API, giving the access token information, its life, etc.
Like I get this value in result when I debug:
{"access_token":"4Oq6o8oAGRf4oflu3hrbsy18qeIfG1","expires_in":36000,"token_type":"Bearer","scope":"read write","refresh_token":"iocSNJ2PTVbph2RnWmcf0Zv69PDKjw"}
However, my onPostExecute for some reason is not getting called.
Here is my code.
login.java
public class Login extends AppCompatActivity {
Button LoginButton, RegButton;
EditText uUserName, uPassWord;
WSAdapter.SendAPIRequests AuthHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
//SetupHomeBtn = (ImageButton) findViewById(R.id.SetupHomeBtn);
LoginButton = (Button) findViewById(R.id.LoginButton);
RegButton = (Button) findViewById(R.id.LoginRegister);
uUserName = (EditText) findViewById(R.id.LoginUserBox);
uPassWord = (EditText) findViewById(R.id.LoginPassBox);
//AuthHelper = new WSAdapter().new SendDeviceDetails();
// Moves user to the main page after validation
LoginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// gets the username and password from the EditText
String strUserName = uUserName.getText().toString();
String strPassWord = uPassWord.getText().toString();
// API url duh
String APIUrl = "http://192.168.0.18:8000/auth/token/";
// If the user is authenticated, then transfer to the MainActivity page
if (APIAuthentication(strUserName, strPassWord, APIUrl)){
startActivity(new Intent(Login.this, Posts.class));
}
}
});
RegButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// gets the username and password from the EditText
startActivity(new Intent(Login.this, Register.class));
}
});
}
private boolean APIAuthentication(String un, String pw, String url){
// when it wasn't static -> AuthHelper = new WSAdapter().new SendAPIRequests();
AuthHelper = new WSAdapter.SendAPIRequests();
try {
// Putting the data to be posted in the Django API
AuthHelper.execute(un, pw, url);
return true;
} catch (JSONException e) {
e.printStackTrace();
}
return false;
}
}
WSAdapter.java
public class WSAdapter {
static public class SendAPIRequests extends AsyncTask<String, String, String> {
// Add a pre-execute thing
#Override
protected String doInBackground(String... params) {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
Log.e("TAG", params[0]);
Log.e("TAG", params[1]);
//String data = "";
StringBuilder result = new StringBuilder();
HttpURLConnection httpURLConnection = null;
try {
// Sets up connection to the URL (params[0] from .execute in "login")
httpURLConnection = (HttpURLConnection) new URL(params[2]).openConnection();
// Sets the request method for the URL
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
httpURLConnection.setRequestProperty("Accept","application/json");
// Tells the URL that I am sending a POST request body
httpURLConnection.setDoOutput(true);
// Tells the URL that I want to read the response data
httpURLConnection.setDoInput(true);
// JSON object for the REST API
JSONObject jsonParam = new JSONObject();
jsonParam.put("client_id", "mYIHBd321Et3sgn7DqB8urnyrMDwzDeIJxd8eCCE");
jsonParam.put("client_secret", "qkFYdlvikU4kfhSMBoLNsGleS2HNVHcPqaspCDR0Wdrdex5dHyiFHPXctedNjugnoTq8Ayx7D3v1C1pHeqyPh1BjRlBTQiJYSuH6pi9EVeuyjovxacauGVeGdsBOkHI3");
jsonParam.put("username", params[0]);
jsonParam.put("password", params[1]);
jsonParam.put("grant_type", "password");
Log.i("JSON", jsonParam.toString());
// To write primitive Java data types to an output stream in a portable way
DataOutputStream wr = new DataOutputStream(httpURLConnection.getOutputStream());
// Writes out a byte to the underlying output stream of the data posted from .execute function
wr.writeBytes(jsonParam.toString());
// Flushes the jsonParam to the output stream
wr.flush();
wr.close();
// // Representing the input stream
InputStream in = new BufferedInputStream(httpURLConnection.getInputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
// reading the input stream / response from the url
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// Disconnects socket after using
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
Log.e("TAG", result.toString());
return result.toString();
}
#Override
protected void onPostExecute(String result) {
//super.onPostExecute(result);
// expecting a response code fro my server upon receiving the POST data
Log.e("TAG", result);
}
}
SO I actually just figured this out. It turns out that my code is running fine, its just that when I debug, I didn't realize theres a button to the side "Run the new thread" or something like that. It then sent me to the onPostExecute. Sorry for being a noob. Hopefully this can be a help to somebody in the future with this simple mistake.
I am New to the android studio and want to something more. Actually, I am trying to pass the string that I got from the spinner in onCreateMethod and pass to the onPostExecute function. I will be grateful for the help. Bellow is my code.
I tried making a global variable called First and store the string from spinner and pass it on the onPostExecute function.
public class Convert extends AppCompatActivity implements LocationListener
{
Spinner dropdown;
Button btn;
String text;
String first;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_convert);
dropdown = (Spinner) findViewById(R.id.spinner1);
btn = (Button)findViewById(R.id.btn);
String[] items = new String[]{"United States,USD", "Nepal,NPR", "Bangladesh,BDT","Brazil,BRL"};
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, items);
dropdown.setAdapter(adapter);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
text = dropdown.getSelectedItem().toString();
first = text.substring(text.length()-3);
Log.i("her", first);
}
});
new DownloadTask().execute("http://openexchangerates.org/api/latest.json?
app_id=XXXXXXXXXX");
}
public class DownloadTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String result = "";
URL url;
HttpURLConnection httpURLConnection = null;
try {
url = new URL(urls[0]);
httpURLConnection = (HttpURLConnection) url.openConnection();
InputStream in = httpURLConnection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while (data != -1) {
char counter = (char) data;
result += counter;
data = reader.read();
}
return result;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
try{
JSONObject jsonObject = new JSONObject(result);
JSONObject curr = jsonObject.getJSONObject("rates");
String npr = curr.getString(first);
Log.i("money", npr );
} catch (JSONException e) {
e.printStackTrace();
}
}
}
What I want is to pass the string first on the onPostExecute function.
When you will call your DownloadTask, asyncTask fires with method execute, just pass param though him. Example:
How to pass url
new DownloadTask().execute("url for download");
How to receive url
protected String doInBackground(String... urls) {
String url = urls[0]; // url for download
}
Also you could send and array of params. Also be careful with AsyncTask, do not pass your context/view variable, it could arise memory leaks, read docs.
I have an Activity that uses a ListView to display an array of data fetched from a JSON response. Clicking on one of the items will present the user with a business card activity, displaying the data associated with the item clicked. When the application first loads, it works fine. I can close the business card and reopen it multiple times. However, if i pause on the ListView activity, the page will no longer load the data. I have placed Log.d commands before and after the connection to try debugging the issue. The activity is receiving the information necessary to perform the connection. However, the closest I have gotten to a solution is knowing that when it doesn't work, I cannot Log.d the response code immediately after opening the connection.
To be clear, I am including the entirety of the code I am using, just in case the issue lies somewhere else. First is the code for the ListView Activity, then is the Business Card Activity code.
This is the Directory Activity.
public class DirectoryActivity extends AppCompatActivity {
ListView lvContacts;
Button goMenu;
Button goFilter;
TextView tempText;
static ArrayList<String> arrlst = new ArrayList<>();
static ArrayAdapter<String> adapter;
private FetchList process;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_directory);
lvContacts = findViewById(R.id.lvContacts);
goMenu = findViewById(R.id.btn_goMenu);
goFilter = findViewById(R.id.btn_goSearch);
tempText = findViewById(R.id.temptext);
// Set adapter for listview: used in FetchList
adapter = new ArrayAdapter<>(this, R.layout.layout_org_list, R.id.listViewItem, arrlst );
lvContacts.setAdapter(adapter);
// Get list from DB
process = new FetchList();
process.setListener(new FetchList.FetchListTaskListener() {
#Override
public void onFetchListTaskFinished(String[] result) {
// update UI in Activity here
arrlst.clear();
for (String OrgName:result) {
addItemsToList(OrgName);
}
adapter.notifyDataSetChanged();
}
});
process.execute();
// Set onclick listener for listview
lvContacts.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
String selectedOrg = lvContacts.getItemAtPosition(position).toString(); // Get org name from list view
goBusinessCard(selectedOrg); // Go to business card
}
});
}
#Override
protected void onDestroy() {
process.setListener(null); // PREVENT LEAK AFTER ACTIVITY DESTROYED
super.onDestroy();
}
public static void addItemsToList(String item) {
arrlst.add(item);
}
// Set Methods for Buttons
public void goMenu(View v) {
startActivity(new Intent(this, HomeActivity.class));
}
public void goFilter(View v) {
startActivity(new Intent(this, FilterActivity.class));
Log.d("FILTER DEBUG", "checking if extras are filled " + this.getIntent().getExtras());
}
// Method for opening BusinessCardActivity and passes orgID
public void goBusinessCard(String selectedOrg) {
Bundle extras = new Bundle();
extras.clear();
extras.putString("selectedOrg", selectedOrg);
Intent BusinessCard = new Intent(this, BusinessCardActivity.class);
BusinessCard.putExtras(extras);
startActivity(BusinessCard);
}
// ASYNC TASK
static class FetchList extends AsyncTask<Void, Void, String[]> {
private FetchListTaskListener listener;
#Override
protected String[] doInBackground(Void... voids) {
try {
URL url = new URL(URL_READ_ORG ); // Set url to API Call location
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); // Open connection to html
InputStream inputStream = httpURLConnection.getInputStream(); // create input stream from html location
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8")); // create reader for inputStream
StringBuilder data = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null ) {
data.append(line); // creates string from all lines in response
}
bufferedReader.close();
inputStream.close();
httpURLConnection.disconnect();
JSONObject JO = new JSONObject(data.toString()); // creates object from json response in data string
JSONArray JA = JO.getJSONArray("orgs");
// Create array list to store items from json response
List<String> al_orgList = new ArrayList<>();
// Iterate through JSON array to get json object org_name
for (int i = 0; i < JA.length(); i++) {
JSONObject Orgs = JA.getJSONObject(i);
String org_name = Orgs.getString("org_name");
al_orgList.add(org_name);
}
// convert array list to array
return al_orgList.toArray(new String[al_orgList.size()]);
} catch (JSONException | IOException e) {
e.printStackTrace();
}
return null;
}
// UI Process - allows manipulation of UI
#Override
protected void onPostExecute(String[] result) {
super.onPostExecute(result);
if (listener != null) {
listener.onFetchListTaskFinished(result);
}
}
private void setListener(FetchListTaskListener listener) {
this.listener = listener;
}
public interface FetchListTaskListener {
void onFetchListTaskFinished(String[] result);
}
}
This is the Business Card Activity that runs the data fetch for individual items
public class BusinessCardActivity extends AppCompatActivity {
TextView tv_org, tv_name, tv_email, tv_phone, tv_website, tv_servicetype,
tv_servicesprovided, tv_address;
String Favorite, Latitude, Longitude, selectedOrg, FavoriteChanged, dbPhone, phoneNum, dbWeb, orgWeb;
CheckBox cbFavorite;
List<String> arrlstID = new ArrayList<>();
String[] arrID;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_business_card);
// Assign fields to variables
tv_org = findViewById(R.id.tv_org);
tv_name = findViewById(R.id.tv_name);
tv_email = findViewById(R.id.tv_email);
tv_phone = findViewById(R.id.tv_phone);
tv_website = findViewById(R.id.tv_website);
tv_servicetype = findViewById(R.id.tv_servicetype);
tv_servicesprovided = findViewById(R.id.tv_servicesprovided);
tv_address = findViewById(R.id.tv_address);
cbFavorite = findViewById(R.id.cbFavorite);
// Set variable for selectedOrg from DirectoryActivity
selectedOrg = Objects.requireNonNull(this.getIntent().getExtras()).getString("selectedOrg");
// Get Org data from DB using async
process = new FetchOrg();
process.setListener(new FetchOrg.FetchOrgTaskListener() {
#Override
public void onFetchOrgTaskFinished(String[] result) {
setTextView(result);
// onClick for Email
tv_email.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
showEmailDialog();
}
});
// onClick for Call
tv_phone.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Get phone number from DB
// Replace any non-digit in phone number to make call
phoneNum = dbPhone.replaceAll("\\D", "");
// make call
goCall(phoneNum);
}
});
// onClick for Web
tv_website.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Fix URL logic
orgWeb = "http://" + dbWeb;
goWeb(orgWeb);
}
});
// onClick for Address
tv_address.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
goMap();
}
});
// TODO add favorite functionality
// When checkbox status changes, change value of Favorite
cbFavorite.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
}
});
}
});
process.execute(selectedOrg);
/*
// if favorite = 1 then check box
if (Favorite.equals("1")) {
cbFavorite.setChecked(true);
} else {
cbFavorite.setChecked(false);
}
*/
}
#Override
protected void onDestroy() {
process.setListener(null); // PREVENT LEAK AFTER ACTIVITY DESTROYED
super.onDestroy();
}
// Method to assign text view items from async task
public void setTextView(String[] org_data) {
String name = org_data[1] + " " + org_data[2];
String address = org_data[8] + " " + org_data[9] + " " + org_data[10] + " " + org_data[11];
tv_org.setText(org_data[0]);
tv_name.setText(name);
tv_email.setText(org_data[3]);
tv_phone.setText(org_data[4]);
tv_website.setText(org_data[5]);
tv_servicetype.setText(org_data[6]);
tv_servicesprovided.setText(org_data[7]);
tv_address.setText(address);
}
public void showEmailDialog() {
// Get dialog_box_goals.xml view
LayoutInflater layoutInflater = LayoutInflater.from(BusinessCardActivity.this);
View promptView = layoutInflater.inflate(R.layout.dialog_box_send_email, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(BusinessCardActivity.this);
alertDialogBuilder.setView(promptView);
final EditText etEmailMessage = (EditText) promptView.findViewById(R.id.etMailMessage);
// setup a dialog window
alertDialogBuilder.setCancelable(false)
.setPositiveButton("Submit", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// my code
/* WONT USE THIS UNTIL EMAILS ARE FINAL
USING MY EMAIL FOR TESTING PURPOSES
// Get email
niagaraDB.open();
c2 = niagaraDB.getEmailByID(passedID);
if (c2.moveToFirst())
{
public String emailTo = c2.getString(0);
}
niagaraDB.close();
*/
// This is for final code
// String to = "mailto:" + emailTo;
String to = "snownwakendirt#yahoo.com";
String subject = "Mail From Connect & Protect Niagara App";
String message = etEmailMessage.getText().toString();
if (message.isEmpty()) {
Toast.makeText(BusinessCardActivity.this,
"Message must contain something",
Toast.LENGTH_LONG).show();
} else {
Intent email = new Intent(Intent.ACTION_SEND);
email.putExtra(Intent.EXTRA_EMAIL, new String[] { to });
// email.putExtra(Intent.EXTRA_CC, new String[]{ to});
// email.putExtra(Intent.EXTRA_BCC, new String[]{to});
email.putExtra(Intent.EXTRA_SUBJECT, subject);
email.putExtra(Intent.EXTRA_TEXT, message);
// need this to prompt email client only
email.setType("message/rfc822");
try {
startActivity(Intent.createChooser(email, "Choose an Email client :"));
finish();
Log.i("Email Sent...", "");
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(BusinessCardActivity.this,
"There is no email client installed.",
Toast.LENGTH_SHORT).show();
}
}
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
// create an alert dialog
AlertDialog alert = alertDialogBuilder.create();
alert.show();
}
public void goCall(final String phoneNum) {
startActivity(new Intent(Intent.ACTION_DIAL, Uri.fromParts("tel", phoneNum, null)));
}
public void goWeb(String orgWeb) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(orgWeb)));
}
public void goCloseBusinessCard(View v) {
finish();
startActivity(new Intent(this, DirectoryActivity.class));
}
public void goMap() {
/*
int locationAddressLatInt = Integer.parseInt(locationAddressLat);
int locationAddressLongInt = Integer.parseInt(locationAddressLong);
*/
// pass id to map view. only one item in array for ease of use in MapActivity
arrlstID.add(selectedOrg);
arrID = new String[arrlstID.size()];
arrlstID.toArray(arrID);
Bundle extras = new Bundle();
extras.putStringArray("arrID", arrID);
Intent Map = new Intent(BusinessCardActivity.this, MapActivity.class);
Map.putExtras(extras);
startActivity(Map);
}
// ASYNC TASK
static class FetchOrg extends AsyncTask<String, Void, String[]> {
private FetchOrgTaskListener listener;
#Override
protected String[] doInBackground(String... params) {
try {
// assign passed string from main thread
String org_name = params[0];
String orgbyname = URL_GET_ORG_BY_NAME + "?org_name=" + org_name;
String line = "";
URL url = new URL(orgbyname);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
InputStream is = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is, "utf-8"));
line = br.readLine();
br.close();
is.close();
conn.disconnect();
/*
This JSON section contains a JSON Object that holds a JSON Array. The Array is created to
individualize each object within the JSON Array. Then, each JSON object is fetched and
assigned to a string variable.
*/
JSONObject JO = new JSONObject(line); // creates object from json response in data string
JSONObject Orgs = JO.getJSONObject("orgs"); // creates array for parsing of json data
// get items from JSONArray and assign for passing to onProgressUpdate
String Org = Orgs.getString("org_name");
String FirstName = Orgs.getString("contact_first_name");
String LastName = Orgs.getString("contact_last_name");
String Email = Orgs.getString("contact_email");
String Phone = Orgs.getString("contact_phone");
String Website = Orgs.getString("org_website");
String ServiceType = Orgs.getString("org_type");
String ServicesProvided = Orgs.getString("org_services");
String Address = Orgs.getString("org_street_address");
String City = Orgs.getString("org_city");
String State = Orgs.getString("org_state");
String Zip = Orgs.getString("org_zip");
String Lat = Orgs.getString("latitude");
String Long = Orgs.getString("longitude");
// Add items to string array
String[] org_data = new String[14]; // 14 is length of array, not the count
org_data[0] = Org;
org_data[1] = FirstName;
org_data[2] = LastName;
org_data[3] = Email;
org_data[4] = Phone;
org_data[5] = Website;
org_data[6] = ServiceType;
org_data[7] = ServicesProvided;
org_data[8] = Address;
org_data[9] = City;
org_data[10] = State;
org_data[11] = Zip;
org_data[12] = Lat;
org_data[13] = Long;
return org_data;
} catch (IOException | JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String[] result) {
super.onPostExecute(result);
if (listener != null) {
listener.onFetchOrgTaskFinished(result);
}
}
private void setListener(FetchOrgTaskListener listener) {
this.listener = listener;
}
public interface FetchOrgTaskListener {
void onFetchOrgTaskFinished(String[] result);
}
}
Activity lifecycle would go back from paused to resume state.
You need to provide the expected behaviour inside onResume something like below
public void onResume(){
super.onResume();
new XXXAsyncTask( new XXXAsyncListener(){
public void postTaskMethod(){
//do stuff here
}
}).execute();
}
I made a few changes in your onCreate()method of your BusinessCardActivity. I check for hasExtra instead--a little more flexibility. I got rid of the Listener and packed all onClick listener below. I felt it was a bit too complicated using the Listener approach (So you can remove this process.setListener(null); from the onDestroy()method). I also added a few Log.e(); so you can see what is going on in the logcat.
(BTW "TAG" would be:
private static final Strting TAG = BusinessCardActivity.class.getSimpleName();)
With "BusinessCardActivity.class.getSimpleName();" written out just in case you refactor sometime.
This is part of your BusinessCardActivity onCreate() method:
// Set variable for selectedOrg from DirectoryActivity
Intent intent = this.getIntent();
if(intent.hasExtra(selectedOrg)){
String selectedOrg = intent.getStringExtra("selectedOrg")
Log.e(TAG, "selectedOrg : " + selectedOrg);
FetchOrg process = new FetchOrg();
process.execute(selectedOrg);
}
else{
Log.e(TAG, "No Extras!")
//You might what to call finish() here
return;
}
//Move all your onClick Listeners below...
I don't think this is the best case to use a Listener so lets use the AsyncTask like this (I also removed the static):
class FetchOrg extends AsyncTask<String, Void, String[]> {
#Override
protected String[] doInBackground(String... params) {
try {
Log.e(TAG, "doInBackground ... Started");
// assign passed string from main thread
String org_name = params[0];
String orgbyname = URL_GET_ORG_BY_NAME + "?org_name=" + org_name;
String line = "";
URL url = new URL(orgbyname);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
InputStream is = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is, "utf-8"));
line = br.readLine();
br.close();
is.close();
conn.disconnect();
Log.e(TAG, "Data Returned : " + line);
/*
This JSON section contains a JSON Object that holds a JSON Array. The Array is created to
individualize each object within the JSON Array. Then, each JSON object is fetched and
assigned to a string variable.
*/
JSONObject JO = new JSONObject(line); // creates object from json response in data string
JSONObject Orgs = JO.getJSONObject("orgs"); // creates array for parsing of json data
// get items from JSONArray and assign for passing to onProgressUpdate
String Org = Orgs.getString("org_name");
String FirstName = Orgs.getString("contact_first_name");
String LastName = Orgs.getString("contact_last_name");
String Email = Orgs.getString("contact_email");
String Phone = Orgs.getString("contact_phone");
String Website = Orgs.getString("org_website");
String ServiceType = Orgs.getString("org_type");
String ServicesProvided = Orgs.getString("org_services");
String Address = Orgs.getString("org_street_address");
String City = Orgs.getString("org_city");
String State = Orgs.getString("org_state");
String Zip = Orgs.getString("org_zip");
String Lat = Orgs.getString("latitude");
String Long = Orgs.getString("longitude");
// Add items to string array
String[] org_data = new String[14]; // 14 is length of array, not the count
org_data[0] = Org;
org_data[1] = FirstName;
org_data[2] = LastName;
org_data[3] = Email;
org_data[4] = Phone;
org_data[5] = Website;
org_data[6] = ServiceType;
org_data[7] = ServicesProvided;
org_data[8] = Address;
org_data[9] = City;
org_data[10] = State;
org_data[11] = Zip;
org_data[12] = Lat;
org_data[13] = Long;
return org_data;
} catch (IOException | JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String[] result) {
setTextView(result);
}
}
Also I would change your method goBusinessCard() a bit (and no need to be public):
private void goBusinessCard(String selectedOrg) {
//Java variables should written in lower case and Classes Capitalized
Intent businessCard = new Intent(this, BusinessCardActivity.class);
businessCard.putExtra("selectedOrg", selectedOrg);
startActivity(businessCard);
}
Please let me know if you have any issues! I typed this out in a standard Text Editor..so there might be a few typos.
Posting a new answer so I can add all the code for the BusinessCardActivity class.
I added some additional logging and changed getString() to optString() in order to be able to offer an alternative value. For example if the value or "key" is invalid or missing you would get an error.
public class BusinessCardActivity extends AppCompatActivity {
TextView tv_org, tv_name, tv_email, tv_phone, tv_website, tv_servicetype,
tv_servicesprovided, tv_address;
String Favorite, Latitude, Longitude, FavoriteChanged, dbPhone, phoneNum, dbWeb, orgWeb;
CheckBox cbFavorite;
List<String> arrlstID = new ArrayList<>();
String[] arrID;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_business_card);
// Assign fields to variables
tv_org = findViewById(R.id.tv_org);
tv_name = findViewById(R.id.tv_name);
tv_email = findViewById(R.id.tv_email);
tv_phone = findViewById(R.id.tv_phone);
tv_website = findViewById(R.id.tv_website);
tv_servicetype = findViewById(R.id.tv_servicetype);
tv_servicesprovided = findViewById(R.id.tv_servicesprovided);
tv_address = findViewById(R.id.tv_address);
cbFavorite = findViewById(R.id.cbFavorite);
Intent intent = this.getIntent();
if(!intent.hasExtra("selectedOrg")){
Log.e(TAG, "No Extras!")
//You might what to call finish() here
return;
}
String selectedOrg = intent.getStringExtra("selectedOrg")
Log.e(TAG, "selectedOrg : " + selectedOrg);
FetchOrg process = new FetchOrg();
process.execute(selectedOrg);
// onClick for Email
tv_email.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
showEmailDialog();
}
});
// onClick for Call
tv_phone.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Get phone number from DB
// Replace any non-digit in phone number to make call
phoneNum = dbPhone.replaceAll("\\D", "");
// make call
goCall(phoneNum);
}
});
// onClick for Web
tv_website.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Fix URL logic
orgWeb = "http://" + dbWeb;
goWeb(orgWeb);
}
});
// onClick for Address
tv_address.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
goMap();
}
});
// TODO add favorite functionality
// When checkbox status changes, change value of Favorite
cbFavorite.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
}
});
/*
// if favorite = 1 then check box
if (Favorite.equals("1")) {
cbFavorite.setChecked(true);
} else {
cbFavorite.setChecked(false);
}
*/
}
#Override
protected void onDestroy() {
process.setListener(null); // PREVENT LEAK AFTER ACTIVITY DESTROYED
super.onDestroy();
}
// Method to assign text view items from async task
public void setTextView(String[] org_data) {
String name = org_data[1] + " " + org_data[2];
String address = org_data[8] + " " + org_data[9] + " " + org_data[10] + " " + org_data[11];
tv_org.setText(org_data[0]);
tv_name.setText(name);
tv_email.setText(org_data[3]);
tv_phone.setText(org_data[4]);
tv_website.setText(org_data[5]);
tv_servicetype.setText(org_data[6]);
tv_servicesprovided.setText(org_data[7]);
tv_address.setText(address);
}
public void showEmailDialog() {
// Get dialog_box_goals.xml view
LayoutInflater layoutInflater = LayoutInflater.from(BusinessCardActivity.this);
View promptView = layoutInflater.inflate(R.layout.dialog_box_send_email, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(BusinessCardActivity.this);
alertDialogBuilder.setView(promptView);
final EditText etEmailMessage = (EditText) promptView.findViewById(R.id.etMailMessage);
// setup a dialog window
alertDialogBuilder.setCancelable(false)
.setPositiveButton("Submit", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// my code
/* WONT USE THIS UNTIL EMAILS ARE FINAL
USING MY EMAIL FOR TESTING PURPOSES
// Get email
niagaraDB.open();
c2 = niagaraDB.getEmailByID(passedID);
if (c2.moveToFirst())
{
public String emailTo = c2.getString(0);
}
niagaraDB.close();
*/
// This is for final code
// String to = "mailto:" + emailTo;
String to = "snownwakendirt#yahoo.com";
String subject = "Mail From Connect & Protect Niagara App";
String message = etEmailMessage.getText().toString();
if (message.isEmpty()) {
Toast.makeText(BusinessCardActivity.this,
"Message must contain something",
Toast.LENGTH_LONG).show();
} else {
Intent email = new Intent(Intent.ACTION_SEND);
email.putExtra(Intent.EXTRA_EMAIL, new String[] { to });
// email.putExtra(Intent.EXTRA_CC, new String[]{ to});
// email.putExtra(Intent.EXTRA_BCC, new String[]{to});
email.putExtra(Intent.EXTRA_SUBJECT, subject);
email.putExtra(Intent.EXTRA_TEXT, message);
// need this to prompt email client only
email.setType("message/rfc822");
try {
startActivity(Intent.createChooser(email, "Choose an Email client :"));
finish();
Log.i("Email Sent...", "");
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(BusinessCardActivity.this,
"There is no email client installed.",
Toast.LENGTH_SHORT).show();
}
}
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
// create an alert dialog
AlertDialog alert = alertDialogBuilder.create();
alert.show();
}
public void goCall(final String phoneNum) {
startActivity(new Intent(Intent.ACTION_DIAL, Uri.fromParts("tel", phoneNum, null)));
}
public void goWeb(String orgWeb) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(orgWeb)));
}
public void goCloseBusinessCard(View v) {
finish();
startActivity(new Intent(this, DirectoryActivity.class));
}
public void goMap() {
/*
int locationAddressLatInt = Integer.parseInt(locationAddressLat);
int locationAddressLongInt = Integer.parseInt(locationAddressLong);
*/
// pass id to map view. only one item in array for ease of use in MapActivity
arrlstID.add(selectedOrg);
arrID = new String[arrlstID.size()];
arrlstID.toArray(arrID);
Bundle extras = new Bundle();
extras.putStringArray("arrID", arrID);
Intent Map = new Intent(BusinessCardActivity.this, MapActivity.class);
Map.putExtras(extras);
startActivity(Map);
}
// ASYNC TASK
class FetchOrg extends AsyncTask<String, Void, String[]> {
#Override
protected String[] doInBackground(String... params) {
HttpURLConnection con = null;
String[] org_data = null;
try {
Log.e(TAG, "FetchOrg doInBackground started");
// assign passed string from main thread
String org_name = params[0];
String orgbyname = URL_GET_ORG_BY_NAME + "?org_name=" + org_name;
URL url = new URL(orgbyname);
con = (HttpURLConnection) url.openConnection();
Log.e(TAG, "FetchOrg doInBackground Connected!");
//Check the response code of the server -
Integer replyCode = con.getResponseCode();
logMess += " Reply Code: " + replyCode.toString();
responseStream = new BufferedInputStream(con.getInputStream());
BufferedReader responseStreamReader = new BufferedReader(new InputStreamReader(responseStream));
stopTime = System.currentTimeMillis();
elapsedTime = stopTime - startTime;
logMess += " elapsed Time : " + elapsedTime + " ms";
Log.e(TAG, "FetchOrg logMess: --- " + logMess);
String line = "";
StringBuilder stringBuilder = new StringBuilder();
//Make sure you get everything!
while ((line = responseStreamReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
//this will close underlying streams
responseStreamReader.close();
String data = stringBuilder.toString();
Log.e(TAG, "FetchOrg Data: --- " + data);
/*
This JSON section contains a JSON Object that holds a JSON Array. The Array is created to
individualize each object within the JSON Array. Then, each JSON object is fetched and
assigned to a string variable.
*/
JSONObject obj = new JSONObject(data); // creates object from json response in data string
JSONObject orgs = obj.getJSONObject("orgs"); // creates array for parsing of json data
String nA = "not available";
// get items from JSONArray and assign for passing to onProgressUpdate
String Org = orgs.optString("org_name", nA);
String FirstName = orgs.optString("contact_first_name", nA);
String LastName = orgs.optString("contact_last_name", nA);
String Email = orgs.optString("contact_email", nA);
String Phone = orgs.optString("contact_phone", nA);
String Website = orgs.optString("org_website", nA);
String ServiceType = orgs.optString("org_type", nA);
String ServicesProvided = orgs.optString("org_services", nA);
String Address = orgs.optString("org_street_address", nA);
String City = orgs.optString("org_city", nA);
String State = orgs.optString("org_state", nA);
String Zip = orgs.optString("org_zip", nA);
String Lat = orgs.optString("latitude", nA);
String Long = orgs.optString("longitude", nA);
// Add items to string array
org_data = new String[14]; // 14 is length of array, not the count
org_data[0] = Org;
org_data[1] = FirstName;
org_data[2] = LastName;
org_data[3] = Email;
org_data[4] = Phone;
org_data[5] = Website;
org_data[6] = ServiceType;
org_data[7] = ServicesProvided;
org_data[8] = Address;
org_data[9] = City;
org_data[10] = State;
org_data[11] = Zip;
org_data[12] = Lat;
org_data[13] = Long;
} catch (Exception ex) {
Log.e(TAG, "FetchOrg doInBackground: " + ex.getMessage());
}
finally{
//just in case you get an error above
if(con != null){
con.disconnect();
}
}
return org_data;
}
#Override
protected void onPostExecute(String[] result) {
if(result != null){
setTextView(result);
}
else{
Log.e(TAG, "FetchOrg onPostExecute: result is null");
}
}
}
Be aware that I did not clean up things like maintaining minimal scope: For example :public void showEmailDialog() and public void goMap() which do not need to be public methods! Any method that does not need to be accessed outside the class (and that is rare!) should not be made public.
You have also defined many class variables at the beginning of the class like "Favorite, Latitude, Longitude, FavoriteChanged" do they need to have class wide scope?? And they are variables! So in java naming convention, variables and methods are written in lower case, while classes are capitalized--this helps reading code easier (for the SO community!)
When working with Indent extras often mistakes are made when entering the "key" like "selectedOrg". Therefore it is some times an advantage to create a global class to help keep things straight. Example public class GlobalExtras and just keep public static final String SELECTED_ORG = "selectedOrg"; Then just use intent.getString(SELECTED_ORG);
Another thing: I am not a big fan of String[] as you have used to store your "org" strings. They can be tricky with size and indexes. You might want to consider using another object.
I do not have access to your API and your data, so I was only able to make requests on my server trying to duplicate your user scenario, but I was unable to reproduce your issue. I hope this helps, let me know what the logcat spits out!
I have designed an application with a successful login and register system in Android Studio. I am hosting my DB on hosting24.
I need to pull data from the DB and display it onscreen inside the application.
Can anyone suggest how to? I have a heap of code written for this application so any suggestions of what code is needed to see I will post. I am not too sure what code I would need to post here..
Scenario would be if a teacher logs into the application they will see a list of registered students and corresponding data related to those students.
<?php
$con = mysqli_connect("host", "username", "pw", "db");
$FirstName = $_POST["FirstName"];
$LastName = $_POST["LastName"];
$statement = mysqli_prepare($con, "SELECT * FROM Student");
mysqli_stmt_bind_param($statement, "ss",$FirstName, $LastName);
mysqli_stmt_execute($statement);
$response = array();
$response["success"] = false;
while(mysqli_stmt_fetch($statement)){
$response["success"] = true;
$response["FirstName"] = $FirstName;
$response["LastName"] = $LastName;
}
echo json_encode($response);
?>
Here is my java code
public class UserAreaActivity extends AppCompatActivity implements View.OnClickListener{
Button fetch;
TextView text;
EditText et;
HttpURLConnection urlConnection = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_area);
fetch= (Button) findViewById(R.id.fetch); //XML Button to get the data
fetch.setOnClickListener(this);
}
class task extends AsyncTask<String, String, Void>
{
private ProgressDialog progressDialog = new ProgressDialog(UserAreaActivity.this);
InputStream is = null ;
String result = "";
protected void onPreExecute() {
progressDialog.setMessage("Fetching data...");
progressDialog.show();
progressDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface arg0) {
task.this.cancel(true);
}
});
}
#Override
protected Void doInBackground(String... params) {
try {
URL url = new URL("MY PHP URL");
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
is = urlConnection.getInputStream();
} catch (Exception e) {
Log.e("log_tag", "Error in http connection "+e.toString());
}
try {
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = "";
while((line=br.readLine())!=null)
{
sb.append(line+"\n");
}
is.close();
result=sb.toString();
} catch (Exception e) {
// TODO: handle exception
Log.e("log_tag", "Error converting result "+e.toString());
}
return null;
}
protected void onPostExecute(Void v) {
// ambil data dari Json database
try {
JSONArray Jarray = new JSONArray(result);
for(int i=0;i<Jarray.length();i++)
{
JSONObject Jasonobject = null;
Jasonobject = Jarray.getJSONObject(i);
//get an output on the screen
String firstName = Jasonobject.getString("FirstName");
String db_detail="";
if(et.getText().toString().equalsIgnoreCase(firstName)) {
db_detail = Jasonobject.getString("detail");
text.setText(db_detail);
break;
}
}
this.progressDialog.dismiss();
} catch (Exception e) {
// TODO: handle exception
Log.e("log_tag", "Error parsing data "+e.toString());
}
}
}
Result in this is it hangs on fetching data for me. I just need a list of names to print to screen
First you will need to create a server side file which can fetch the data from database and post it as JSON (or other format if you prefer)
<?php
// Code to connect to database
// fetch and process the data
// print json echo json_encode($output)
?>
Suppose the above php file is at http://example.com/process.php
In Android you need to make an asynchronous HTTP request to the JSON API you created earlier (at http://example.com/process.php). One way is to use an AsyncHttpClient to fetch data
public void loadFromWeb(){
RequestParams params = new RequestParams();
AsyncHttpClient client = new AsyncHttpClient();
params.put("parameter", data);
client.post("http://example.com/process.php", params, new JsonHttpResponseHandler() {
#Override
public void onStart() {
}
#Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
try {
//process the response
//Do what you want with data, display in your layout
} catch (Exception e) {
//catch exception
}
}
#Override
public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
// Process failure
}
});
}
You might want to read more about AsyncHttpClient for this.
Or you can have a look at other ways to make asynchronous calls, one such library is RetroFit
I have an HTTP GET that is receiving information from a URI. The URI is for Google Shopping.
https://www.googleapis.com/shopping/search/v1/public/products?key=key&country=US&q=digital+camera&alt=atom
(Left my key out).
Is there a way that I can change it from
q=digital+camera
to anything a user puts in an EditText?
So basically, I want the EditText to change what is searched on Google Shopping.
First screen, ProductSearchEntry with EditText for search query:
Code for ProductSearchEntry
public class ProductSearchEntry extends Activity{
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.productsearchentry);
Button search = (Button) findViewById(R.id.searchButton);
search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent searchIntent = new Intent(getApplicationContext(), ProductSearch.class);
startActivity(searchIntent);
}
});
}
}
Then, I have a second class, ProductSearch, with no picture, but just this code:
public class ProductSearch extends Activity{
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.productsearchresults);
EditText searchQuery = (EditText) findViewById(R.id.searchQuery);
ProductSearchMethod test = new ProductSearchMethod();
String entry;
TextView httpStuff = (TextView) findViewById(R.id.httpTextView);
try {
entry = test.getSearchData(searchQuery.getText().toString());
httpStuff.setText(entry);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Which references the ProductSearchMethod class which consists of a TextView that is changed to the code recieved in the HTTP GET:
Code:
public class ProductSearchMethod {
public String getSearchData(String query) throws Exception{
BufferedReader in = null;
String data = null;
try{
HttpClient client = new DefaultHttpClient();
URI site = new URI("https://www.googleapis.com/shopping/search/v1/public/products?key=key&country=US&q="+query.replace(" ","+")+"&alt=atom");
HttpGet request = new HttpGet();
request.setURI(site);
HttpResponse response = client.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String l = "";
String nl = System.getProperty("line.seperator");
while((l = in.readLine()) !=null){
sb.append(l + nl);
}
in.close();
data = sb.toString();
return data;
}finally{
if (in != null){
try{
in.close();
return data;
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
ProductSearchMethod comes up great, but it doesn't change the text from "Loading Items" to the website code. I had it working before but then I tried to edit what it searched (all this ^) and now it doesn't change.
Make changes in your code like
public class ProductSearchEntry extends Activity{
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.productsearchentry);
EditText etSearch = (EditText) findViewById(id of your edittext);
Button search = (Button) findViewById(R.id.searchButton);
search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//while calling intent
Intent searchIntent = new Intent(getApplicationContext(), ProductSearch.class);
searchIntent.putExtra("searchText",etSearch.getText().toString());
startActivity(searchIntent);
}
});
}
}
and another activity like this,
public class ProductSearch extends Activity{
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.productsearchresults);
String searchQuery = getIntent().getStringExtra("searchText");
ProductSearchMethod test = new ProductSearchMethod();
String entry;
TextView httpStuff = (TextView) findViewById(R.id.httpTextView);
try {
entry = test.getSearchData(searchQuery);
httpStuff.setText(entry);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Yeah... Change your getSearchData() method to include a string as a parameter
public String getSearchData(String query) throws Exception{
Then, insert that string into the query URL, replacing spaces with "+". You may want to do further conditioning to the string, for instance URL encoding it.
URI site = new URI("https://www.googleapis.com/shopping/search/v1/public/products?key=key&country=US&q="+query.replace(" ","+")+"&alt=atom");
In your XML, create a button that contains the following line:
android:onClick="search"
In your ProductSearch activity, add the following method, and move the code in onCreate into it. You will also need to create an EditText in your XML for input.
public void search(View v)
{
EditText searchQuery = (EditText) findViewById(R.id.searchQuery);
ProductSearchMethod test = new ProductSearchMethod();
String returned;
try {
returned = test.getSearchData(searchQuery.getText().toString());
httpStuff.setText(returned);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Finally, you will probably want to read up on running asynchronous tasks so that the query won't freeze your app while performing.
May be I got you wrong, but why don't you just pass it as a parameter in
getSearchData() => getSearchData(string query)
Then you can change the line
URI site = new URI("https://www.googleapis.com/shopping/search/v1/public/products?key=key&country=US&q=digital+camera&alt=atom");
to
URI site = new URI("https://www.googleapis.com/shopping/search/v1/public/products?key=key&country=US&q=+ URLEncoder.encode(query, "UTF-8")+&alt=atom");
Check out http://androidforums.com/developer-101/528924-arduino-android-internet-garage-door-works-but-could-use-input.html I use Asynctask to trigger a get command on a local Arduino server. It appends the Arduino's pin number and, depending on if it's needed, a port number to the end of the URL. I'm sure you could use it to help you out.