Android pass variable from Java activity to Kotlin adapter - android

I don't know why I'm blanking on this... but I've got a java activity which displays comments... and I need to pass the id of the photo that's being commented onto the adapter that gets all of the comments. The adapter is called CommentGrabber:
commentGrabber = new CommentGrabber(this);
...and it's executed like this:
private void requestComment() {
commentGrabber.getComment();
}
The "id" variable of the current photo can be had at any time by getting its intent but I've saved it to a string called "photo_id."
final String photo_id = getIntent().getStringExtra("id");
This is what the adapter side looks like:
fun getComment(String photo_id) {
//this is where the function is handled
}
So I just need to figure out how to get the "photo_id" from my comment activity to "getComment" in the adapter.

I would have the adapter method expect an argument like below:
fun getComment(photo_id : String) {
// from there then pass the photo_id to the service call
}
You would then call it like so:
adapter.getComment(photo_id);
Whenever you want to fetch comments by id.
I hope this makes sense. If you need further clarification, please do not hesitate to ask.

Related

ViewModel not updating the view on postValue

I used the lifecycle callback onCreate to fetch data like below
mWeOutViewModel.getPlaceListLiveData()
.observe(this, weOutItemViewModels -> {
AppLogger.i(getCustomTag() + "adding items " + weOutItemViewModels.size());
if (weOutItemViewModels != null && weOutItemViewModels.size() > 0)
mWeOutListAdapter.addToExisting(weOutItemViewModels);
});
As you can see the AppLogger output the initial size which is 0 when the fragment is displayed, then I fetch the data and call postValue (setValue crashes the app and it expected because I fetch data from the internet using a background thread). So I call post value like below :
private void updatePlaces(List<WeOutGroupedViewModels> weOutGroupedViewModels) {
List<WeOutGroupedViewModels> oldList = placeMutableLiveData.getValue();
oldList.addAll(weOutGroupedViewModels);
AppLogger.i(TAG +" updating places "+oldList.size());
placeMutableLiveData.postValue(oldList);
}
As you can see the other AppLogger before postValue, the size of the list is displayed(not empty), but nothing happens until the app crashes and nothing is shown in the logs. I have no ways of debugging since even on debug mode nothing happens. The post value doesn't trigger the observer.
I initialize the mutableLivedata like this :
private final MutableLiveData<List<WeOutGroupedViewModels>> placeMutableLiveData = new MutableLiveData<>();
and access like this :
public LiveData<List<WeOutGroupedViewModels>> getPlaceListLiveData() {
return placeMutableLiveData;
}
Event when I make the livedata public to access directly the livedata, there is no change (just in case someone thinks that's is where the issue comes from)
Instead of placeMutableLiveData.postValue(oldList);
I recommend using
placeMutableLiveData.postValue(Collections.unmodifiableList(new ArrayList<>(newList));
That way, the next time you access this list, you won't be able to mutate it in place, which is a good thing. You're not supposed to mutate the list inside a reactive state holder (MutableLiveData).
So theoretically it should look like this:
private void updatePlaces(List<WeOutGroupedViewModels> weOutGroupedViewModels) {
List<WeOutGroupedViewModels> newList = new ArrayList<>(placeMutableLiveData.getValue());
newList.addAll(weOutGroupedViewModels);
AppLogger.i(TAG +" updating places "+newList.size());
placeMutableLiveData.postValue(Collections.unmodifiableList(newList));
}

Best approach to waiting on pending live data using architecture components

I'm working on an application that fetches data from a graphql server via apollo-android.
I do a single fetch on my aws rds database. I do this fetch right at the onCreate() of my CalendarFragment.
The thing is, at onViewCreated(), I want to set my textview to one of the fields that is fetched, first and last name. So, I run my getBarberFullName method which returns the String value of mBarberFullName. I'm trying to follow the UI controller displays while the view model handles all the logic approach. getBarberFullName resides within my ViewModel.
public String getBarberFullName() {
if (appointmentsAreNull()) return mBarberFullName.getValue();
AppointmentModel am = mMasterAppointments.getValue().get(0);
String fullName = am.bFirstName;
fullName = fullName.concat(" " + am.bLastName);
// Get the logged in barber's full name and set it as mBarberFullName.
mBarberFullName.setValue(fullName);
return mBarberFullName.getValue();
}
where mMasterAppointments is a MutableLiveData<List<AppointmentModel>>. In my onViewCreated() callback, I run
String barberName = mBarberViewModel.getBarberFullName();
mTxtv_barberName.setText(barberName);
However, mMasterAppointments is always null so it just returns the default value of mBarberFullName which is a String.
However, if I were to run the following code, in the same onViewCreated(), I get the desired result where the textview is updated with the desired barber's full name.
mBarberViewModel.getAllAppointments().observe(getViewLifecycleOwner(), am -> {
if (am.isEmpty()) {
Log.d(TAG, "No barber.");
return;
}
String barberGreeting;
barberGreeting = am.get(0).bFirstName;
barberGreeting = barberGreeting.concat(" " + am.get(0).bLastName);
mTxtv_barberName.setText(barberGreeting);
});
getAllAppointments returns an observer to mMasterAppointments located in my ViewModel.
Although getAllAppointments and getBarberFullName are called within onViewCreated(), one is able to access the pending values of mMasterAppointments while the other is not. Why?
I don't want to do the logic in my Fragments onViewCreated callback, so how can I wait on the pending mMasterApointmentData in my ViewModel's getBarberFullName()? Are there tools within LiveData and ViewModel that would aid me in this situation?
Use LiveData's Transformations class
when you need to perform calculations, display only a subset of the
data, or change the rendition of the data.
First add a new String LiveData for BarberFullName in the viewmdoel, and give it the value of transforming (mapping) the source LiveData mMasterAppointments into the desired String:
val fullBarberName: LiveData<String> = Transformations.map(mMasterAppointments) { am ->
" ${am[0].bFirstName} ${am.get(0).bLastName}"
}
Now you can observe this String LiveData in your fragment, the way you in did your second snippet.
Note that the code I provided is in Kotlin, I use it nowadays. I hope you get it.

Unable to get ViewModel instance in RecyclerView.Adapter class Kotlin

I'm new to Kotlin and trying to create an alarm clock app. In this app I'm using LiveData and RecycleView. Right now I need to change the alarm status:
Here is my AlarmsRecyclerAdapter where i tried to create .onClickListener{}
override fun onBindViewHolder(holder: AlarmsRecyclerAdapter.AlarmItemHolder, position: Int) {
//mAlarmViewModel = ViewModelProviders.of( context as Fragment)[AlarmViewModel::class.java]
if (mAlarms != null) {
val current = mAlarms!!.get(position)
holder.view.edit_time_button.text = current.printTime()
holder.view.switch_alarm_enabled.isEnabled = current.enabled
holder.view.switch_alarm_enabled.setOnClickListener {
current.enabled = !current.enabled
// mAlarmViewModel.insert(current)
}
} else {
// Covers the case of data not being ready yet.
holder.view.edit_time_button.text = "no timer"
}
}
I also tried to get instance of ViewModel in the comment line, but it just throws errors like
java.lang.ClassCastException: android.app.Application cannot be cast to androidx.fragment.app.FragmentActivity
at com.xxx.alarm.AlarmsRecyclerAdapter.onBindViewHolder(AlarmsRecyclerAdapter.kt:58)
at com.xxx.alarm.AlarmsRecyclerAdapter.onBindViewHolder(AlarmsRecyclerAdapter.kt:33)
I need to change the alarms in the database, so how can I get an instance of ViewModel in the adapter class? Or is there better way to manage the data changing?
Not really sure about getting your ViewModel inside your RecyclerView, and not really sure if this would be considered best practice. But here is the way I am doing this, and have others seen doing it.
First you create your ViewModel in you Fragment.
Then you observe your AlarmData and when it changes you update the data in your RecyclerAdapter.
So in your Fragment you do something like this():
mAlarmViewModel = ViewModelProviders.of( context as Fragment)[AlarmViewModel::class.java]
mAlarmViewMode.getAlarms().observe(...
mAdapter.setData(newData)
and inside you Adapter you add the following:
setData(data:List) {
mAlarms= data;
notifyDataSetChanged();
}
this should keep your data updated.
Now for the changing of your data.
Try Setting the OnclickListener inside your ViewHolder, as this is going to increase the speed of your app.
to get your current value you could do this:
val current = mAlarms!!.get(getAdapterPosition())
Finally you shold add a Interface to your Adapter, something like this:
interface ItemSelectedListener {
fun onItemSelected(item:Any, v:View)
}
Set this interface from your Fragment and call it from the onClickListener.
Then you have all the data you need inside your Fragment and can modify it from there

Pass data from Activity to class

I'm trying to change Roman's Nurik WizardPager so that in one of the steps display some data from my database.
I'm taking a Model and an UI from the library and I modify them so I can have a
DisplayOrderPage with a parameter ArrayList for my data
public DisplayOrderPage(ModelCallbacks callbacks, ArrayList<Salads> ord , String title) {
super(callbacks, ord, title);
}
and a DisplayOrderFragment which is going to display the data.
I can get an ArrayList with my data from my database in the MainActivity but I don't know how to pass that data to the SandwichWizardModel since it's not an Activity.
you can do one thing.. also pass the context of the activity as parameter. And declare a method in the activity which change the gui within a handler .. like this
in Activity
changeGUI(){
new Handler().post(new Runnable(){
// change gui
}
}
and call like
methodInCLasse(this, arrayList);

Adding items to Array List with specified objects

I am working in a translator kind of app and i need some help.
I have a class with getters and setters for my Array List objects. Each object has a phrase, a meaning, and usage.
so i have this to create my list:
ArrayList<PhraseCollection> IdiomsList = new ArrayList<PhraseCollection>();
now how do i add these objects to the list, each object containing the phrase, its meaning, and a use in a sentence?
For Example: The Layout would be something like this
Phrase
Kick the bucket
Meaning
When someone dies
Usage
My grandfather kicked the bucket
Thanks a lot
this is what i came up with that worked for me
private void loadIdioms() {
//creating new items in the list
Idiom i1 = new Idiom();
i1.setPhrase("Kick the bucket");
i1.setMeaning("When someone dies");
i1.setUsage("My old dog kicked the bucket");
idiomsList.add(i1);
}
ArrayList has a method call add() or add(ELEMENT,INDEX);
In order to add your objects you must first create them
PhraseCollection collection=new PhraseCollection();
then create the ArrayList by
ArrayList<PhraseCollection> list=new ArrayList<PhraseCollection>();
add them by :
list.add(collection);
Last if you want to render that in your ListView item, you must override the toString() in your PhraseCollection.
I suppose you would use the add(E) method (http://docs.oracle.com/javase/6/docs/api/java/util/ArrayList.html#add(E)).
Here is an example using your example provided.
public class Phrase {
public final String phrase, meaning, usage;
//TODO: implement getters?
public Phrase(String phrase, meaning, usage) {
this.phrase = phrase;
this.meaning = meaning;
this.usage = usage;
}
}
and use it like this:
// create the list
ArrayList<Phrase> idiomsList = new ArrayList<Phrase>();
// create the phrase to add
Phrase kick = new Phrase("kick the bucket", "When someone dies", "My grandfather kicked the bucket");
// add the phrase to the list
idiomsList.add(kick);

Categories

Resources