How to access response value outside onResponse method in android - java

I am working on a android project. I got the response from google api and parsed the json. But i want to return the value outside of onResponse method which seems to be impossible for me now. Below is my code, I have already seen this answer here. But i want this value outside of this async method. Is it possible to access this value.
UPDATE - I have updated my code for more details. This is my full activity class. You can see what i want to achieve. Please help me how i can access value returned by Volley onResponse in method get_time_to_travel, inside method parseJson. This is really killing me now. My first android project and i am stuck here from last two days.
Any help on this would be appreciated.
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private LinearLayoutManager linearLayoutManager;
private CustomAdapter adapter;
private List<UserData> userData;
private LocationManager locationManager;
private LocationListener locationListener;
String origin, mode = "driving";
private String API = "APIKey";
TextView textView;
RequestQueue requestQueue;
RequestQueue requestQueue1;
String url = "https://url/users";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
recyclerView.setHasFixedSize(true);
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
double lat = location.getLatitude();
double lng = location.getLongitude();
origin = String.valueOf(lat)+","+String.valueOf(lng);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.INTERNET
}, 10);
}
return;
}
else{
locationManager.requestLocationUpdates("gps", 5000, 0, locationListener);
}
getData();
linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
adapter = new CustomAdapter(this, userData);
recyclerView.setAdapter(adapter);
}
private void getData(){
userData = new ArrayList<>();
requestQueue = Volley.newRequestQueue(this);
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(url,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
parseJson(response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("VOLLEY", "ERROR");
}
}
);
requestQueue.add(jsonArrayRequest);
}
private void parseJson(JSONArray response){
try {
for (int i = 0; i < response.length(); i++) {
JSONObject users = response.getJSONObject(i);
String id = ("id: "+users.getString("id"));
String name = ("Name: "+users.getString("name"));
String username = ("Username: "+users.getString("username"));
String email = ("Email: "+users.getString("email"));
String address = parseAddress(users);
String destination = parseCoordinates(users);
String company = parseCompany(users);
String phone = ("Phone: "+users.getString("phone"));
String website = ("Website: "+users.getString("website"));
String eta = get_time_to_travel(origin, destination, API, mode);
UserData udata = new UserData(id, name, username, email, address, phone, website, company,eta);
userData.add(udata);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
private String parseAddress(JSONObject users) {
JSONObject completeAdd = null;
String address = null;
try {
completeAdd = users.getJSONObject("address");
String street = completeAdd.getString("street");
String suite = completeAdd.getString("suite");
String city = completeAdd.getString("city");
String zipcode = completeAdd.getString("zipcode");
address = ("Address :" + street + ", " + suite + ", " + city + ", " + zipcode);
} catch (JSONException e) {
e.printStackTrace();
}
return address;
}
private String parseCoordinates(JSONObject users) {
JSONObject completeAdd = null;
String destination = null;
try {
completeAdd = users.getJSONObject("address");
JSONObject coordinates = completeAdd.getJSONObject("geo");
String latitude = coordinates.getString("lat");
String longitude = coordinates.getString("lng");
destination = latitude + "," + longitude;
} catch (JSONException e) {
e.printStackTrace();
}
return destination;
}
private String parseCompany(JSONObject users) {
JSONObject companyDetail = null;
String company = null;
try {
companyDetail = users.getJSONObject("company");
String company_name = companyDetail.getString("name");
String catchPhrase = companyDetail.getString("catchPhrase");
String bs = companyDetail.getString("bs");
company = ("Company: " + company_name + ", " + catchPhrase + ", " + bs);
} catch (JSONException e) {
e.printStackTrace();
}
return company;
}
private String get_time_to_travel(String origin, String destination, String API, String mode){
requestQueue1 = Volley.newRequestQueue(this);
String eta = null;
String google_api = "https://maps.googleapis.com/maps/api/distancematrix/json?origins="+origin+"&destinations="
+destination+"s&mode="+mode+"&language=fr-FR&key="+API;
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, google_api, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
eta = parseGoogleData(response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("VOLLEY", "ERROR");
}
}
);
requestQueue1.add(jsonObjectRequest);
return eta;
}
private String parseGoogleData(JSONObject response) {
String estimated_time_arrival = null;
try {
JSONArray rows = response.getJSONArray("rows");
JSONObject elements = rows.getJSONObject(0);
JSONArray elementsArr = elements.getJSONArray("elements");
JSONObject durationObj = elementsArr.getJSONObject(0);
JSONObject durationData = durationObj.getJSONObject("duration");
estimated_time_arrival = durationData.getString("text");
} catch (JSONException e) {
e.printStackTrace();
}
return estimated_time_arrival;
}
}

