ViewModel method does not call every time onCreate method is called - android

My application fetches data from API and populates the recycler view with food's categories image and name. When I click on any image then another activity will open and the second activity will show a list of food of that category. But when I open any category then it's working for the first time but if I press back or Up button came back to the MainAcivity and tap on any other Category then the food items on the Second activity is not changing(ViewModel's method is not getting called).
See the Full Code on GitHub: https://github.com/harshabhadra/Foodie/tree/master/app/src/main
This is MainAcivity's onClick method. I am sending the category name via Intent:
#Override
public void onItemClick(int item) {
Intent categoryIntent = new Intent(MainActivity.this,
CategoryActivity.class);
categoryIntent.putExtra("name", foodAdapter.getFood(item));
startActivity(categoryIntent);
}
This is my second Activity:
Intent intent = getIntent();
Food food = intent.getParcelableExtra("name");
category = food.getFoodName();
setTitle(category);
foodViewModel = ViewModelProviders.of(this).get(FoodViewModel.class);
foodViewModel.getFoodCategory(category).observe(this, new
Observer<List<FoodCategory>>() {
#Override
public void onChanged(List<FoodCategory> foodCategories) {
if (!foodCategories.isEmpty()) {
progressBar.setVisibility(View.GONE);
categoryAdapter = new
CategoryAdapter(CategoryActivity.this, foodCategories);
recyclerView.setAdapter(categoryAdapter);
Log.e(TAG, "Category Name: " + category);
}else {
Toast.makeText(CategoryActivity.this, "empty list",
Toast.LENGTH_SHORT).show();
}
}
});
I'm expecting to see a different list of foods in the Second Activity according to the category when I tap on that category in MainAcivity.

What's happening is that you are calling loadData(category) in your repository when categoryData is null, i.e. the first time it runs. Afterwards it returns the same livedata without loading on the new category data.
You just need to move loadData outside the if. Or what you could actually do is to initialize lazily categoryData and get rid of the if.

Related

Android RecyclerView onClick with JSON

I want to transfer to another fragment the item that I clicked on my recyclerview. I don't know how to transfer the data that I clicked on my recyclerview to another fragment. Here's my code. The data is from my JSON.
public void onBindViewHolder(ViewHolder holder, int position) {
final ListItem listItem = listItems.get(position);
holder.textViewHead.setText(listItem.getHead());
holder.textViewDesc.setText(listItem.getDesc());
Picasso.with(context)
.load(listItem.getImgUrl())
.into(holder.imageViewElliptic);
holder.relativeLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "You clicked " + listItem.getHead(), Toast.LENGTH_LONG).show();
}
});
}
Well, first you should store your data either in a List or some other accessible data object, and I think you are doing that already since you created your adapter.
Well, you have this line:
public void onBindViewHolder(ViewHolder holder, int position) {
You can get the data from your List or something else by using the position provided by the method, like this:
YourJsonData data = yourDataSource.get(holder.getAdapterPosition());
Since you are using an onClickListener you should not call position directly, this might cause issues.
For example, in my project I use Lesson[] as my data source:
https://github.com/gi097/MyWindesheim/blob/master/app/src/main/java/com/giovanniterlingen/windesheim/view/Adapters/ScheduleAdapter.java
Once you get the data you can Intent a new Activity which creates the fragments for you. Alternatively, if there is already a Fragment present, you can update that one by notifying your Activity which then updates that particular Fragment.
Use Intent in onClick and send the whole ArrayList to the next activity
Intent intent = new Intent(context, AnotherActivity.class);
intent.putExtra("model", arrayList.get(position));
context.startActivity(intent);
And receive it in next Activity by using this code snippet.
Intent i = getIntent();
ArrayModel arrayModel = (ArrayModel) i.getSerializableExtra("model");
if (arrayModel != null) {
String head = arrayModel.getHead();
Log.d("HEAD", head);
}

Android Java - Passing data between intents but need to save it on main activity

I have an app that for right now, consists of 2 buttons (will later consists of 20+). When I click on a button, it takes me to a new activity that has a list of items I can select. After selecting something and clicking the Back button, it starts a new activity that passes on the item's information (in this case, "orange") and then it assigns the word "orange" to the button that was clicked.
Now when I click on the other button to assign it's information, I lose all of my first button information. What are my options for saving the previous information? Would I have to create an intent for it and keep passing it back and forth between actvities?
At the end, I need to collect all the information that was assigned to both buttons and pass that onto another activity, as this is just the customizing page. Is there a way I can just have the Strings set such that leaving the activity won't delete the String information?
Here's my MainActivity
Bundle extras = getIntent().getExtras();
if (extras != null) {
btnValue = extras.getString("btnValue");
itemValue = extras.getString("itemValue");
}
if (btnValue.equals("btn1")){
btn1.setText(itemValue);
} else if (btnValue.equals("btn2")) {
btn2.setText(itemValue);
}
}
public void onClickBtn1(View v) {
Intent myIntent = new Intent(this, Main2Activity.class);
myIntent.putExtra("btn", "btn1");
startActivity(myIntent);
}
public void onClickBtn2(View v) {
Intent myIntent = new Intent(this, Main2Activity.class);
myIntent.putExtra("btn", "btn2");
startActivity(myIntent);
}
and my 2nd activity
Bundle extras = getIntent().getExtras();
if (extras != null) {
btnValue = extras.getString("btn");
}
listView = (ListView) findViewById(R.id.list);
String[] values = new String[] { "apple", "banana", "orange", "cherry"};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1, values);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
itemPosition = position;
itemPositionString = String.valueOf(itemPosition);
}
});
}
public void onClickBack (View v) {
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("btnValue", btnValue);
intent.putExtra("itemValue", itemValue);
startActivity(intent);
}
You can use the Android lifecycle to manage the activity's state.
To save the activity state you need to do your work on the method onSaveInstanceState.
onSaveInstanceState(Bundle bundle)
On restoration you either check the bundle the following methods
onRestoreInstanceState(Bundle bundle)
onCreate(Bundle bundle)
You can find more details here:
https://developer.android.com/training/basics/activity-lifecycle/recreating.html
When you use startActivity it creates new activity. So you lose old information. You need to use startActivityForResult from MainActivity while starting second activity and from the second activity you should use setResult
Intent returnIntent = new Intent();
returnIntent.putExtra("result",result);
setResult(RESULT_OK, returnIntent);
finish();
And you handle the result in MainActivity with
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
..
..
}
Here, there is an example How to manage `startActivityForResult` on Android?
You basically have 3 choices:
Pass all data in the Intent and return any new/changed data in another Intent using startActivityForResult().
Save the data in a static variable somewhere (globals). All activities can then reference the current data and make changes to it that are then seen by all other activities. This is the quick-and-dirty solution which is suitable for small, trivial or "homework" solutions.
Save the data in a persistent storage (a file or an SQLite database). All activities can read all the current data, display it and make changes. After the BACK button is pressed, the underlying Activity should read the current data from the persistent storage to refresh the views.

