Hello I'm learning android and trying to display a customized ListView but it fails to load. The issue comes from my query as the list is empty. Please what did i do wrong as i was following parse example.
Below is my code using fragments to display the view as it fails to get inflated.
EventTab.java:
//query Events for current user
private void queryEventListFromParse(){
//Create query for objects of type "Event"
ParseQuery<ParseObject> query = ParseQuery.getQuery("Event");
// Restrict to cases where the author is the current user.
//pass in a ParseUser and not String of that user
query.whereEqualTo("author", ParseUser.getCurrentUser());
query.orderByAscending("createAt");
// Run the query
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> eventList, ParseException e) {
if (e == null) {
// If there are results, update the list of event and notify the adapter
Log.d(TAG, "Im in background"); //im able to display image
eventList.clear();
for (ParseObject event : eventList) {
eventList.add(event);
}
updateEventsList();
} else {
Log.d(TAG, "Event retrieval error: " + e.getMessage());
}
}
});
}
IMPORTANT UPDATE:
Thanks to Shadow Droid for pointing out the error. The reason why getView() fails to be called due to the List called evenList returning 0. This fails to get getView called and hence returns 0 and fails to display the list.
Below is error message when i commented eventList.clear();
Error from console:
12-05 04:52:10.511 11450-11450/com.example.davchen.skibuddies E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.davchen.skibuddies, PID: 11450
java.util.ConcurrentModificationException
at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)
at com.example.davchen.skibuddies.Fragments.EventTab$1.done(EventTab.java:87)
at com.example.davchen.skibuddies.Fragments.EventTab$1.done(EventTab.java:80)
at com.parse.ParseTaskUtils$2$1.run(ParseTaskUtils.java:115)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5942)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
This is happening bcoz you are passing empty eventList to your adapter. There is confusion in parameter and global variable.
Global variable private List<Event> eventList; and it is initialized to empty in onCreate.
while as parameter in done method you are clearing the list which you get after parsing eventList.clear();
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> eventList, ParseException e) {
if (e == null) {
// If there are results, update the list of event and notify the adapter
Log.d(TAG, "Im in background"); //im able to display image
eventList.clear();
for (ParseObject event : eventList) {
eventList.add(event);
}
updateEventsList();
} else {
hence your adapter is getting count as zero and it will not call getView method.
As a solution I would suggest to check by commenting the eventList.clear(); and if works properly and still you require to clear list then go for different variable or parameter name
Related
Every time the value in database changes causes the related activity stops working. But after starting the activity again the display and data retrieved will still work and is updated.
I found this in Logcat:
AndroidRuntime: FATAL EXCEPTION: main
java.lang.NumberFormatException: For input string: "201908241000gjjj"
That is a string key for database:
//formatDateTime and parseDateTime are methods to simplify simpleDateFormat and return String
String stringDate = formatDateTime(dateFromString, "yyyyMMdd");
String stringTime = parseDateTime(taskTime, "hh:mm a", "HHmm");
final String key = stringDate + stringTime + taskParticipant;
dbrSchedule.child(key).setValue(schedule); //schedule is model class
I never ask the code to retrieve and parse it to Numeric. Inside onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dbrCurrentTask.orderByChild("dateOrder").startAt(stringDateForWorkingInProgress).endAt(stringDateForCurrent).addValueEventListener(todayTasks);
}
private ValueEventListener todayTasks = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
scheduleList.clear();
for (DataSnapshot scheduleTaskDS : dataSnapshot.getChildren()) {
final ScheduleFD scheduleTemp = scheduleTaskDS.getValue(ScheduleFD.class);
if (scheduleTemp != null) {
if ((scheduleTemp.getDateOrder().equals(stringDateForCurrent) && !scheduleTemp.getStatus().equals(getString(R.string.task_completed))) || (!scheduleTemp.getDateOrder().equals(stringDateForCurrent) && scheduleTemp.getStatus().equals(getString(R.string.working_in_progress)))) {
scheduleList.add(scheduleTemp);
}
}
}
tra = new TaskFDAdapter(ScheduleCheckInOut.this, scheduleList);
trv.setAdapter(tra);
if (!scheduleList.isEmpty()) {
handler.postDelayed(runnable, 360);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
#Override
protected void onDestroy() {
super.onDestroy();
dbrCurrentTask.orderByChild("dateOrder").startAt(stringDateForWorkingInProgress).endAt(stringDateForCurrent).removeEventListener(todayTasks);
}
Also I have did same thing but with try catch:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
dbrCurrentTask.orderByChild("dateOrder").startAt(stringDateForWorkingInProgress).endAt(stringDateForCurrent).addValueEventListener(todayTasks);
} catch (NumberFormatException e){
//refresh
finish();
overridePendingTransition(0, 0);
startActivity(new Intent(getApplicationContext(), THIS_ACTIVITY.class));
overridePendingTransition(0, 0);
}
But it still show NumberFormatException in Logcat and stop working when database value is changed.
I also tried to change my string key to without any numeric but same Exception shown.
After a lot of testing, I found that the string key 201908241000gjjj which shown in Error: java.lang.NumberFormatException: For input string: "201908241000gjjj" is the previous string key of string key 201908261000ffghrr which the child value changed:
{
"Schedules": {
"201908231000bb": {children}
"201908241000gjjj": {children} //NumberFormatException show this key
"201908261000ffghrr": {children} //value changed
}
}
For any changes in children will show the Exception for the previous string key. If children changed in 201908241000gjjj, then Exception show 201908231000bb.
And if children changed in 201908231000bb, it have no error because 201908231000bb is the first and have no previous string key for it.
Why is this weird things happen? Will the size of children influence this? I have another reference group have 3 children and String values for each child with no issue when Database changes but this reference group (Schedules) has about 34 children and String values for each child.
I expect no matter how the value in database is changed, the activity will keep working, but it goes back to the previous activity and then pops up "Application not working" after any change in the referred database.
I find a bit unclear what is your question, but here is my try:
You are getting NumberFormatException in .getValue(ScheduleFD.class) in the listener, that is a guess I make from your post, you should have the exact line in your logcat.
You don't necessarily need to wrap the query in a try catch, you may catch something, but it won't be a NumberFormatException, if you want to use the try/catch, wrap it around .getValue(ScheduleFD.class) inside the EventListener, where I think is more certainly that you are getting the exception.
However if you are getting the exception there is because your logic is wrong, what's the point on getting the value if you are expecting to catch an exception?
The way you are storing your data in the database must be consistent with the way you are going to retrieve it.
If I'm wrong I'd suggest to add your ScheduleFD.class to your question along with a sample data of what you are trying to get.
I'm working on a ViewPager fragment that uses FragmentStatePagerAdapter as the adapter. The Adapter's data is a List object that comes from the database, and I am observing the query with MediatorLiveData.
MediatorLiveData merges six different lists that I have for one day and turns them into one list that is used by the Adapter.
I want to add an item to the List to a specific index and update the UI dynamically. The observer notifies the adapter when an item is added and the update works fine, however when I try to do it on a specific index, calling notifyDataSetChanged() causes an IndexOutOfBoundsError.
I initialize the adapter with a list as follows:
public MealDetailsPagerAdapter(FragmentManager fm, List<Long> list, long date, MealViewModel vm) {
super(fm);
this.mealIdList = list;
this.date = date;
this.model = vm;
}
Where MealViewModel is not relevant to this question, it is used on the fragment that the adapter is creating. The list changes are done by another viewmodel.
Here's a code that works correctly:
public void changeItems(List<Long> list, long date) {
if(this.date != date){
this.mealIdList = list;
notifyDataSetChanged();
return;
}
mealIdList.addAll(list);
mealIdList = removeDuplicates(mealIdList);
System.out.println(Arrays.toString(mealIdList.toArray()));
notifyDataSetChanged();
}
And the observer that calls it:
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel.getMealIdsInDay().observe(getViewLifecycleOwner(), longs -> {
myAdapter.changeItems(longs, mCurrentIndexDay);
if(isResumed){
mViewPager.setCurrentItem(myAdapter.getPageIndexForMealId(mViewModel.getMealId()));
isResumed=false;
}
updateIndicator(mViewPager);
});
}
Where isResumed is false by default, however if the user adds a new Meal isResumed is changed to true and the viewPager's current position gets changed to the created Meal's position.
However, with the working code, the created Meal's position will always be at the end of the adapter's List because of addAll(). I want to add the meal to a specific position, but if I get the index with mViewPager.getCurrentItem() and send it to the method as follows:
mealIdList.addAll(index, list);
the addAll itself works, but notifyDataSetChanged() causes an IndexOutOfBoundsError.
Here's the complete stack trace:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: fi.seehowyoueat.shye.debug, PID: 14148
java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
at java.util.ArrayList.set(ArrayList.java:453)
at androidx.fragment.app.FragmentStatePagerAdapter.destroyItem(FragmentStatePagerAdapter.java:147)
at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1212)
at androidx.viewpager.widget.ViewPager.setCurrentItemInternal(ViewPager.java:669)
at androidx.viewpager.widget.ViewPager.setCurrentItemInternal(ViewPager.java:631)
at androidx.viewpager.widget.ViewPager.dataSetChanged(ViewPager.java:1086)
at androidx.viewpager.widget.ViewPager$PagerObserver.onChanged(ViewPager.java:3097)
at androidx.viewpager.widget.PagerAdapter.notifyDataSetChanged(PagerAdapter.java:291)
at fi.octo3.shye.view.viewpagers.MealDetailsPagerAdapter.changeTheItems(MealDetailsPagerAdapter.java:87)
at fi.octo3.shye.fragments.MealDetailsFragment.lambda$onActivityCreated$0(MealDetailsFragment.java:223)
at fi.octo3.shye.fragments.-$$Lambda$MealDetailsFragment$XB4Svnx84FE6kVa5Gzle01e8F3o.onChanged(Unknown Source:4)
at androidx.lifecycle.LiveData.considerNotify(LiveData.java:131)
at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:149)
at androidx.lifecycle.LiveData.setValue(LiveData.java:307)
at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
at fi.octo3.shye.models.viewmodel.-$$Lambda$2CouvY7DQv4NA0nk6EMoH6jUavw.onChanged(Unknown Source:4)
at androidx.lifecycle.MediatorLiveData$Source.onChanged(MediatorLiveData.java:152)
at androidx.lifecycle.LiveData.considerNotify(LiveData.java:131)
at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:149)
at androidx.lifecycle.LiveData.setValue(LiveData.java:307)
at androidx.lifecycle.LiveData$1.run(LiveData.java:91)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:280)
at android.app.ActivityThread.main(ActivityThread.java:6748)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Looking at it, it seems that the problem is somehow caused by the LiveData, but I'm not sure how to fix it. If you want to look at the method that updates the MediatorLiveData that I have it's here:
private void refresh(long key){
if(groupsAndMealsMap.get(key) != null){
//remove source and then value from map
liveDataMerger.removeSource(groupsAndMealsMap.get(key));
groupsAndMealsMap.remove(key);
//add new value to map and add it as a source
groupsAndMealsMap.append(key, mealIdsInGroup);
liveDataMerger.addSource(groupsAndMealsMap.get(key), liveDataMerger::setValue);
}
}
refresh() is called by addItem() that gets an updated List of Meals from the database (list being mealIdsInGroup) and liveDataMerger consists of six LiveData> objects.
Any help will be appreciated. Thank you!
EDIT
Here's the addItem() method, as you can see the service executor waits for the operation to be done before moving on to the refresh() method.
public void addItem(Meal meal, long mealGroupId){
ExecutorService service = Executors.newCachedThreadPool();
service.execute(() -> {
setMealId(db.mealDao().insertMealIntoGroup(meal, mealGroupId));
mealIdsInGroup = db.mealDao().loadMealsWithinGroup(mealGroupId);
});
service.shutdown();
try {
service.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
refresh(mealGroupId);
}
I suspect that the issue occurs because the insert operation is not over yet.
Use a Handler to put a delay
new Handler(getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
notifyDataSetChanged();
}
}, 500);
500 ms just for testing.
Does that issue occurs no matter of what position you're in?
Because if you are in position 0 of the adapter, the adapter didn't created the fragment that's in 3rd position yet.
Remember that the one of the main differences between ViewPagerAdapter and FragmentStatePagerAdapter is that the latter only creates 3 fragments at a time, and if you are in the first position or in the last, the adapter will only contain 2 instances of fragments.
Let me know if this solution helped you!
I am using BaseExpandableListAdapter and trying to do a dynamic list, where elements appears and disappears when you check or uncheck other elements. The group is an ArrayList of an object tha I made calle Mode, and children are a HashMap like that: HashMap> children.
The problem comes when I actualize the list to add children and they are added perfectly, but when I check other elements and the new children must disappear the program give me a NullPointerException in the method getChildrenCount(). I am actually using the notifyDataSetChanged() in both cases, when I am adding and when I am removing.
This is a piece of my code (the important part is that if I find another Mode object with the same parent ID in the DB I must to delete the old one):
cbMode.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
boolean isSelected = modeDao.rbIsAlreadySelected(currentChild);
if(!isSelected) {
//if checked uncheck all the children of the same parent AND delete the children
Mode oldMode = modeDao.isThereAnotherRB(currentChild.getIdFather());
if(oldMode != null){
uncheckTheOldCB(oldMode);
setFalseOnCb(oldMode);
modeDao.deleteMode(oldMode);
deleteModeChildren(oldMode);
}
//AND insert it on the DB
modeDao.setSelectedMode(currentChild);
currentChild.setChecked(true);
//if has children show them
if(currentChild.hasChildren() == 1){
setNewFatherMode(currentChild);
}
}else {
//if unchecked delete this from the DB
modeDao.deleteMode(currentChild);
deleteModeChildren(currentChild);
currentChild.setChecked(false);
}
notifyDataSetChanged();
}
});
It shows as how I delete the children:
private void deleteModeChildren(Mode oldMode){
for (Map.Entry<Mode, ArrayList<Mode>> entry : children.entrySet()) {
Mode currentMode = entry.getKey();
if(currentMode.getId() == oldMode.getId()) {
children.remove(entry.getKey());
break;
}
}
}
And this is how I overrided the getChild method:
#Override
public Object getChild(int groupPosition, int childPosition) {
return this.children.get(this.parents.get(groupPosition))
.get(childPosition);
}
This it the track of the exception:
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.util.ArrayList.size()' on a null object reference
at com.iurban.iurbanapp.Adapters.NewModesAdapter.getChildrenCount(NewModesAdapter.java:63)
at android.widget.ExpandableListConnector.refreshExpGroupMetadataList(ExpandableListConnector.java:563)
at android.widget.ExpandableListConnector.access$000(ExpandableListConnector.java:50)
at android.widget.ExpandableListConnector$MyDataSetObserver.onChanged(ExpandableListConnector.java:857)
at android.database.DataSetObservable.notifyChanged(DataSetObservable.java:37)
at android.widget.BaseExpandableListAdapter.notifyDataSetChanged(BaseExpandableListAdapter.java:56)
at com.iurban.iurbanapp.Adapters.NewModesAdapter$3.onClick(NewModesAdapter.java:223)
at android.view.View.performClick(View.java:4787)
at android.widget.CompoundButton.performClick(CompoundButton.java:120)
at android.view.View$PerformClick.run(View.java:19873)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
And this is the getChildCount method:
#Override
public int getChildrenCount(int groupPosition) {
return children.get(parents.get(groupPosition)).size();
}
Ok, after a while I just to realise that I was deleting the children but not the corresponding parent of it. So, the getChildCount method gave me an error because the groupCount value were 4 when it must be 3.
Thank you all!
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.util.ArrayList.size()' on a null object reference
This tells you that the size() method is what threw the NPE, so there's a good chance that it is the list which is null.
Double check that it is indeed initialised.
I'm trying to access a certain value within the last added Firebase node. In my database I have a set of Clients, which through my app, can be added to. Inside a client there's a piece of information titled 'clientName'. I would like to get this value.
Once I get the value, I'm trying to give a toast message showing that value.
Here is my code inside the onClick method of my button. I'm not sure why it's not working. If you know of another way I could do this or a way to fix my current code I'd really appreciate it!
Thanks in advance guys!
my_button[bt].setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (my_button[Index].getId() == ((ImageButton) v).getId()) {
String bla = (String) getIntent().getExtras().get("id");
String address = "https://console.firebase.google.com/project/cssecond-92a2d/database/data/clients/" +bla+"/clientName";
Firebase ref = new Firebase(address);
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(com.firebase.client.DataSnapshot dataSnapshot) {
String value = (String) dataSnapshot.getValue();
Toast.makeText(HomePageNews.this,"In your hands you have: "+ value ,Toast.LENGTH_LONG).show();
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
}
});
Everything looks fine in your code. The problem is this line of code:
String bla = (String) getIntent().getExtras().get("id");
The id that is returning from that intent is null, so your reference is also null. In order to fix this, you need to change the code to get the correct value from the intent that is coming from your previous activity and than it should work.
When I attempt to call the method loadUserList() from another class, I get the following error:
Attempt to invoke virtual method android.content.res.Resources
android.content.Context.getResources() on a null object reference
This is my loadUserList method
public void loadUserList()
{
final ProgressDialog dia = ProgressDialog.show(this, null, getString(R.string.alert_loading));
ParseQuery<ParseObject> query = ParseQuery.getQuery("Chat_User");
query.whereEqualTo("receiver", ParseUser.getCurrentUser());
query.include("sender");
query.findInBackground(new FindCallback<ParseObject>()
{
#Override
public void done(List<ParseObject> li, ParseException e)
{
dia.dismiss();
if (li != null)
{
if (li.size() == 0)
Toast.makeText(com.yarnyard.UserList.this, R.string.msg_no_user_found,
Toast.LENGTH_SHORT).show();
uList = new ArrayList<ParseObject>(li);
ListView list = (ListView) findViewById(R.id.list);
list.setAdapter(new UserAdapter());
list.setOnItemClickListener(new OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int pos, long arg3)
{
loadUserList();
/*startActivity(new Intent(com.yarnyard.UserList.this, Chat.class)
.putExtra(Const.EXTRA_DATA, uList.get(pos).getUsername()));*/
}
});
}
else
{
Utils.showDialog(
com.yarnyard.UserList.this,
getString(R.string.err_users) + " "
+ e.getMessage());
e.printStackTrace();
}
}
});
}
This is how I am calling it
public void done(ParseException e)
{
UserList UserList = new UserList();
UserList.loadUserList();
}
My error log
07-30 14:14:56.219 13383-13383/com.anonimv2 E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.anonimv2, PID: 13383
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
at android.content.ContextWrapper.getResources(ContextWrapper.java:85)
at android.view.ContextThemeWrapper.getResources(ContextThemeWrapper.java:74)
at android.content.Context.getString(Context.java:376)
at com.yarnyard.UserList.loadUserList(UserList.java:96)
at com.yarnyard.custom.CustomActivity.onOptionsItemSelected(CustomActivity.java:116)
at android.app.Activity.onMenuItemSelected(Activity.java:2882)
at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:353)
at com.android.internal.policy.impl.PhoneWindow.onMenuItemSelected(PhoneWindow.java:1131)
at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:761)
at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:152)
at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:904)
at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:894)
at android.widget.ActionMenuView.invokeItem(ActionMenuView.java:587)
at com.android.internal.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:141)
at android.view.View.performClick(View.java:4832)
at android.view.View$PerformClick.run(View.java:19839)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:211)
at android.app.ActivityThread.main(ActivityThread.java:5321)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1016)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:811)
Any advice would be much appreciated.
Normal, non-static methods are called on objects, not on classes. This is a fine point that you really need to learn before using object oriented languages. Only then you will see, in practice, how you can connect objects by passing references.
The UserList objects that you construct in the done method is not the one you want to call, it's just an empty, uninitialized shell.
As I understand, you extend UserList from Context, right?
Then keep in mind that in Android never initial a Context object by yourself, it's framework's job..
In your case, because you create a context instance without attach to any baseContext, so when access to common resource, you got a NPE.
I guess that you are trying to move to a new Fragment or Actvity? Then read these link start activity switch fragment