Async task is doing work on other thread. So if you want to access any variable out side that method, you need to wait until the task get completed. Otherwise the variable will be null.
eg: on on response method
#Override
public void onResponse(String response) {
res=response;
anyMethodtopassVar(DataType data);
}

in OnCreate() of activity, remove these 2 lines
adapter = new CustomAdapter(this, userData);
recyclerView.setAdapter(adapter);
in getData() remove this line
userData = new ArrayList<>();
put them in parseJson() as below:
private void parseJson(JSONArray response){
try {
if(userData==null){
userData = new ArrayList<>();
}else{
userData.clear();
}
for (int i = 0; i < response.length(); i++) {
JSONObject users = response.getJSONObject(i);
String id = ("id: "+users.getString("id"));
String name = ("Name: "+users.getString("name"));
String username = ("Username: "+users.getString("username"));
String email = ("Email: "+users.getString("email"));
String address = parseAddress(users);
String destination = parseCoordinates(users);
String company = parseCompany(users);
String phone = ("Phone: "+users.getString("phone"));
String website = ("Website: "+users.getString("website"));
String eta = get_time_to_travel(origin, destination, API, mode);
UserData udata = new UserData(id, name, username, email, address, phone, website, company,eta);
userData.add(udata);
}
if(adapter == null){
adapter = new CustomAdapter(this, userData);
recyclerView.setAdapter(adapter);
}else{
adapter.notifyDataSetChanged();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
this way, when json call finish, parseJson() is called.
and after parsing the array into userData the adapter is initialized or notified.
EDIT:
Well, this is not the best sol. but it's just something from the top of my head
little nasty/dirty. i don't know but i think it will do the job
1- you don't have to reinit the queue every time, so in get_time_to_travel() put that line out of the method:
requestQueue1 = Volley.newRequestQueue(this);
add final int index param to the method and make it void:
private void get_time_to_travel(String origin, String destination, String API, String mode, final int index){...
make onResponse() in the method like this:
public void onResponse(JSONObject response) {
eta = parseGoogleData(response);
userData.get(index).setEta(eta);//add this setter to your data object if not exist.
}
remove return eta;
init udata with empty string as eta for now:
UserData udata = new UserData(id, name, username, email, address, phone, website, company,"");
userData.add(udata);
modify the call to get_time_to_travel() in parseJson() as below:
get_time_to_travel(origin, destination, API, mode, i);
when get_time_to_travel() is called at onResponse() the object will be modified to hold the eta value retrieved from the API
this is nasty, sometimes the adapter might be notified before all calls to google api is completed. so this is just to show you how to make it
Edit2
a workaround for this is
init userData object with label "Loading..." for eta
UserData udata = new UserData(id, name, username, email, address, phone, website, company,"Loading...");
and notify the adapter at end of onResponse() of get_time_to_travel():
public void onResponse(JSONObject response) {
eta = parseGoogleData(response);
userData.get(index).setEta(eta);//add this setter to your data object if not exist.
adapter.notifyDataSetChanged();
}

Do you want to get the result of parseJson inside onResponse?
Change the return type of parseJson to UserData, call return userDate; inside try block and return null; in catch block. This will help you catch the result of parseJson from where you are calling it.
Let me know if I did not understand your question properly.

public void getString(final VolleyCallback callback) {
StringRequest req = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
res=response;
callback.onSuccess(res);
}
}...
}}
public interface VolleyCallback{
void onSuccess(String result);
}
Now inside your mainactivity you can do like this.
public void onResume(){
super.onResume();
getString(new VolleyCallback(){
#Override
public void onSuccess(String res){
... //do something
}
});
}

Related

Do multiple requests in the same session from different Activities

I've recently tried to develop a servlet and then connect it to my android app but I can't get it to work properly.
This is my login servlet
#WebServlet(name = "login", value = "/auth/login")
public class AuthUser extends HttpServlet {
private Gson gson = new Gson();
public void init() {
Dao.registerDriver();
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
String id = request.getParameter("id");
String psw = request.getParameter("psw");
HttpSession s = request.getSession();
PrintWriter out = response.getWriter();
HashMap<String, Object> responseJson = new HashMap<>();
Student student;
if(id != null && psw != null) {
student = FetchFromDB.fetchStudentData(id);
if (student != null && student.getPassword().equals(psw)) {
s.setAttribute("username", student.getNumber());
s.setAttribute("surname", student.getSurname());
s.setAttribute("role", student.getRole());
responseJson.put("id", request.getSession().getId());
responseJson.put("user", student);
responseJson.put("message", "Logged succesfully");
out.print(new Gson().toJson(responseJson));
} else {
responseJson.put("message", "The mail or the username is not correct, please try again");
out.println(new Gson().toJson(responseJson));
}
} else {
responseJson.put("message", "The mail or username value is null, check that out");
}
out.flush();
}
public void destroy() {
}
}
I call this servlet from my login page in my android app as follow:
private void login() throws MalformedURLException {
RequestQueue queue = Volley.newRequestQueue(this);
String username = usernameText.getText().toString();
String psw = passwordText.getText().toString();
String url = Costants.URL + "auth/login?id="+username+"&psw="+psw+"";
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
url,
null,
response -> {
Log.d("In onResponse", ""+response);
try {
Log.d("In callServer", "Object returned: " +response.toString());
intent.putExtra("key-username", usernameText.getText().toString());
intent.putExtra("key-role", response.getJSONObject("user").getString("role"));
intent.putExtra("key-surname", response.getJSONObject("user").getString("surname"));
intent.putExtra("key-session-id", response.getString("id"));
startActivity(intent);
} catch (JSONException e) {
e.printStackTrace();
}
}, error -> {
VolleyLog.d("In onErrorResponse", "Error: " + error.getMessage());
Toast.makeText(getApplicationContext(),
error.getMessage(), Toast.LENGTH_SHORT).show();
});
// Access the RequestQueue through your singleton class.
MySingleton.getInstance(getApplicationContext()).addToRequestQueue(jsonObjReq);
}
When I click in the login button it works, so it communicates with the servlet and the main activity starts as it should do.
BUT when I try to make another call from my MainActivity the session in the servlet won't be recognised and so the user appears as unkown, here's the code of the mainActivity.
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
String usernameOfLoggedUser;
String surnameOfLoggedUser;
String roleOfLoggedUser;
String sessionId;
Bundle extras;
private UserViewModel viewModel;
private BookedLessonsViewModel bookedLessonsViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
extras = getIntent().getExtras();
usernameOfLoggedUser = extras.getString("key-username", "NoValue");
surnameOfLoggedUser = extras.getString("key-surname", "NoValue");
roleOfLoggedUser = extras.getString("key-role", "NoValue");
sessionId = extras.getString("key-session-id", "NoValue");
showWelcomeToast(usernameOfLoggedUser);
setViewModelUser(usernameOfLoggedUser, roleOfLoggedUser, surnameOfLoggedUser);
fetchBookedLessons(usernameOfLoggedUser);
setupUIElements();
}
/**
* Fetch lessons from db and set the model view for the lessons booked
* #param username
*/
private void fetchBookedLessons(String username) {
String url = Costants.URL + "book/bookedLessonsForUser";
ArrayList<BookedLesson> bookedLessons = new ArrayList<>();
CustomRequest jsonCustomReq = new CustomRequest(
Request.Method.GET,
url,
null,
sessionId,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d("in onResponse", response.toString());
// int i = 0;
// try {
// JSONArray reservations = response.getJSONArray("reservations");
// while(i < reservations.length()) {
// JSONObject reservation = reservations.getJSONObject(i);
// String idUser = reservation.getString("idUser");
// String idTeacher = reservation.getString("idTeacher");
// String subject = reservation.getString("nameSubject");
// String day = reservation.getString("day");
// String slot = reservation.getString("slot");
// String status =reservation.getString("status");
//
// BookedLesson bookedLesson = new BookedLesson(idUser, idTeacher, slot, subject, day, status);
// bookedLessons.add(bookedLesson);
// i++;
// }
// } catch (JSONException e) {
// e.printStackTrace();
// } finally {
// setViewModelLessons(bookedLessons);
// }
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}
);
MySingleton.getInstance(getApplicationContext()).addToRequestQueue(jsonCustomReq);
}
private void showWelcomeToast(String username) {
Toast toast = Toast.makeText(getApplicationContext(), "You are logged as: " + username, Toast.LENGTH_SHORT*2);
toast.show();
}
#Override
protected void onResume() {
super.onResume();
fetchBookedLessons(usernameOfLoggedUser);
}
private void setupUIElements() {
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_main);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(binding.navView, navController);
}
/**
* Set the model view for the user so that every fragment has the data for the logged user
* #param usernameOfLoggedUser
* #param roleOfLoggedUser
* #param surnameOfLoggedUser
*/
private void setViewModelUser(String usernameOfLoggedUser, String roleOfLoggedUser, String surnameOfLoggedUser) {
viewModel = new ViewModelProvider(this).get(UserViewModel.class);
viewModel.setUser(usernameOfLoggedUser);
viewModel.setRole(roleOfLoggedUser);
viewModel.setSurname(surnameOfLoggedUser);
viewModel.getUser().observe(this, username -> {
Log.d("In onCreate", "Share data: " + username);
});
}
/**
* Pass the array fetched and set the model view for the lessons
* #param lessons
*/
private void setViewModelLessons(ArrayList<BookedLesson> lessons) {
bookedLessonsViewModel = new ViewModelProvider(this).get(BookedLessonsViewModel.class);
bookedLessonsViewModel.setBookedLessons(lessons);
bookedLessonsViewModel.getBookedLessons().observe(this, bookedLessons -> {
Log.d("In getBookedLessons", "Lessons: " + bookedLessons.size());
});
}
}
But I get this value in return:
-26 13:48:47.053 12225-12225/com.example.bookinglessons D/inĀ onResponse: {"message":"you're not logged"}
If you know what's going on it would be really helpful, thanks in advance.
I found the solution for this kind of problems.
You just need to add these lines in the onCreate of your first Activity (MainActivity in my case).
CookieManager cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);
This solved my problems and mantained the session.