delete item from Activity after receive it in Fragment / Lifecycle issue

I need some help. I've got activity where I create item. Next I want to send it to the fragment in second activity so I need to firstly send it to that Activity (am I correct ?). This is how I create item :
public void savePart() {
Part part = new Part(name,quantity,"","",tag,"","2");
Intent intent = new Intent(this,InvActivity.class);
intent.putExtra("Part", (Serializable) part);
setResult(2,intent);
finish();
}
This is how I receive it in second activity:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == 2) {
part = (Part) data.getSerializableExtra("Part");
}
}
I've got method to return the part in fragment :
public Part getMyData() {
return part;
}
In Fragment's onResume() I receive the Part object, check if object with similar code exists and add it to the ListView if not:
#Override
public void onResume() {
super.onResume();
List<Part>subList = new ArrayList<>();
if (mActivity.getMyData() != null) {
Part part = mActivity.getMyData();
for(Part parts : mParts) {
if (parts.getCode().contains(part.getCode())) {
subList.add(parts);
}
}
if (subList.size() == 0) {
mParts.add(part);
adapter = new PartAdapter(getContext(), R.layout.part_item, mParts, mActivity, new AdapterCallback() {
#Override
public void onMethodCallback() {
}
});
mPartsLV.setAdapter(adapter);
} else {
Toast.makeText(getContext(), R.string.equipment_exists, Toast.LENGTH_SHORT).show();
}
}
}
So far everything works well. items are added correctly and shown in ListVIew in fragment.Here is where the problem begins :) In listView row I've got imageView which deletes item from ListView.
mDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mParts.remove(part);
notifyDataSetChanged();
}
});
That works great to but ... when fragment comes back to onResume() deleted item shows again is ListView. That is because each time I receive Part and check if exists in List. I think I should somehow clear intent after receiving Part from Activity where Part was created but I don't know how ? Maybe any other solution,please ?
Declare your subList as public and populate it once. So you need to modify your onResume function a bit. Check if the list is populated already. If not, populate the list from the extras and vice versa.
ListsubList = new ArrayList<>();
your list is created every time when onResume() called that's why delete entries could not managed. So either take a copy of this list or every time check which elements got deleted,and then set data to listview.

