So I was trying to retrieve all the posts from the REST API I made to be outputted to a textview in my Posts activity. I can successfully retrieve the JSON Objects and store them in their corresponding ArrayLists. However, whenever I call my ListPosts function from my Posts activity within the AsyncTask's onPostExecute, its saying that my postsSect textview is null.
I am thinking that for some reason the R.id is not getting contacted, even though I declared it in onCreate of my Posts. Because of this I'm getting this error message in my logcat:
01-14 21:43:57.022 16588-16588/com.example.android.androidcraftsappprototype E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.androidcraftsappprototype, PID: 16588
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.Window$Callback android.view.Window.getCallback()' on a null object reference
at android.support.v7.app.AppCompatDelegateImpl.<init>(AppCompatDelegateImpl.java:249)
at android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:182)
at android.support.v7.app.AppCompatActivity.getDelegate(AppCompatActivity.java:520)
at android.support.v7.app.AppCompatActivity.findViewById(AppCompatActivity.java:191)
at com.example.android.androidcraftsappprototype.WSAdapter$SendPostsRequest.onPostExecute(WSAdapter.java:186)
at com.example.android.androidcraftsappprototype.WSAdapter$SendPostsRequest.onPostExecute(WSAdapter.java:104)
at android.os.AsyncTask.finish(AsyncTask.java:695)
at android.os.AsyncTask.-wrap1(Unknown Source:0)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:712)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Posts.java
public class Posts extends AppCompatActivity {
TextView postsSect;
Button postsDoneBtn;
WSAdapter.SendPostsRequest PostsHelper;
StringBuilder postsBuffer = new StringBuilder();
#Override
protected void onResume(){
super.onResume();
PostsDetails postDetailsHelper = new PostsDetails();
//postDetailsHelper.ListPosts();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_posts);
postsDoneBtn = (Button) findViewById(R.id.PostsDoneButton);
postsSect = (TextView) findViewById(R.id.PostsSection);
PostsDetails postDetailsHelper = new PostsDetails();
postDetailsHelper.callPostDetails("http://192.168.0.18:8000/api/");
//postDetailsHelper.ListPosts();
postsDoneBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(Posts.this, MainActivity.class));
}
});
}
public class PostsDetails {
//String post_title, post_content;
ArrayList<Integer> post_id = new ArrayList<Integer>();
ArrayList<String> post_title = new ArrayList<String>();
ArrayList<String> post_content = new ArrayList<String>();
boolean isPDCalled;
// sets if Post details are called
// checks if postsDetails functions are called for AsyncTask
boolean getIsPDCalled(){
return isPDCalled;
}
// calls the execute for AsyncTask
private void callPostDetails(String theurl){
PostsHelper = new WSAdapter().new SendPostsRequest();
// executes AsyncTask
PostsHelper.execute(theurl);
}
// sets values for the posts arrays
public void setPost(int p_id, String p_title, String p_content) {
this.post_id.add(p_id);
this.post_title.add(p_title);
this.post_content.add(p_content);
}
public ArrayList<Integer> getPostID() {
return this.post_id;
}
public ArrayList<String> getPostTitle() {
return this.post_title;
}
public ArrayList<String> getPostContent() {
return this.post_content;
}
// Lists the posts from the database
public void ListPosts() {
/////////// add functionality if a post was deleted and was clicked
int lastFrJSONArray = getPostID().size() - 1;
postsSect = (TextView) findViewById(R.id.PostsSection);
// outputs the id of the very first post, something to put to the textview
postsSect.setText("id: " + getPostID().get(0) + "\n");
for (int i = lastFrJSONArray; i >= 0; i--)
{
// appending the titles and contents of the current post
postsSect.append("title: " + getPostTitle().get(i) + "\n");
postsSect.append("content: " + getPostContent().get(i) + "\n");
// if this is the last post, then don't need to append id for the next post.
if (i != 0) {
postsSect.append("id: " + getPostID().get(i) + "\n");
}
}
}
}
}
WSAdapter.java
public class WSAdapter {
/*#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}*/
public class SendPostsRequest extends AsyncTask<String, String, String> {
TextView postsSect;
// Add a pre-execute thing
HttpURLConnection urlConnection;
private WeakReference<Activity> mPostReference;
/*public SendPostsRequest(Activity activity){
mPostReference = new WeakReference<Activity>(activity);
}*/
#Override
protected String doInBackground(String... params) {
StringBuilder result = new StringBuilder();
try {
urlConnection = (HttpURLConnection) new URL(params[0]).openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}
}catch( Exception e) {
e.printStackTrace();
}
/*finally {
urlConnection.disconnect();
}*/
return result.toString();
}
#Override
protected void onPostExecute(String result) {
// expecting a response code fro my server upon receiving the POST data
Log.e("TAG", result);
Posts.PostsDetails postsHelper = new Posts().new PostsDetails();
// For posts
try {
JSONArray pJObjArray = new JSONArray(result);
// algorithm for parsing the JSONArray from the Django REST API
for (int i = 0; i < pJObjArray.length(); i++) {
// puts the current iterated JSON object from the array to another temporary object
JSONObject pJObj_data = pJObjArray.getJSONObject(i);
// inputs necesarry elements to the ListPosts function
postsHelper.setPost(pJObj_data.getInt("id"), pJObj_data.getString("post_title"), pJObj_data.getString("post_content"));
}
} catch (JSONException e) {
//Toast.makeText(JSonActivity.this, e.toString(), Toast.LENGTH_LONG).show();
Log.d("Json","Exception = "+e.toString());
}
postsHelper.ListPosts();
}
}
}
First of all restructure your code. And for setting text make those fields static which you want to use and then set their values in the onPostExecute of AsyncTask or else you can return the jsonstring as it is to your activity and then parse it there and set values for better readability.
Related
So I have been trying to fetch JSON objects in my Django REST Framework API. The algorithm for this called within the onPostExecute of my AsyncTask but it seems that it is not being called as when I debug it doesn't go there. Nothing fatal seems to be appearing in my logcat except that there is nothing in my array that should contain data from the DRF API.
I have two activities that calls my AsyncTask from my WSAdapter class. One is for logging in and the other is for listing all posts once logged in.
The logging in works just fine but listing the posts doesn't.
My code is below:
Posts.java
public class Posts extends AppCompatActivity {
TextView postsSect;
Button postsDoneBtn;
WSAdapter.SendAPIRequests PostsHelper;
StringBuilder postsBuffer = new StringBuilder();
#Override
protected void onResume(){
super.onResume();
PostsDetails postDetailsHelper = new PostsDetails();
postDetailsHelper.ListPosts();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_posts);
PostsDetails postDetailsHelper = new PostsDetails();
postsDoneBtn = (Button) findViewById(R.id.PostsDoneButton);
postDetailsHelper.callPostDetails("192.168.0.18:8000/api");
postDetailsHelper.ListPosts();
postDetailsHelper.postDetailsCalled('n');
postsDoneBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(Posts.this, MainActivity.class));
}
});
}
public class PostsDetails {
//String post_title, post_content;
ArrayList<Integer> post_id = new ArrayList<Integer>();
ArrayList<String> post_title = new ArrayList<String>();
ArrayList<String> post_content = new ArrayList<String>();
boolean isPDCalled;
// sets if Post details are called
boolean postDetailsCalled(char called) {
if (called == 'y'){
return true;
}
return false;
}
// checks if postsDetails functions are called for AsyncTask
boolean getIsPDCalled(){
return isPDCalled;
}
// calls the execute for AsyncTask
private void callPostDetails(String theurl){
PostsHelper = new WSAdapter.SendAPIRequests();
// sets if post details are called
postDetailsCalled('y');
// executes AsyncTask
PostsHelper.execute(theurl);
}
// sets values for the posts arrays
public void setPost(int p_id, String p_title, String p_content) {
post_id.add(p_id);
post_title.add(p_title);
post_content.add(p_content);
}
// Lists the posts from the database
public void ListPosts() {
/////////// add functionality if a post was deleted and was clicked
postsSect = (TextView) findViewById(R.id.PostsSection);
postsSect.setText(post_title.get(post_title.size()) + "\n");
for (int i = post_id.size() - 1; i > 0; i--)
{
postsSect.append(post_title.get(i));
}
}
}
}
WSAdapter.java
public class WSAdapter extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
static public class SendAPIRequests extends AsyncTask<String, String, String> {
// Add a pre-execute thing
#Override
protected String doInBackground(String... params) {
Log.e("TAG", params[0]);
Log.e("TAG", params[1]);
String data = "";
HttpURLConnection httpURLConnection = null;
try {
// Sets up connection to the URL (params[0] from .execute in "login")
httpURLConnection = (HttpURLConnection) new URL(params[0]).openConnection();
// Sets the request method for the URL
httpURLConnection.setRequestMethod("POST");
// Tells the URL that I am sending a POST request body
httpURLConnection.setDoOutput(true);
// 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("postData=" + params[1]);
// Flushes the postData to the output stream
wr.flush();
wr.close();
// Representing the input stream
InputStream in = httpURLConnection.getInputStream();
// Preparing input stream bytes to be decoded to charset
InputStreamReader inputStreamReader = new InputStreamReader(in);
StringBuilder dataBuffer = new StringBuilder();
// Translates input stream bytes to charset
int inputStreamData = inputStreamReader.read();
while (inputStreamData != -1) {
char current = (char) inputStreamData;
inputStreamData = inputStreamReader.read();
// concatenates data characters from input stream
dataBuffer.append(current);
}
data = dataBuffer.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
// Disconnects socket after using
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
Log.e("TAG", data);
return data;
}
#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);
Posts.PostsDetails postsHelper = new Posts().new PostsDetails();
// For posts
try {
if (postsHelper.getIsPDCalled()){
JSONObject pJObj = new JSONObject(result);
JSONArray pJObjArray = pJObj.getJSONArray("posts");
for (int i = 0; i < pJObjArray.length(); i++) {
JSONObject pJObj_data = pJObjArray.getJSONObject(i);
postsHelper.setPost(pJObj_data.getInt("id"), "post_title", "post_content");
}
}
} catch (JSONException e) {
//Toast.makeText(JSonActivity.this, e.toString(), Toast.LENGTH_LONG).show();
Log.d("Json","Exception = "+e.toString());
}
}
}
}
Login.java
public class Login extends AppCompatActivity {
Button LoginButton;
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);
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/token-auth/";
// If the user is authenticated, then transfer to the MainActivity page
if (APIAuthentication(strUserName, strPassWord, APIUrl)){
startActivity(new Intent(Login.this, Posts.class));
}
}
});
}
private boolean APIAuthentication(String un, String pw, String url){
// when it wasn't static -> AuthHelper = new WSAdapter().new SendAPIRequests();
AuthHelper = new WSAdapter.SendAPIRequests();
JSONObject postData = new JSONObject();
try {
// Attempt to input info to the Django API
postData.put("username", un);
postData.put("password", pw);
// Putting the data to be posted in the Django API
AuthHelper.execute(url, postData.toString());
return true;
} catch (JSONException e) {
e.printStackTrace();
}
return false;
}
}
I was expecting my onPostExecute to be called and store data for my posts arrays.
Okay this is a nice example of async tasks. The problem here is when you call an async task then the code below will continue to execute even when the async task hasn't finished. So what happens in your case:
You fetch the posts and then ask to display them on the exact moment that the async function is still getting the posts. So of course the List is empty.
You can fix this by using the await keyword. This keyword stops the rest of your code from executing until that line has been executed. So change:
postDetailsHelper.callPostDetails("192.168.0.18:8000/api");
to:
await postDetailsHelper.callPostDetails("192.168.0.18:8000/api");
Now the reason that the login does work is because you call that function within the if statement. If you would store the return value of that function in a boolean first then it wouldn't work either.
I am trying to make a translation application from English to Bangla using Yandex API.
It works fine in the emulator but in the real device it shows result for only one word in the text view but when writing a sentence it shows null / nothing.
I think the problem is buffer overflow but don't know how to fix it for the real device. Here are some reference pictures. In the emulator the result works fine:
In the real device it shows empty in text view:
But it works fine when a single word is used in real device.
Here is the code for my Asynctask:
public class
TranslatorBackgroundTask extends AsyncTask<String, Void, String> {
//Declare Context
Context ctx;
//Set Context
TranslatorBackgroundTask(Context ctx){
this.ctx = ctx;
}
String resultString;
#Override
protected String doInBackground(String... params) {
//String variables
String textToBeTranslated = params[0];
String languagePair = params[1];
String jsonString;
try {
//Set up the translation call URL
String yandexKey = "trnsl.1.1.20170823T130435Z.79a583874abfc8ff.61e23593359fdc92452e69a3d5ec05347fc4180b";
String yandexUrl = "https://translate.yandex.net/api/v1.5/tr.json/translate?key=" + yandexKey
+ "&text=" + textToBeTranslated + "&lang=" + languagePair;
URL yandexTranslateURL = new URL(yandexUrl);
//Set Http Conncection, Input Stream, and Buffered Reader
HttpURLConnection httpJsonConnection = (HttpURLConnection) yandexTranslateURL.openConnection();
InputStream inputStream = httpJsonConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
//Set string builder and insert retrieved JSON result into it
StringBuilder jsonStringBuilder = new StringBuilder();
while ((jsonString = bufferedReader.readLine()) != null) {
jsonStringBuilder.append(jsonString + "\n");
}
//Close and disconnect
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
inputStream.close();
httpJsonConnection.disconnect();
//Making result human readable
resultString = jsonStringBuilder.toString().trim();
//Getting the characters between [ and ]
resultString = resultString.substring(resultString.indexOf('[')+1);
resultString = resultString.substring(0,resultString.indexOf("]"));
//Getting the characters between " and "
resultString = resultString.substring(resultString.indexOf("\"")+1);
resultString = resultString.substring(0,resultString.indexOf("\""));
Log.d("Translation Result:", resultString);
return jsonStringBuilder.toString().trim();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
//String text = String.valueOf(resultString);
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String result) {
MainActivity.tvTranslatedText.setText(resultString);
Toast.makeText(ctx, resultString, Toast.LENGTH_LONG).show();
super.onPostExecute(result);
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}
And the code for the main activity:
public class MainActivity extends AppCompatActivity{
Context context=this;
private static final int REQUEST_CODE = 1234;
static TextView tvTranslatedText;
EditText etUserText;
Button buTranslate;
Button buSpeak;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_activity_main);
tvTranslatedText = (TextView)findViewById(R.id.tvTranslatedText);
etUserText = (EditText)findViewById(R.id.etUserText);
buTranslate = (Button)findViewById(R.id.buTranslate);
buSpeak = (Button)findViewById(R.id.buSpeak);
}
public void buTranslate(View view) {
//Default variables for translation
String textToBeTranslated = "";
textToBeTranslated= etUserText.getText().toString();
String languagePair = "en-bn"; //English to bengali ("<source_language>-<target_language>")
//Executing the translation function
Translate(textToBeTranslated,languagePair);
}
//Function for calling executing the Translator Background Task
void Translate(String textToBeTranslated, String languagePair){
TranslatorBackgroundTask translatorBackgroundTask= new TranslatorBackgroundTask(context);
String translationResult = "";
translationResult = String.valueOf(translatorBackgroundTask.execute(textToBeTranslated,languagePair)); // Returns the translated text as a String
Log.d("Translation Result",translationResult); // Logs the result in Android Monitor
}
//Speak button activities
public void buSpeak(View view) {
startVoiceRecognitionActivity();
}
private void startVoiceRecognitionActivity()
{
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Speak to translate");
startActivityForResult(intent, REQUEST_CODE);
}
/**
* Handle the results from the voice recognition activity.
*/
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
if (data != null) {
//pull all of the matches
ArrayList<String> matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
String topResult = matches.get(0);
EditText AutoText = (EditText) findViewById(R.id.etUserText);
AutoText.setText(topResult);
}
}
}
}
The error message:
Caused by: com.google.android.apps.gsa.shared.exception.GsaIOException: Error code: 393238 | Buffer overflow, no available space.
Why didn't you add a listener to your sample code?
Try adding these on onCreate in MainActivity:
buTranslate.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
buTranslate(view);
}
}
);
Update:
There was another issue. Emulators on android sdk 16 don't show Unicode properly. Thats why you don't see your results, as those are Unicodes. Try Log to print your resultString.
I want to show string from another string in my MainActivity, but the string is getting printed in console. Here is my code:
public class MainActivity extends AppCompatActivity {
Button start;
public TextView showText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showText= (TextView)findViewById(R.id.textView);
start = (Button)findViewById(R.id.button);
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
RetrieveFeedTask click1 = new RetrieveFeedTask();
click1.execute();
showText.setText(click1.getString());
}
});
}
}
And the class:
class RetrieveFeedTask extends AsyncTask<Void, Void, String> {
static final String API_URL = "http://numbersapi.com/random/trivia?json";
private Exception exception;
public String finalString;
protected void onPreExecute() { }
protected String doInBackground(Void... urls) {
try {
URL url = new URL(API_URL );
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
while ((finalString = bufferedReader.readLine()) != null) {
stringBuilder.append(finalString).append("\n");
}
bufferedReader.close();
return stringBuilder.toString();
}
finally{
urlConnection.disconnect();
}
}
catch(Exception e) {
Log.e("ERROR", e.getMessage(), e);
return null;
}
}
protected void onPostExecute(String response) {
if(response == null) {
response = "THERE WAS AN ERROR";
}
try {
JSONObject object = (JSONObject) new JSONTokener(response).nextValue();
finalString = object.getString("text");
Log.i("Here",finalString);
} catch (JSONException e) {
}
}
public String getString() {
return this.finalString;
}
}
You require the finalString before it's populated with your data. the onPostExecute is executed after the doInBackground so you should pass your text view to your task and set it's value in the onPostExecute
public TextView showText;
public RetrieveFeedTask(TextView showText) { this.showText = showText; }
protected void onPostExecute(String response) {
if(response == null) {
response = "THERE WAS AN ERROR";
}
try {
JSONObject object = (JSONObject) new JSONTokener(response).nextValue();
finalString = object.getString("text");
showText.setText(finalString ); // add this
Log.i("Here",finalString);
} catch (JSONException e) {
}
}
The problem is that showText.setText(click1.getString()); of your activity is called earlier than finalString = object.getString("text"); of your task.
Solution:
Create an interface:
public interface DataCallback {
void onNewData(String data);
}
and implement it in your activity:
public class MainActivity extends ... implements DataCallback
public void onNewData(String data) {
showText.setText(data);
}
Pass the interface to your asynctask when you create it:
RetrieveFeedTask click1 = new RetrieveFeedTask(this);
Call the interface inside the task in onPostExecute() to notify the activity that there is new data:
JSONObject object = (JSONObject) new JSONTokener(response).nextValue();
finalString = object.getString("text");
callback.onNewData(finalString);
I am having trouble with my code where i have my Activity which i use to call google api's and retrieve jsons, deserialize them and use it's Polylines to draw on the map.
The problem is that getMapAsync() which sends the callback for onMapReady() (which is used to create the map) is executed immediately after executing my Async Tasks which retrieves necessary data to create the map.
How can i make this happen without stopping the UI thread? I tried doing this calling .execute.get() which freeze the UI thread. But if i do that, i won't be able to use ProgressDialog to inform the users about the delay for fetching data from the servers, which they will be exposed to a frozen UI until the task is complete. How can i do this?
public class RouteAssistantActivity extends Activity implements OnMapReadyCallback{
public GoogleMapsDirectionsResponse dirRes;
public GoogleMapsDistanceResponse disRes;
public String jsonString;
private String mapsAPIKey;
private String directionsBaseURL;
private String distanceBaseURL;
MapFragment mapFragment;
private ProgressDialog progress;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ra_route_assisstant);
mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.ra_map);
progress = new ProgressDialog(RouteAssistantActivity.this);
progress.setTitle("Please Wait");
progress.setMessage("Retrieving Data from the Server");
progress.setIndeterminate(true);
try {
ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
if (appInfo.metaData != null) {
mapsAPIKey = appInfo.metaData.getString("com.google.android.maps.v2.API_KEY");
directionsBaseURL = appInfo.metaData.getString("com.google.android.maps.directions.baseURL");
distanceBaseURL = appInfo.metaData.getString("com.google.android.maps.distance.baseURL");
}
} catch (PackageManager.NameNotFoundException e) {
Log.e("Meta Error", "Meta Data not found. Please check the Manifest and the Meta Data Package Names");
e.printStackTrace();
}
//Test
String directionsURL = directionsBaseURL+"origin=6.948109,79.858191&destination=6.910176,79.894347&key="+mapsAPIKey;
String distanceURL = distanceBaseURL+"units=metric&origins=6.948109,79.858191&destinations=6.910176,79.894347&key="+mapsAPIKey;
Log.e("CA Debug","URL : " + directionsURL);
Log.e("CA Debug","URL : " + distanceURL);
new configurationSyncTask().execute(distanceURL,"distance");
new configurationSyncTask().execute(directionsURL, "direction");
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
LatLng rajagiriya = new LatLng(6.910176, 79.894347);
String points = dirRes.getRoutes().get(0).getOverviewPolyline();
List<LatLng> list = PolyUtil.decode(points);
googleMap.setMyLocationEnabled(true);
googleMap.getUiSettings().setRotateGesturesEnabled(true);
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(rajagiriya, 13));
googleMap.addMarker(new MarkerOptions()
.title("Rajagiriya")
.snippet("My Place")
.position(rajagiriya));
googleMap.addPolyline(new PolylineOptions()
.geodesic(false)
.addAll(list)
.color(Color.RED)
.width(25));
}
private class configurationSyncTask extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
progress.show();
}
#Override
protected String doInBackground(String... params) {
String url = params[0];
String type = params[1];
Log.d("CA Debug", getClass().getSimpleName() + " --> Real URL : " + url);
Log.d("CA Debug", getClass().getSimpleName() + " --> doInBackground requesting content");
jsonString = requestContent(url);
// if the output is null, stop the current task
if (jsonString == null) {
Log.d("CA Debug", getClass().getSimpleName() + " --> Stopping Async Task");
this.cancel(true);
Log.d("CA Debug", getClass().getSimpleName() + " --> Async Task Stopped");
}
return type;
}
#Override
protected void onPostExecute(String types) {
if (types.equalsIgnoreCase("distance")) {
disRes = GMapsDistanceResponseJSONDeserializer.deserialize(jsonString);
} if (types.equalsIgnoreCase("directions")) {
dirRes = GMapsDirectionsResponseJSONDeserializer.deserialize(jsonString);
}
progress.dismiss();
}
}
public String requestContent(String url) {
Log.d("CA Debug",getClass().getSimpleName()+" --> URL : "+url);
try {
URL urlObj = new URL(url);
HttpsURLConnection con = (HttpsURLConnection) urlObj.openConnection();
con.setChunkedStreamingMode(0);
con.setRequestMethod("GET");
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null,null, new SecureRandom());
con.setSSLSocketFactory(sc.getSocketFactory());
InputStream clientResponse;
String jsonString;
int status = con.getResponseCode();
if(status >= HttpURLConnection.HTTP_BAD_REQUEST){
Log.d("CA Debug", getClass().getSimpleName()+" --> Bad Request");
jsonString = null;
} else {
Log.d("CA Debug", getClass().getSimpleName()+" --> converting Stream To String");
clientResponse = con.getInputStream();
jsonString = convertStreamToString(clientResponse);
}
Log.d("CA Debug", getClass().getSimpleName()+" --> JSON STRING : " + jsonString);
return jsonString;
} catch (IOException | NoSuchAlgorithmException | KeyManagementException e) {
Log.d("CA Debug", getClass().getSimpleName()+" --> Error when creating an Input Stream");
e.printStackTrace();
}
return null;
}
public String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
} finally {
try {
is.close();
} catch (IOException e) {
}
}
return sb.toString();
}
}
Quick and somewhat dirty solution would be to execute both AsyncTasks on a single AsyncTask and then on its onPostExecute code invoke getMapAsync. this way you will be sure your tasks finished before you dealing with map's readyness.
Firstly, run tasks after onMapReady because you will get rid of
concern of ready map.
Your async tasks are not parallel, they working on background but second one will be executed after first one completed, check this link
Move some parts of onMapReady to onPostExecute, something like below
Move
#Override
protected void onPostExecute(String types) {
if (types.equalsIgnoreCase("distance")) {
disRes = GMapsDistanceResponseJSONDeserializer.deserialize(jsonString);
}if (types.equalsIgnoreCase("directions")) {
dirRes = GMapsDirectionsResponseJSONDeserializer.deserialize(jsonString);
String points = dirRes.getRoutes().get(0).getOverviewPolyline();
List<LatLng> list = PolyUtil.decode(points);
googleMap.addPolyline(new PolylineOptions()
.geodesic(false)
.addAll(list)
.color(Color.RED)
.width(25)
);
}
}
AsyncTask.SERIAL_EXECUTOR is used to force AsyncTask to execute in Serial Fashion.
More over for your case a little trick will do the job.
Create call back for same AsyncTask and pass different parameters to differentiate the functions.
Now in the second call back initiate mapFragment.getMapAsync(this);
public class MainFragment ...
{
DataDownloader dataDownloader;
int processCount=1;
void initiateProcessFirst(){
new DataDownloader(this,processCount ).execute();
}
public void initiateSecondProcess(){
processCount++;
new DataDownloader(this,processCount ).execute();
}
public void secondProcessCompleted(){
mapFragment.getMapAsync(this);
}
}
AsyncTask Logic goes like the below
public class DataDownloader extends AsyncTask<Void,Void,Boolean> {
MainFragment context;
int processCount;
public DataDownloader(MainFragment context ,int processCount){
this.context=context;
this.processCount=processCount;
}
#Override
protected Boolean doInBackground(Void... params) {
boolean status=false;
// Do logic according to the Process Count
return status;
}
#Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
if(processCount==1)
context.initiateSecondProcess();
else
context.secondProcessCompleted();
}
}
I am new to Android Studio and have a simple android view i am working on. A button click makes a call to the foursquare API and get backresults for starbucks around my location that I parse and am trying to set to the adapter for the listbox on the same view. If i put a breakpoint in the OnPostExecute() I see the mFoursquare adapter that I set for the listview has two json string results in the mFoursquareAdapter , I even call the
mFoursquareAdapter.notifyDataSetChanged();
in it but the view does not get refreshed with the results. I have posted the code below. Can anyone please point out what I am doing wrong or need to change since I already have the results and need to get this done...Your help and feedback very much appreciated! thanks
public class FoursquareInfoFragment extends android.app.Fragment {
private ArrayAdapter<String> mFoursquareAdapter;
public FoursquareInfoFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Dummy data for the ListView. Here's the sample weekly forecast
String[] data = {
"Sample Foursquare Data",
};
List<String> foursquareList = new ArrayList<String>(Arrays.asList(data));
mFoursquareAdapter = new ArrayAdapter<String>(
getActivity(), // the current context ie the activity
R.layout.fragment_my, // the name of the layout Id
R.id.textViewFoursquare, // the Id of the TextView to populate
foursquareList);
View rootView = inflater.inflate(R.layout.fragment_my, container, false);
//View resultsView = inflater.inflate(R.layout.results, container, false);
View resultsView = inflater.inflate(R.layout.fragment_my, container, false);
ListView listView = (ListView) resultsView.findViewById(R.id.listview_FoursquareInfo);
listView.setAdapter(mFoursquareAdapter);
Button btnGetFoursquareData = (Button) rootView.findViewById(R.id.btnFoursquare);
btnGetFoursquareData.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FetchFoursquareDataTask fetch = new FetchFoursquareDataTask();
fetch.execute("Starbucks");
}
});
return rootView;
}
public class FetchFoursquareDataTask extends AsyncTask<String, Void, String[]> {
private final String LOG_TAG = FetchFoursquareDataTask.class.getSimpleName();
#Override
protected void onPostExecute(String[] result) {
if (result != null) {
mFoursquareAdapter.clear();
for (String ItemStr : result) {
mFoursquareAdapter.add(ItemStr);
}
mFoursquareAdapter.notifyDataSetChanged();
}
}
#Override
protected String[] doInBackground(String... params) {
// If there's no venue category, theres nothing to look up. Verify the size of the params.
if (params.length == 0) {
return null;
}
// These two need to be declared outside the try/catch
// so that they can be closed in the finally block.
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
// Will contain the raw JSON response as a string.
String foursquareJsonStr = null;
try {
// Build Foursquare URI with Parameters
final String FOURSQUARE_BASE_URL =
"https://api.foursquare.com/v2/venues/search";
final String client_id = "client_id";
final String client_secret = "client_secret";
final String v = "20130815";
final String near = "Dunwoody, Ga";
final String query = "Starbucks";
final String limit = "2";
Uri builtUri = Uri.parse(FOURSQUARE_BASE_URL).buildUpon()
.appendQueryParameter("client_id", client_id)
.appendQueryParameter("client_secret", client_secret)
.appendQueryParameter("v", v)
.appendQueryParameter("near", near)
.appendQueryParameter("query", query)
.appendQueryParameter("limit", limit)
.build();
URL url = new URL(builtUri.toString());
// Create the request to Foursquare, and open the connection
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
// Nothing to do.
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
foursquareJsonStr = null;
return null;
}
foursquareJsonStr = buffer.toString();
Log.v(LOG_TAG, "Foursquare JSON String: " + foursquareJsonStr);
} catch (IOException e) {
Log.e(LOG_TAG, "Error ", e);
// If the code didn't successfully get the fpursquare data, there's no point in attempting
// to parse it.
return null;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("PlaceholderFragment", "Error closing stream", e);
}
}
}
String[] list = new String[]{"", ""};
try {
JSONObject foursquareJson = new JSONObject(foursquareJsonStr);
JSONObject responseObject = (JSONObject) foursquareJson.get("response");
JSONArray foursquareArray = responseObject.getJSONArray("venues");
list = new String[foursquareArray.length()];
for (int i = 0; i < foursquareArray.length(); i++) {
list[i] = foursquareArray.get(i).toString();
}
return list;
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
e.printStackTrace();
} finally {
Log.e(LOG_TAG, "ba");
return list;
}
}
}
}
This
mFoursquareAdapter.add(ItemStr);
Should be
foursquareList.add(ItemStr)
And you'll need to declare foursquareList properly (as a field).
You should also declare your Adapter as a field variable as well, just in case you need to reference it later