How can i make an Arraylist of Objects from response received with volley

I am trying to make an ArrayList of objects .But the logd at the last is always showing an empty ArrayList.How can I do it.With the present code I tried few things but they didn't work.I guess i have to return the ArrayList but I am confused.
This is my code in MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<News> newsArrayList = new ArrayList<>();
RequestQueue requestQueue = Volley.newRequestQueue(this);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, mURL, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray articles = response.getJSONArray("articles");
for (int i = 0; i < 10; i++) {
JSONObject news = articles.getJSONObject(i);
title = news.getString("title");
img_url = news.getString("image");
desc = news.getString("description");
news_url = news.getString("url");
newsArrayList.add(new News(title, img_url, desc, news_url));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "onErrorResponse: Something went Wrong");
}
});
requestQueue.add(jsonObjectRequest);
Log.d(TAG, "onCreate: " + newsArrayList);
This is News.java
public class News {
private String mTitle;
private String mImg_url;
private String mNews_url;
private String mDesc;
public News(String title, String img_url, String desc, String news_url) {
this.mTitle = title;
this.mImg_url = img_url;
this.mDesc = desc;
this.mNews_url = news_url;
}
public String getmTitle() {
return mTitle;
}
public String getmImg_url() {
return mImg_url;
}
public String getmNews_url() {
return mNews_url;
}
public String getmDesc() {
return mDesc;
}
}