How to pass value via Intent form 1st activity to third?

I need to pass some value from 1st activity into the third. I already pass it form 1st to 2nd like this.
my 1st activity: (I do it in on create method)
mainListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(DisplayRecepit.this, DisplayLogs.class);
intent.putExtra("recepitID", receiptList.get(position).getId());
startActivity(intent);
}
});
And I recieved it in 2nd activity like this: (I do it in on create method)
final long forwardedId = (long) getIntent().getExtras().get(String.valueOf("recepitID"));
List<Logs> logsList = new Select().from(Logs.class).where("Receipt = " + forwardedId).execute();
Now I need somehow pass it from 2nd activity to my third activity.
In my 2nd activity I have a button that takes me to 3rd activity.
I saw some examples on web but I didn't make my app working, so any help is welcome.
Question: I have pass value via intent from 1st activity to 2nd activity. How should I pass this same value from 2nd activity to my 3rd activity?
In your second activity pass this value using intent
Intent i = new Intent(getApplicationContext, Third.class);
i.putExtra("forwardedId",forwardedId);
startActivity(i)
First you have to pass data to 2nd Activity.then you can pass from 2nd to 3rd Activity.
Using default android mechanism its not possible. Still if you cant to achieve this you can use Eventbus : "https://github.com/greenrobot/EventBus" where you post message (can be anything a string, integer, even a class pojo with arrylist) from first activity and catch it anywhere.
Go to above mentioned link add the dependency in your app level build.gradle and sync it.
Create this event Pojo :
public class SomeEvent {
private ArrayList<String> message;
public SomeEvent(ArrayList<String> message) {
this.message = message;
}
public ArrayList<String> getMessage() {
return message;
}
}
Activity 1 :
in onResume() do this :
EventBus.getDefault().register(this);
in onDestroy() do this :
EventBus.getDefault().unregister(this);
to post an event :
Do this only after Eventbus registration.
EventBus.getDefault().post(new SomeEvent(some arraylist);
Now in Activity 3:
just write this method. Don't call it explicitly. Eventbus handles that internally. Make sure the argument of this method is your event class which you post in Eventbus.
public void onEvent(SomeEvent event){
// you got your arraylist which you posted from Activity 1;
ArrayList<String> list = event.getMessage();
}

How to catch the result of an intent in Listview's CustomListAdapter class in android

I have an ArrayList which has objects of type Person. Person class has fields name, address1, address2, city, state, postcode and country. I want to be able to edit a particular person and then update the changes such that the ListAdapter which displays the Persons shows updated data. This ListView is contained in RecipientActivity (Activity A)
In the custom Adapter I start the Activity RecipientAddressActivity (Activity B) using an intent in the TextView's onClick event:
holder.txtRecName.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent rec_Intent = new Intent(context,
RecipientAddressActivity.class);
rec_Intent.putExtra("Current_Recipient",
recipientArray.get(index));
rec_Intent.putExtra("RecipientIndex",index);
context.startActivity(rec_Intent);
}
});
In the Activity B I get the Current_Recipient and the index in onCreate() event like this:
current_rec = (Person) getIntent().getSerializableExtra(
"Current_Recipient");
Recipient_Index = getIntent().getIntExtra("RecipientIndex", 151);
In the same activity, I have a button "Save" and on its Onclick I create a Person object which can be either a new Person or an old person being edited.
Button Save's onClick() event
{
Intent Recipient_info = new Intent();
Person recipient = new Person(edt_rec_name.getText().toString(),
edt_rec_addr1.getText().toString(),edt_rec_addr2.getText().toString(),
edt_rec_city.getText().toString(), edt_rec_state.getText().toString(),
edt_rec_pcode.getText().toString(), edt_rec_country.getText().toString());
Recipient_info.putExtra("Person", recipient);
Recipient_info.putExtra("RecipientIndex", Recipient_Index);
setResult(RESULT_OK, Recipient_info);
finish();
}
The problem is there are 2 ways of starting Activity B. I don't know where or how to catch the result when Actvity B is started using ListView's Adapter.
Please help me asap. Kindly let me know if some more code or explanation is required.
Thanks.
I have noticed that in your code:
you are not starting activity as activityForResult.
check that and try now! if you still face this problem than here are some links, that will be useful in your problem:
calling onActivityResult from CustomArray adapter
onActivityResult in not called in the class extended from ArrayAdapter
How to add item in Custom listView in onActivityResult method?
How to Call onActivityResult in adapter listview?

Categories

Resources