So, in my onCreate() method, I'm calling a Parse query and returning a single ParseObject that is tied to a global variable, like so...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
String quizId = getActivity().getIntent().getStringExtra("quizId");
ParseQuery<ParseObject> getQuiz = ParseQuery.getQuery("Quiz");
getQuiz.getInBackground(quizId, new GetCallback<ParseObject>() {
#Override
public void done(ParseObject result, ParseException e) {
mQuiz = result;
mQuestionRelation = mQuiz.getRelation("questions");
Log.d("KMH", "mQuiz: " + mQuiz.getObjectId());
}
});
}
}
The console returns this as proof it's getting the object:
11-19 03:12:40.104 14876-14876/com.codejunkie.games.quizie D/KMH﹕ Parse returned quiz: HTgGeY3NJL
Then, I set my global ParseRelation variable to a relation of the returned ParseObject. Now, inside of my onResume() method, I'm using that Relation global variable and it's getting a NullPointerException.
#Override
public void onResume() {
super.onResume();
ParseQuery<ParseObject> getAnswers = mQuestionRelation.getQuery();
getAnswers.addDescendingOrder("createdAt");
getAnswers.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> answers, ParseException e) {
mAnswers = answers;
String[] answerText = new String[mAnswers.size()];
int i = 0;
for(ParseObject answer : mAnswers) {
answerText[i] = answer.getString("answer");
i++;
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), R.layout._item_question, R.id.questionText, answerText);
setListAdapter(adapter);
}
});
}
This is the line with the NullPointer:
ParseQuery<ParseObject> getAnswers = mQuestionRelation.getQuery();
ANSWER:
I wasn't setting my globals in the main thread due to the .getInBackground call to Parse. Here's how I fixed it:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
String quizId = getActivity().getIntent().getStringExtra("quizId");
ParseQuery<ParseObject> getQuiz = ParseQuery.getQuery("Quiz");
try {
mQuiz = getQuiz.get(quizId);
mQuestionRelation = mQuiz.getRelation("questions");
} catch (ParseException e) {
e.printStackTrace();
}
}
}
And to handle the case of mQuestionRelation being null:
if (mQuestionRelation != null) {
ParseQuery<ParseObject> getQuestions = mQuestionRelation.getQuery();
getQuestions.addAscendingOrder("createdAt");
getQuestions.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> questions, ParseException e) {
if (e == null) {
mQuestions = questions;
String[] answerText = new String[mQuestions.size()];
int i = 0;
for (ParseObject question : mQuestions) {
answerText[i] = question.getString("question");
i++;
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), R.layout._item_question, R.id.questionText, answerText);
mQuestionsList.setAdapter(adapter);
}
}
});
}
You get your Relation in a different thread (since it is executed in background). This means that the set is not actually done in onCreate() but sometimes later, so the 'done' method might be called after onResume() depending on how slow the querying is. If that happens, then you'll get a null pointer exception indeed.
Related
I want to display this textview "txtCalculate" which comes from the class CustomerMapActivity which is displayed in the activity_map_customer layout in another layout which is activity_bon_de_commande, of the class BonDeCommande.
the problem is I don't know how to do it
I'm new to java programming
thank you
public void readValues(){
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
Query lastQuery = ref.child("ride_info").orderByKey().limitToLast(1);
lastQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()){
double value0_float = ds.child("pickup").child("lat").getValue(Double.class);
double value1_float = ds.child("pickup").child("lng").getValue(Double.class);
double value2_float = ds.child("destination").child("lat").getValue(Double.class);
double value3_float = ds.child("destination").child("lng").getValue(Double.class);
String pickupLat = String.valueOf(value0_float);
String pickupLng = String.valueOf(value1_float);
String destiLat = String.valueOf(value2_float);
String destiLng = String.valueOf(value3_float);
String requestUrl=null;
try {
requestUrl = "https://maps.googleapis.com/maps/api/directions/json?"+
"mode=driving&"
+"transit_routing_preference=less_driving&"
+"origin="+pickupLat+","+pickupLng+"&"
+"destination="+destiLat+","+destiLng+"&"
+"key="+getResources().getString(R.string.google_maps_key);
Log.e("LINK",requestUrl);
mService.getPath(requestUrl).enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
try {
JSONObject jsonObject = new JSONObject(response.body().toString());
JSONArray routes = jsonObject.getJSONArray("routes");
JSONObject object = routes.getJSONObject(0);
JSONArray legs = object.getJSONArray("legs");
JSONObject legsObject = legs.getJSONObject(0);
//Get distance
JSONObject distance = legsObject.getJSONObject("distance");
String distance_text = distance.getString("text");
//use regex to extract double from string
//This regex will remove all text not digit
Double distance_value= Double.parseDouble(distance_text.replaceAll("[^0-9\\\\.]+",""));
//Get Time
JSONObject time = legsObject.getJSONObject("duration");
String time_text = time.getString("text");
Integer time_value = Integer.parseInt(time_text.replaceAll("\\D+",""));
String final_calculate = String.format("%.2f €",
TypeObject.getPrice(distance_value,time_value));
HERE -----> txtCalculate.setText(final_calculate);
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
mCurrentRide.cancelRide();
endRide();
}
});
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
mCurrentRide.cancelRide();
endRide();
}
});
}
screenshot of my screen
You need to Create an Interface with an update method, declare in your Activity and after, pass as parameter to your handler object that gets the data.
Don't forget If you're getting the data in a different Thread, you need to update your views always in an UI Thread or in the Main Thread.
Here Follow some example code:
Your Activity or Fragment
public class MainActivity extends AppCompatActivity
implements UpdateViewCallback { // implement the interface here
private TextView textView = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
textView = findViewById(R.id.textView);
// Pass the interface in your Object that makes the async work
final AsyncWork asyncWork = new AsyncWork(this);
// Running
Thread thread = new Thread(asyncWork);
thread.start();
}
/**
* UpdateViewCallback
* #param result
*/
#Override
public void updateView(final String result) {
// Always update View on MainThread or an UI Thread, or else issues will start to happening
this.runOnUiThread(new Runnable() {
public void run() {
// Check if View is null since you're updating in a thread async
if (textView != null) {
textView.setText(result);
}
}
});
}
}
Your Interface:
public interface UpdateViewCallback {
void updateView(String result);
}
Your Object to handle the Async Work:
public class AsyncWork implements Runnable {
private UpdateViewCallback updateViewCallback;
public AsyncWork(UpdateViewCallback updateViewCallback) {
this.updateViewCallback = updateViewCallback;
}
/**
* Async Work here
*/
#Override
public void run() {
// Do some Work and after update using the interface you passed in the constructor
updateViewCallback.updateView("This is a test");
}
}
I'm stuck, I try to get an Array in Parse. I succeed to get it however I can't return it to use it in another method.
Do someone know what should I do ?
Retrieved ["international","entrepreneurship"]
public class CardsActivity extends AppCompatActivity {
ParseUser currentUser = ParseUser.getCurrentUser();
String test = currentUser.getObjectId();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cards);
// Specify which class to query
ParseQuery<ParseObject> query = ParseQuery.getQuery("_User");
query.selectKeys(Arrays.asList("tastes"));
// Specify the object id
query.getInBackground(test, new GetCallback<ParseObject>() {
public void done(ParseObject object, ParseException e) {
if (e == null) {
ArrayList<String> userTastesGot = (ArrayList<String>) object.get("tastes");
Log.d("User", "Retrieved " + userTastesGot);
} else {
Toast.makeText(CardsActivity.this, "Nous n'avons pas trouvés vos goûts", Toast.LENGTH_SHORT).show();
}
}
});
You can't return it from onCreate, no. I wouldn't even retrieve it in onCreate unless you can be certain that it won't be needed until it has been retrieved. I would do something like this:
interface Callback<T> {
void success(T result);
void failure(Exception error);
}
void getUserTastes(Callback<ArrayList<String>> callback){
// Note the special way to get a query for the user table
ParseQuery<ParseUser> query = ParseUser.getQuery();
query.selectKeys(Arrays.asList("tastes"));
// TODO: Specify the object id
query.getInBackground(test, new GetCallback<ParseUser>() {
public void done(ParseUser object, ParseException e) {
if (e == null) {
ArrayList<String> userTastesGot = (ArrayList<String>) object.get("tastes");
Log.d("User", "Retrieved " + userTastesGot);
callback.success(userTastesGot);
} else {
callback.failure(e);
}
}
});
}
Use whatever protection levels are appropriate.
private void getFriendRequests(){
ParseQuery<ParseObject> query = ParseQuery.getQuery("FriendRequests");
query.whereEqualTo("To",ParseUser.getCurrentUser().getUsername());
query.whereNotEqualTo("Accepted", true);
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
if (e == null) {
fillFriendRequests(objects);
displayFriendRequest();
} else {
}
}
});
}
private void fillFriendRequests(List<ParseObject> list){
for(ParseObject object:list){
frArrayStrings.add(object.getString("From"));
}
public void displayFriendRequest(){
friendRequestView= (ListView)mview.findViewById(R.id.listViewFriendReqs);
mAdapter = new ArrayAdapter<>(getActivity(),android.R.layout.simple_list_item_1,frArrayStrings);
friendRequestView.setAdapter(mAdapter);
setClickListenter();
}
I cannot understand why I get nothing even there is a string in the query.
I certainly named the query right but when I see the
object.getString("From");in textview, there is nothing there and the textsize is 0. Can you guys help out what's wrong with my code?
I haver a list view in my android app that needs to be updated. Everything works fine, but the content is reloading every second time. For example if I reload the content once, the notifyDataSetChanged() is called, but nothing changes. On my second refresh, the data is reloaded. My third time same as first and so on.. What could be the problem? Here's my code:
private class LoadMoreDataTask extends AsyncTask<Void, Void, Void>{
#Override
protected Void doInBackground(Void... params) {
ParseQuery<ParseObject> likeQuery = ParseQuery.getQuery("Likes");
likeQuery.whereEqualTo("username", ParseUser.getCurrentUser().getUsername());
likeQuery.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> likeList, ParseException e) {
if (e == null) {
postList.clear();
try {
query = new ParseQuery<ParseObject>("Images");
query.orderByDescending("createdAt");
query.setLimit(limit += 20);
ob = query.find();
for (ParseObject num : ob) {
PostRow test1;
Like singleLike = new Like(true);
for (int i = 0; i < likeList.size(); i++) {
if (likeList.get(i).get("imgId").equals(num.getObjectId())) {
isLiked = true;
break;
} else {
isLiked = false;
}
}
singleLike.setLikeStatus(isLiked);
ParseFile img = (ParseFile) num.get("img");
test1 = new PostRow(img.getUrl().toString(), (String) num.get("username"), num.getObjectId(), singleLike, num.getInt("likeCount"));
postList.add(test1);
}
} catch (ParseException e1) {
e1.printStackTrace();
}
} else {
//error
}
}
});
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
adapter.notifyDataSetChanged();
int position = listViewPosts.getFirstVisiblePosition();
View v = listViewPosts.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
listViewPosts.setSelectionFromTop(position, top);
}
}
Here's where I call the Async Task. It's an onrefresh listener, in another AsyncTask's onPostExecute method:
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
new LoadMoreDataTask().execute();
swipeRefreshLayout.setRefreshing(false);
}
});
I'm trying to sync a list from the handheld to the wearable. On the phone side, I have a listview and you can add items to it and on the wear side I am just displaying the same list. I'm adding items to /card/id path and adding the array size on /counter. OnDataChanged method does gets called when I add items to the list on phoneside, but when I try to read the items on wearside, it's not working. It gives nullpointer exception when I'm trying to get the connected nodes and therefor I'm not able to read the data. Here's the code and the log snapshot:
Error
04-15 12:41:38.075: E/AndroidRuntime(13791): Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'android.os.Looper com.google.android.gms.common.api.GoogleApiClient.getLooper()' on a null object reference
Wear side:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDefaultCircleRadius = getResources().getDimension(R.dimen.default_settings_circle_radius);
mSelectedCircleRadius = getResources().getDimension(R.dimen.selected_settings_circle_radius);
cards = new ArrayList<GiftCard>();
new LoadCards().execute();
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
#Override
public void onLayoutInflated(WatchViewStub stub) {
//mTextView = (TextView) stub.findViewById(R.id.count_text);
mListView = (WearableListView) stub.findViewById(R.id.card_list_view);
}
});
mHandler = new Handler();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
#Override
public void onDataChanged(DataEventBuffer dataEvents) {
for (DataEvent event : dataEvents) {
if (event.getType() == DataEvent.TYPE_CHANGED) {
// DataItem changed
DataItem item = event.getDataItem();
if (item.getUri().getPath().compareTo(COUNT_PATH) == 0) {
DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
final String counter = dataMap.getString(CardUtil.CARD_COUNT);
new LoadCards().execute();
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(c,"Card count: "+ counter,Toast.LENGTH_LONG).show();
//mTextView.setText("COUNTER FROM DATACHANGE METHOD: " + counter);
}
});
}
else if(item.getUri().getPath().compareTo(CARD_PATH) == 0){
}
} else if (event.getType() == DataEvent.TYPE_DELETED) {
// DataItem deleted
}
}
}
public GiftCard loadCardData(int id){
//Uri uri = getIntent().getData().buildUpon().encodedPath("/card").appendPath(String.valueOf(id)).build();
Uri uri = getUriForDataItem("/counter");
Log.d("URI", uri.getPath());
DataApi.DataItemResult result = Wearable.DataApi.getDataItem(mGoogleApiClient,uri).await();
DataMapItem item = DataMapItem.fromDataItem(result.getDataItem());
Asset cardImageAsset = item.getDataMap().getAsset(CardUtil.CARD_IMAGE);
//Asset barcodeImageAsset = item.getDataMap().getAsset(CardUtil.BARCODE_IMAGE);
String card_type = item.getDataMap().getString(CardUtil.CARD_TYPE);
Bitmap cardImage = BitmapFactory.decodeStream(Wearable.DataApi.getFdForAsset(mGoogleApiClient, cardImageAsset).await().getInputStream());
// Bitmap barcodeImage = BitmapFactory.decodeStream(Wearable.DataApi.getFdForAsset(mGoogleApiClient,barcodeImageAsset).await().getInputStream());
GiftCard card = new GiftCard();
card.setCardImage(cardImage);
card.setCardName(card_type);
card.setCardID(id);
return card;
}
public class LoadCards extends AsyncTask<Void, Void, Boolean> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Void... arg0) {
// Uri uri = getIntent().getData().buildUpon().encodedPath("/counter").build();
Uri uri = getUriForDataItem("/counter");
Toast.makeText(c,uri.toString(),Toast.LENGTH_LONG).show();
DataApi.DataItemResult result = Wearable.DataApi.getDataItem(mGoogleApiClient,uri).await();
DataMapItem item = DataMapItem.fromDataItem(result.getDataItem());
int card_count = Integer.parseInt(item.getDataMap().getString(CardUtil.CARD_COUNT));
// int card_count = Integer.parseInt(loadCardCounter());
if(card_count <= 0){
Toast.makeText(c,"No cards available to show!",Toast.LENGTH_LONG).show();
} else {
for (int i = 1; i <= card_count; i++) {
GiftCard c = loadCardData(i);
cards.add(c);
}
}
return null;
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
//update the card list
mAdapter = new CardListAdapter(c,cards);
mListView.setAdapter(mAdapter);
// mListView.setClickListener();
}
}
private Uri getUriForDataItem(String path) {
String nodeId = getNodeId();
return new Uri.Builder().scheme(PutDataRequest.WEAR_URI_SCHEME).authority(nodeId).path(path).build();
}
private String getNodeId() {
NodeApi.GetConnectedNodesResult nodesResult = Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();
List<Node> nodes = nodesResult.getNodes();
if (nodes.size() > 0) {
return nodes.get(0).getId();
} else {
Toast.makeText(c,"NO NODES AVAILABLE",Toast.LENGTH_LONG).show();
}
return null;
}}
From the stacktrace it's pretty obvious that you are trying to use Wearable DataAPI from the thread without Looper - in doInBackground() method I believe. That is why it crashes.
Move this code directly into onDataChanged() method and it should solve the issue.