GetterAndSetter returns empty ArrayList

I am adding String returned by Callback method from Volley's onRespond method.
I have already initialized GetterAndSetter Method inside OnCreate Method.
this is my code:
onRespond(){
...
AddtoList(CreateURL, new VolleyCallback() {
#Override
public void onSuccess(String result) {
getterAndSetter.addString(result);
}
});
....
}
My GetterAndSetter Class:
public class GetterAndSetter {
ArrayList<String> strings = new ArrayList<>();
public void addString(String string) {
this.strings.add(string);
}
public ArrayList<String> getList(){
return this.strings;
}
}
I tries to get all the strings added inside of this getterandsetter's ArrayList via following code inside my another method :
void LoadImages(MainActivity mainActivity){
...
List<String> details = getterAndSetter.getList();
Log.d("gs", getterAndSetter.getList().toString());
...
}
As seen above, I tried to print log, but it print "[]"(Empty String). I have seen alot of Answers on Stackoverflow, but can't solve my problem.
Update : I am adding more code so that you guys can understand the problem.
My OnCreate Method :
#Override
protected void onCreate(Bundle savedInstanceState) {
...
getterAndSetter = new GetterAndSetter();
LoadImages(this);
}
LoadImages :
private void LoadImages(MainActivity mainActivity) {
StringRequest stringRequest = new StringRequest(URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
mView.dismiss();
Log.d("Respone", "onResponse: " + response);
// Used to Get List of Images URLs
getResponse = ParseJSON(response);
List<String> urlList = getResponse.get(0);
List<String> titles = getResponse.get(1);
List<String> details = getterAndSetter.getList();
Log.d("gs", getterAndSetter.getList().toString());
for (String urls : urlList) {
Log.d("urls", urls);
}
for (String title : titles) {
Log.d("tts", title);
}
for (String dt : details) {
Log.d("dts", dt);
}
}
}, error -> {
Log.d(TAG, "onErrorResponse: Error Occured...");
});
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(stringRequest);
}
ParseJSON method :
ArrayList<ArrayList<String>> ParseJSON(String URL) {
try {
JSONObject root = new JSONObject(URL);
JSONObject photos = root.getJSONObject("photos");
JSONArray photo = photos.getJSONArray("photo");
ArrayList<String> listURLS = new ArrayList<>();
ArrayList<String> Titles = new ArrayList<>();
ArrayList<ArrayList<String>> result = new ArrayList<>();
for (int i = 0; i < photo.length(); i++) {
JSONObject photosJSONObject = photo.getJSONObject(i);
String FarmID = photosJSONObject.getString("farm");
String ServerID = photosJSONObject.getString("server");
String ID = photosJSONObject.getString("id");
String SecretID = photosJSONObject.getString("secret");
String ImageTitle = photosJSONObject.getString("title");
listURLS.add(i, CreatePhotoURL(FarmID, ServerID, ID, SecretID));
Titles.add(i, ImageTitle);
String CreateURL = "https://api.flickr.com/services/rest/?method=flickr.photos.getInfo&api_key=" + API_Key + "&photo_id=" + ID + "&format=json&nojsoncallback=1";
AddtoList(CreateURL, new VolleyCallback() {
#Override
public void onSuccess(String result) {
getterAndSetter.addString(result);
}
});
result.add(listURLS);
result.add(Titles);
}
return result;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
AddtoList Method :
public void AddtoList(String CreateURL, VolleyCallback volleyCallback) {
RequestQueue requestQueue = Volley.newRequestQueue(this);
StringRequest stringRequest = new StringRequest(CreateURL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
JSONObject root;
try {
root = new JSONObject(response);
JSONObject photo = root.getJSONObject("photo");
String username = photo.getJSONObject("owner").getString("username");
String DateTaken = photo.getJSONObject("dates").getString("taken");
String Views = photo.getString("views");
String str = "Date Taken : " + DateTaken + "\n" + "Views : " + Views + "\n" + "User Name : " + username + "\n";
volleyCallback.onSuccess(str);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "onErrorResponse: " + error.toString());
}
});
requestQueue.add(stringRequest);
}
My CallBack
public interface VolleyCallback {
void onSuccess(String result);
}
The problem is that you're trying to print the list BEFORE the callback is being invoked by Volley.
You parse a Json and for each element, you make a new request. After parsing the Json you print the list, it's empty because of the calls you make aren't ended at the moment you print the list.
You need to wait until all the request you start from inside the loop have ended.

HttpURLConnection won't work after pausing on activity

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!

How can I display information from an API that requires two URLs?

The first URL returns a list of names and IDs of farmers markets:
https://search.ams.usda.gov/farmersmarkets/v1/data.svc/locSearch?lat=" + latitude + "&lng=" + longitude
Then, the ID from the above URL must be used to get further information from each farmers market:
"https://search.ams.usda.gov/farmersmarkets/v1/data.svc/mktDetail?id=" + id
I want to display the name of the farmers markets from the first URL, and then the address of each farmers market from the second URL. How can I do this so that it all proceeds in the correct order?
Here is my MainActivity:
public class MainActivity extends AppCompatActivity {
public static final String TAG = MainActivity.class.getSimpleName();
private ListView mListView;
GPSTracker gps;
Context mContext;
String marketAddress;
ArrayList<String> marketAddressArrayList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
mListView = (ListView) findViewById(R.id.list_view);
double latitude = 45.496481;
double longitude = -122.573462;
gps = new GPSTracker(mContext, MainActivity.this);
if (gps.canGetLocation()) {
latitude = gps.getLatitude();
longitude = gps.getLongitude();
}
else {
gps.showSettingsAlert();
}
final String marketUrl = "https://search.ams.usda.gov/farmersmarkets/v1/data.svc/locSearch?lat=" + latitude + "&lng=" + longitude;
Log.d(TAG, String.valueOf(latitude));
Log.d(TAG, String.valueOf(longitude));
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(marketUrl)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
e.printStackTrace();
Log.d(TAG, "failure");
}
#Override
public void onResponse(Response response) throws IOException {
try {
final String jsonData = response.body().string();
Log.v(TAG, "THIS IS MY JSONDATA " + jsonData);
if (response.isSuccessful()) {
Log.d(TAG, marketUrl);
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
getCurrentDetails(jsonData);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
Log.v(TAG, jsonData);
}
}
catch (IOException e) {
Log.e(TAG, "Exception caught: ", e);
}
}
});
Log.d(TAG, "Main UI code is running!");
}
private void getCurrentDetails(String jsonData) throws JSONException {
JSONObject usdaJSON = new JSONObject(jsonData);
JSONArray resultsJSON = usdaJSON.getJSONArray("results");
Market[] markets = new Market[resultsJSON.length()];
for(int i = 0; i < resultsJSON.length(); i++){
final JSONObject marketJSON = resultsJSON.getJSONObject(i);
String marketname = marketJSON.getString("marketname");
String id = marketJSON.getString("id");
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://search.ams.usda.gov/farmersmarkets/v1/data.svc/mktDetail?id=" + id)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
e.printStackTrace();
Log.d(TAG, "failure");
}
#Override
public void onResponse(Response response) throws IOException {
try {
final String marketDetailsJsonData = response.body().string();
Log.v(TAG, "THIS IS MY JSONDATA " + marketDetailsJsonData);
if (response.isSuccessful()) {
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
JSONObject detailsJSON = new JSONObject(marketDetailsJsonData);
JSONObject marketDetailsJSON = detailsJSON.getJSONObject("marketdetails");
marketAddress = marketDetailsJSON.getString("Address");
marketAddressArrayList.add(marketAddress);
//marketAddressArrayList.get(0);
//updateMarketAddress(); call this method for each market found - it will run 20 times if there are 20 markets
Log.d(TAG, "this is marketadress"+ marketAddress);
} catch (JSONException e) {
e.printStackTrace();
Log.d(TAG, "broken");
}
}
});
}
}
catch (IOException e) {
Log.e(TAG, "Exception caught: ", e);
}
}
});
Log.d(TAG, "outside of the loop"+ marketname);
Market market = new Market(marketname, id, marketAddress);
markets[i] = market;
//markets[i].setAddress(marketAddressArrayList.get(i));
}
MarketAdapter adapter = new MarketAdapter(this, markets);
mListView.setAdapter(adapter);
for(int i = 0; i < resultsJSON.length(); i++) {
Log.d(TAG, markets[i].getMarketname());
Log.d(TAG, markets[i].getId());
// Log.d(TAG, markets[i].getMarketAddress());
}
}
}
First, extract out all the JSON parsing (for example, use Retrofit instead of OkHTTP) and UI updating to a separate method.
Then, hit the first URL, from that onResponse, hit the second URL.
Basically, what you are doing now,
if (response.isSuccessful()) {
Log.d(TAG, marketUrl);
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
getCurrentDetails(jsonData); // Call the second URL
But it doesn't need to be on the UI thread if you aren't updating the UI
Your for loop at the end must be within the second onResponse body, where the adapter/list would be populated.
Also, MarketAdapter should probably use List<Market> instead of ArrayList<String>

Categories