variable value gets null in retrofit - android

I have a fragment which has an adapter. I am using retrofit to fetch data from web
my frangment
class MyTransactionFragment : Fragment() {
val disposable = CompositeDisposable()
var transactionDetailList:ArrayList<TransactionData>? = null
private var mApiSocket: ApiSocket? = null
private var mRecyclerView:RecyclerView? = null
var adapter:TransactionAdapter? = null
companion object {
val TAG = ItemFragment::class.java.simpleName!!
fun newInstance(transactionPojo: TransactionPojo): MyTransactionFragment {
val fragment = MyTransactionFragment()
val args = Bundle()
args.putSerializable(Constants.TRANSACTIONS, transactionPojo)
fragment.arguments = args
return fragment
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_my_transaction, container, false)
mApiSocket = Utils().getApiSocket(activity!!)
val layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
view.mRecyclerViewTransaction.layoutManager = layoutManager
view.mRecyclerViewTransaction.setHasFixedSize(true)
if (arguments!=null && arguments!!.getSerializable(Constants.TRANSACTIONS) != null){
val transactionPojo = arguments!!.getSerializable(Constants.TRANSACTIONS) as TransactionPojo
transactionDetailList = ArrayList(transactionPojo.transactions.data)
adapter = TransactionAdapter(transactionDetailList, activity!!,disposable)
view.mRecyclerViewTransaction.adapter = adapter
mRecyclerView = view.mRecyclerViewTransaction
val scrollListener = object : EndlessRecyclerViewScrollListener(layoutManager) {
override fun onLoadMore(page: Int, totalItemsCount: Int, view: RecyclerView) {
disposable.add(mApiSocket!!.transaction(""+page+1)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(MyTransactionFragment()::onResponse,MyTransactionFragment()::onError))
}
}
view.mRecyclerViewTransaction.addOnScrollListener(scrollListener)
}
return view
}
private fun onResponse(transactionPojo: TransactionPojo){
transactionDetailList = ArrayList(transactionPojo.transactions.data)
adapter!!.addData(transactionDetailList) //here adapter variable gets null Why
}
fun onError(e: Throwable) {
Log.e("TransactionFragment", e.toString())
if (e is NoNetWorkException) {
Utils().showSnackBar(activity!!, "No Network connection")
} else
Utils().showSnackBar(activity!!, "Something went wrong please try again later")
Utils().hideProgress()
}
override fun onDetach() {
super.onDetach()
disposable.dispose()
}
}
In this adapter variable in the onResponse getting null Why?

Last I found it
Actually I am calling MyTransactionFragment()::onResponse in subscriber. which means I am putting the result on the new instance of MyTransactionFragment. So I changed this to
disposable.add(mApiSocket!!.transaction(""+page+1)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(::onResponse,::onError))

Related

Clicking on Recyclerview item has a late item

I have an application using databinding, livedata, room, kotlin koroutines, viewmodel, retrofit and koin. I have one activity, and two fragments.
UserListFragment: Show in a recyclerview a list of user items.
UserFullProfileFragment: Show the user item detail.
When the application is running, an external API is called to retrieve a list of users and display it in a recyclerview. Then, if I click on one item, an external API is called to get the detail of the current user whith its ID.
The problem is when I click on one item at the first, everything is going well but for following items, this is the detail of previous item which is displayed and so on and so forth.
Any ideas ?
UserRepository:
class UserRepositoryImpl (private val userApi: UserApi, private val userDao: UserDao, private val networkStateManager: NetworkStateManager) : UserRepository {
override suspend fun getUserList(): Result<List<UserListItem>> {
if (networkStateManager.hasNetWorkConnection()) {
return try {
// get user list from user API
val response = userApi.getUserList()
if (response.isSuccessful) {
Log.d("REPO", "get users from api")
response.body()?.let { userResponse ->
Log.d("REPO", "response:$response")
val userList = userResponse.data
// convert user API object to user entity
val entities = userList.map { it.toUserEntity() }
// save user list in database
withContext(Dispatchers.IO) { userDao.addUsers(entities) }
// convert user entity to user model
val userItemList = entities.map { it.toUserListItem() }
return Result.Success(userItemList)
} ?: handleFailure(response)
} else {
handleFailure(response)
}
} catch (e: Exception) {
return Result.Failure(e, e.localizedMessage)
}
} else {
// get user list from database if no network
val data = withContext(Dispatchers.IO) { userDao.findAllUsers() }
return if (data.isNotEmpty()) {
Log.d("REPO", "get users from db")
val userItemList = data.map { it.toUserListItem() }
Result.Success(userItemList)
} else {
Result.Failure(Exception("error"), "no network connection")
}
}
}
override suspend fun getUserFullProfile(userId: String): Result<UserFullProfile> {
if (networkStateManager.hasNetWorkConnection()) {
return try {
// get user from user API
val response = userApi.getUserFullProfile(userId)
if (response.isSuccessful) {
Log.d("REPO", "get users from api")
response.body()?.let { userResponse ->
Log.d("REPO", "response:$userResponse")
// convert user API object to user entity
val userEntity = userResponse.toUserEntity()
// save user data in database
withContext(Dispatchers.IO) { userDao.addUserFullProfile(userEntity) }
// convert user entity to user model
val user = userEntity.toUserFullProfile()
return Result.Success(user)
} ?: handleFailure(response)
} else {
handleFailure(response)
}
} catch (e: Exception) {
return Result.Failure(e, e.localizedMessage)
}
} else {
// get user from database if no network
val data = withContext(Dispatchers.IO) { userDao.getUserById(userId) }
return if (data != null) {
Log.d("REPO", "get users from db")
val user = data.toUserFullProfile()
Result.Success(user)
} else {
Result.Failure(Exception("error"), "no network connection")
}
}
}
UserViewModel:
getUserList and getUserFullProfile are use cases which call the repository
class UserViewModel (private val getUserList: GetUserList, private val getUserFullProfile: GetUserFullProfile) : ViewModel() {
val userList = MutableLiveData<List<UserListItem>>()
val userFullProfile = MutableLiveData<UserFullProfile>()
fun getUserList() {
viewModelScope.launch {
when (val result = getUserList.getUserList()) {
is Result.Success -> userList.value = result.successData
is Result.Failure -> result.exception.localizedMessage
}
}
}
fun getUserFullProfile(userId: String) {
viewModelScope.launch {
when (val result = getUserFullProfile.getUserFullProfile(userId)) {
is Result.Success -> userFullProfile.value = result.successData
is Result.Failure -> result.exception.localizedMessage
}
}
}
UserRecyclerAdaper:
class UserRecyclerAdapter(private val context: Context?, val clickListener: UserClickListener) : RecyclerView.Adapter<UserRecyclerAdapter.UserViewHolder>() {
var userList : List<UserListItem> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val inflatedView: UserItemBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.context), R.layout.user_item, parent, false)
return UserViewHolder(inflatedView)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
holder.bindUser(position)
}
override fun getItemCount() = userList.size
fun setUsers(users: List<UserListItem>) {
this.userList = users
notifyDataSetChanged()
}
inner class UserViewHolder(private val v: UserItemBinding) : RecyclerView.ViewHolder(v.root) {
fun bindUser(position: Int) {
val item = userList[position]
Log.d("ADAPTER", item.toString())
v.user = item
Picasso.get()
.load(item.picture)
.placeholder(R.drawable.ic_launcher_foreground)
.error(R.drawable.ic_launcher_background)
.into(v.picture)
v.userClickInterface = clickListener
v.root.setOnClickListener {
clickListener.onItemClick(item)
}
}
}
UserListFragment:
class UserListFragment : Fragment(), UserClickListener {
private val userViewModel by viewModel<UserViewModel>()
private lateinit var userAdapter: UserRecyclerAdapter
private lateinit var viewDataBinding: FragmentUserListBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
viewDataBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_user_list, container, false)
viewDataBinding.lifecycleOwner = this
return viewDataBinding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView.layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
userAdapter = UserRecyclerAdapter(context, this)
recyclerView.adapter = userAdapter
recyclerView.isNestedScrollingEnabled = false
viewDataBinding.viewModel = userViewModel
userViewModel.getUserList()
userViewModel.userList.observe(viewLifecycleOwner, { userList ->
if (userList.isNotEmpty() && userList != null) {
userAdapter.setUsers(userList)
}
})
}
override fun onItemClick(user: UserListItem) {
Log.d("FRAGMENT", user.toString())
userViewModel.getUserFullProfile(user.id)
userViewModel.userFullProfile.observe(viewLifecycleOwner, { userFullProfile ->
Log.d("UFP", userFullProfile.toString())
if (userFullProfile != null) {
(activity as MainActivity).replaceFragment(UserFullProfileFragment.newInstance(userFullProfile),
R.id.fragment_layout, "userFullProfile")
}
})
}
UserFullProfileFragment:
class UserFullProfileFragment : Fragment() {
companion object {
#JvmStatic
fun newInstance(user: UserFullProfile) = UserFullProfileFragment().apply {
arguments = Bundle().apply {
putParcelable("user", user)
}
}
}
private var user: UserFullProfile? = null
private lateinit var mViewDataBinding: FragmentUserFullProfileBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mViewDataBinding.user = user
notify()
Picasso.get()
.load(mViewDataBinding.user?.picture)
.placeholder(R.drawable.ic_launcher_foreground)
.error(R.drawable.ic_launcher_background)
.into(mViewDataBinding.picture)
val dateOfBirth = parseDate(mViewDataBinding.user?.dateOfBirth)
mViewDataBinding.dateOfBirth.text = dateOfBirth
val registerDate = parseDate(mViewDataBinding.user?.registerDate)
mViewDataBinding.registerDate.text = registerDate
}
override fun onAttach(context: Context) {
super.onAttach(context)
user = arguments?.getParcelable("user")
Log.d("APP", user.toString())
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
mViewDataBinding = DataBindingUtil.inflate(inflater,
R.layout.fragment_user_full_profile, container, false)
mViewDataBinding.lifecycleOwner = this
return mViewDataBinding.root
}
Thank you :)
Finally, I found a solution :
I pass the user id argment from UserListFragment to UserFullProfileFragment instead of the current user object and I call the external API to get the current user in the UserFullProfileFragment.
This is the final code:
UserListFragment:
override fun onItemClick(user: UserListItem) {
val action = UserListFragmentDirections.actionUserListFragmentToUserFullProfileFragment(user.id)
findNavController().navigate(action)
}
UserFullProfileFragment:
class UserFullProfileFragment : Fragment() {
private lateinit var userID: String
private var mViewDataBinding: FragmentUserFullProfileBinding? = null
private val binding get() = mViewDataBinding!!
private val userViewModel by viewModel<UserViewModel>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.viewModel = userViewModel
userID = UserFullProfileFragmentArgs.fromBundle(requireArguments()).userArgs
userViewModel.getUserFullProfile(userID)
userViewModel.userFullProfile.observe(viewLifecycleOwner, { userFullProfile ->
if (userFullProfile != null) {
binding.user = userFullProfile
Picasso.get()
.load(binding.user?.picture)
.placeholder(R.drawable.ic_launcher_foreground)
.error(R.drawable.ic_launcher_background)
.into(binding.picture)
val dateOfBirth = parseDate(binding.user?.dateOfBirth)
binding.dateOfBirth.text = dateOfBirth
val registerDate = parseDate(binding.user?.registerDate)
binding.registerDate.text = registerDate
}
})
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
mViewDataBinding = DataBindingUtil.inflate(inflater,
R.layout.fragment_user_full_profile, container, false)
binding.lifecycleOwner = this
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
mViewDataBinding = null
}
}

viewModel with two fragments is not working

I am developing an app, where users can add their address in their profile and now I want to add a viewModel observer on the coordinates I am receiving from the profile fragment, like my fragment A and give this information to a map fragment, so I can create a new marker on that location. Apparently I am not getting any information of the observer in my fragment B.
So that is my code:
This is the first fragment of the profile:
class ProfilFoto : Fragment() {
lateinit var mDatabase : DatabaseReference
var mAuth = FirebaseAuth.getInstance()
var user = FirebaseAuth.getInstance().currentUser
var DISPLAY_NAME : String? = null
private var model: Communicator?=null
#SuppressLint("SetTextI18n", "ResourceType")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// setContentView(R.layout.fragment_notifications)
val rootView: View = inflater.inflate(R.layout.fragment_profil_foto, container, false)
model= activity?.let { ViewModelProviders.of(it).get(Communicator::class.java) }
val loca = rootView.findViewById<View>(R.id.locationtext) as TextView
var uid = user!!.uid
val userHashMap = HashMap<String, Any>()
mDatabase = FirebaseDatabase.getInstance().getReference("User").child(uid)
val speicherButton = rootView.findViewById<Button>(R.id.speichern)
speicherButton.setOnClickListener {
val location = rootView.findViewById<View>(R.id.locationPerson) as EditText
val loc = location.text.toString()
if (!loc.isEmpty()) {
Log.e("Location", loc)
val locationAddress = GeocodingLocation()
locationAddress.getAddressFromLocation(loc,
getActivity()?.getApplicationContext(), GeocoderHandler())
model!!.setMsgCommunicator(locationAddress.toString())
//userHashMap["Adresse"] = loc
mDatabase.child("Adresse").setValue(loc)
.addOnSuccessListener {
Log.e("Telefon", loc)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
// mDatabase.updateChildren(userHashMap)
}
}
mDatabase.addValueEventListener(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
return rootView
}
private class GeocoderHandler : Handler() {
override fun handleMessage(message: Message) {
val locationAddress: String?
locationAddress = when (message.what) {
1 -> {
val bundle: Bundle = message.getData()
bundle.getString("address")
}
else -> null
}
if (locationAddress != null) {
Log.e("Handler", locationAddress)
}
}
}
}
And this is the map fragment where the message should appear:
class MapsFragment : Fragment() {
private val callback = OnMapReadyCallback { googleMap ->
val model= activity?.let { ViewModelProviders.of(it).get(Communicator::class.java) }
if (model != null) {
model.message.observe(this, { t ->
//txt.text = o!!.toString()
Log.e("Marker", t.toString())
var latlong = t.toString().split(",")
var lat = parseFloat(latlong[0])
var long = parseFloat(latlong[1])
googleMap.addMarker(
MarkerOptions()
.position(LatLng(lat.toDouble(), long.toDouble()))
.title("Der Neue")
)
})
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val rootView : View = inflater.inflate(R.layout.fragment_maps, container, false)
...
return rootView
}
and this is the communicator class I am using:
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class Communicator : ViewModel(){
val message =MutableLiveData<Any>()
fun setMsgCommunicator(msg:String){
message.setValue(msg)
}
}
and maybe it is important to also show the GeoLocator from where I am getting the coordinates:
private const val TAG = "GeocodingLocation"
public class GeocodingLocation {
lateinit var mDatabase : DatabaseReference
var user = FirebaseAuth.getInstance().currentUser
fun getAddressFromLocation(locationAddress: String,
context: Context?, handler: Handler?) {
val thread: Thread = object : Thread() {
override fun run() {
val geocoder = Geocoder(context, Locale.getDefault())
var result: String? = null
var uid = user!!.uid
mDatabase = FirebaseDatabase.getInstance().getReference("User").child(uid)
try {
val addressList: List<*>? = geocoder.getFromLocationName(locationAddress, 1)
if (addressList != null && addressList.size > 0) {
val address: Address = addressList[0] as Address
val sb = StringBuilder()
sb.append(address.getLatitude()).append("\n")
mDatabase.child("Latitude").setValue(address.latitude)
.addOnSuccessListener {
Log.e("Telefon", address.latitude.toString())
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
sb.append(address.getLongitude()).append("\n")
mDatabase.child("Longtitude").setValue(address.longitude)
.addOnSuccessListener {
Log.e("Telefon", address.longitude.toString())
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
result = sb.toString()
}
} catch (e: IOException) {
Log.e(TAG, "Unable to connect to Geocoder", e)
} finally {
val message: Message = Message.obtain()
message.setTarget(handler)
if (result != null) {
message.what = 1
val bundle = Bundle()
bundle.putString("address", result)
message.setData(bundle)
} else {
message.what = 1
val bundle = Bundle()
result = """Address: $locationAddress
Unable to get Latitude and Longitude for this address location."""
bundle.putString("address", result)
message.setData(bundle)
}
message.sendToTarget()
}
}
}
thread.start()
}
}
Does anybody know what I am doing wrong to get absolutely nothing? Like in the profile fragment I am receiving a latitude and longitude in the Log.
Move the registering observer code, outside the callback block. Inside the callback, set the value when map is ready to update. In the observer check if map is ready, set the marker. Hope that works!
private lateinit var googleMap: GoogleMap
private val callback = OnMapReadyCallback { map ->
googleMap = map
}
val model= activity?.let { ViewModelProviders.of(it).get(Communicator::class.java) }
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val rootView : View = inflater.inflate(R.layout.fragment_maps, container, false)
if (model != null) {
model.message.observe(this, { t ->
//txt.text = o!!.toString()
Log.e("Marker", t.toString())
var latlong = t.toString().split(",")
var lat = parseFloat(latlong[0])
var long = parseFloat(latlong[1])
googleMap?.let{
it.addMarker(
MarkerOptions()
.position(LatLng(lat.toDouble(), long.toDouble()))
.title("Der Neue")
)
})
}
}
return rootView
}

Blank fragment is displayed

I am creating a food ordering app . I am fetching the list of restaurants using volley .
Error:
The restaurant list does not displayed and in the logcat window the following displayed:
E/RecyclerView: No adapter attached; skipping layout
What I have tried to resolve:
used postman to verify volley response,the response is as expected
made sure if the variables were received in the right order
made sure that the array was received in the right format.
I attach the code of the HomeFragment and the adapter file
HomeFragment.class
class HomeFragment : Fragment() {
lateinit var recyclerRestaurant: RecyclerView
lateinit var progressLayout: RelativeLayout
lateinit var progressBar: ProgressBar
lateinit var layoutManager: RecyclerView.LayoutManager
lateinit var recyclerAdapter: RestaurantRecyclerAdapter
var restaurantList = arrayListOf<Restaurant>()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_home, container, false)
setHasOptionsMenu(true)
recyclerRestaurant = view.findViewById(R.id.recyclerRestaurant)
progressLayout = view.findViewById(R.id.progressLayout)
progressBar = view.findViewById(R.id.progressBar)
layoutManager = LinearLayoutManager(activity)
progressLayout.visibility= View.VISIBLE
val queue = Volley.newRequestQueue(activity as Context)
val url = "http://13.235.250.119/v2/restaurants/fetch_result/"
if (ConnectionManager().checkConnectivity(activity as Context)) {
val jsonObjectRequest = object : JsonObjectRequest(
Request.Method.GET,url , null,
Response.Listener<JSONObject>{
progressLayout.visibility = View.GONE
try {
val data = it.getJSONObject("data")
val success = data.getBoolean("success")
if (success) {
val data = it.getJSONObject("data").getJSONArray("data")
for(i in 0 until data.length()) {
val resObject = data.getJSONObject(i)
val restaurants = Restaurant(
resObject.getString("id").toInt(),
resObject.getString("name"),
resObject.getString("rating"),
resObject.getString("cost_per_person"),
resObject.getString("image_url")
)
restaurantList.add(restaurants)
if(activity != null) {
recyclerAdapter = RestaurantRecyclerAdapter(activity as Context, restaurantList)
val mLayoutManager=LinearLayoutManager(activity)
recyclerRestaurant.layoutManager =mLayoutManager
recyclerRestaurant.adapter = recyclerAdapter
recyclerRestaurant.setHasFixedSize(true)
}
}
}
else {
Toast.makeText(
activity as Context,
"some error has occurred",
Toast.LENGTH_SHORT
).show()
}
}catch (e: JSONException){
e.printStackTrace()
}
},
Response.ErrorListener {
if(activity != null){
Toast.makeText(activity as Context,"Volley error has occurred", Toast.LENGTH_LONG).show() }
}) {
override fun getHeaders(): MutableMap<String, String> {
val headers = HashMap<String, String>()
headers["Content-type"] = "application/json"
headers["token"] = "06f579db533924"
return headers
}
}
queue.add(jsonObjectRequest)
}else{
val dialog = AlertDialog.Builder(activity as Context)
dialog.setTitle("error")
dialog.setMessage("Internet connection not found")
dialog.setPositiveButton("open settings"){ text, listener->
val settingsIntent = Intent(Settings.ACTION_WIRELESS_SETTINGS)
startActivity(settingsIntent)
activity?.finish()
}
dialog.setNegativeButton("exit"){text,listener->
ActivityCompat.finishAffinity(activity as Activity)
}
dialog.create()
dialog.show()
}
return view
}
}
RestaurantRecyclerAdapter.class
class RestaurantRecyclerAdapter(val context:Context, val itemList: ArrayList<Restaurant> ):RecyclerView.Adapter<RestaurantRecyclerAdapter.RestaurantViewHolder>() {
class RestaurantViewHolder(view: View): RecyclerView.ViewHolder(view){
val txtRestaurantName :TextView= view.findViewById(R.id.txtRestaurantName)
val imgRestaurantImage :ImageView = view.findViewById(R.id.imgRestaurantImage)
val txtRating : TextView = view.findViewById(R.id.txtRating)
val txtPerPerson : TextView = view.findViewById(R.id.txtPerPerson)
val llContent : LinearLayout = view.findViewById(R.id.llContent)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RestaurantViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.recycler_single_row,parent,false)
return RestaurantViewHolder(view)
}
override fun getItemCount(): Int {
return itemList.size
}
override fun onBindViewHolder(holder: RestaurantViewHolder, position: Int) {
val restaurant = itemList[position]
holder.txtRestaurantName.text = restaurant.name
holder.txtRating.text = restaurant.rating
holder.txtPerPerson.text = restaurant.cost_per_person
Picasso.get().load(restaurant.image).error(R.drawable.ic_food).into(holder.imgRestaurantImage)

LiveData doesn't triggered observing it from Fragment

I've a Fragment that observes a LiveData contained in a ViewModel to pass information in an RecyclerView.Adapter.
LiveData in the Fragment isn't triggered, but if I move it in an Activity, it's triggered.
Here's the code:
class ProfileViewModel : ViewModel() {
private val profileLiveData: MutableLiveData<User> = MutableLiveData(
private val followersPreview: LiveData<Query> =
Transformations.map(profileLiveData) { profile ->usersApi.getFollowers(profile.followers) }
private val followingPreview: LiveData<Query> =
Transformations.map(profileLiveData) { profile -> usersApi.getFollowing(profile.following) }
fun getProfile(userDocumentId: String): LiveData<User> {
usersApi.getProfile(userDocumentId)
.addSnapshotListener { querySnapshot, firebaseFirestoreException ->
if (firebaseFirestoreException != null) {
Log.d("Exception get profile", firebaseFirestoreException.message!!)
// Handle exception
}
val profileUser: User = querySnapshot?.toObject(User::class.java)!!
profileLiveData.value = profileUser
}
return profileLiveData
}
fun getProfileFollowers(): LiveData<Query> {
return followersPreview
}
}
class ListsProfileFragment : Fragment() {
private lateinit var fragmentListsBinding: FragmentListsProfileBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
fragmentListsBinding = FragmentListsProfileBinding.inflate(layoutInflater)
return fragmentListsBinding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val profileViewModel = ViewModelProviders.of(this).get(ProfileViewModel::class.java);
Log.d("Viewmodel", profileViewModel.toString())
profileViewModel
.getProfileFollowers()
.observe(viewLifecycleOwner,
Observer {
it.addSnapshotListener { querySnapshot, firebaseFirestoreException ->
val followers = mutableListOf<UserPreview>()
querySnapshot?.documents?.forEach { doc ->
val follower: UserPreview = UserPreview(
doc.get("username") as String,
doc.get("profileImage") as String
)
followers.add(follower)
}
fragmentListsBinding.recyclerViewFollowers.layoutManager =
LinearLayoutManager(this.activity, RecyclerView.HORIZONTAL, false)
fragmentListsBinding.recyclerViewFollowers.adapter =
AccountsAdapter(followers)
}
})
}
Could anyone help me? Thanks in advance.
Resolved using this code to load the ViewModel:
profileViewModel =
activity?.run { ViewModelProviders.of(this).get(ProfileViewModel::class.java) }
?: throw Exception("Invalid Activity")

search in a recyclerview

i have a fragment that have a recyclerview i'm trying to use setOnQueryTextListener to search some specific data and display the new data instead of the old one
this is my Fragmenttask.kt file
class Fragmenttask : Fragment(), SwipeRefreshLayout.OnRefreshListener {
private var mListener: OnFragmentInteractionListener? = null
private var mSwipeRefreshLayout: SwipeRefreshLayout? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
//container!!.removeAllViews()
setHasOptionsMenu(true)
val CustumViewtask = inflater!!.inflate(R.layout.fragment_fragmenttask, container, false)
val taskMainRV = CustumViewtask.findViewById(R.id.recyclerView_main) as RecyclerView
//taskMainRV.setBackgroundColor(Color.BLUE)
taskMainRV.layoutManager = LinearLayoutManager(context)
//recyclerView_main.adapter = MainAdapter()
fetchJson(taskMainRV)
return CustumViewtask
}
override fun onRefresh() {
Toast.makeText(context, "تم التحميل بنجاح والحمد لله", Toast.LENGTH_LONG).show()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_user, menu)
val searchItem = menu.findItem(R.id.action_search)
val searchView = MenuItemCompat.getActionView(searchItem) as SearchView
searchView.queryHint = "أكتب كلمة بحث ..."
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextChange(q: String): Boolean {
println("my serch : $q")
//fetchJson(taskMainRV)
//adaptertask?.notifyDataSetChanged()
//notifyDataSetChanged
println("mohamed 78797987897987987987987987987987987987897")
return false
}
override fun onQueryTextSubmit(q: String): Boolean {
println("my serch : $q")
println("mohamed 78797987897987987987987987987987987987897**************")
return false
}
})
//searchView.setOnQueryTextListener(this)
//https://stackoverflow.com/questions/30398247/how-to-filter-a-recyclerview-with-a-searchview?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
}
fun onQueryTextChange(query: String): Boolean {
// Here is where we are going to implement the filter logic
return false
}
fun onQueryTextSubmit(query: String): Boolean {
return false
}
fun fetchJson(RSV: RecyclerView) {
//SharedPreferences
val MY_APP_INFO: String = "UserInfo"
val prefs = activity.getSharedPreferences(MY_APP_INFO, AppCompatActivity.MODE_PRIVATE)
val LoggedUserId = prefs.getString("UserId", null)
var serchqury = arguments.getString("serchqury")
if(serchqury.isNullOrEmpty()){
serchqury = ""
}
println(serchqury+" ------------**/*/*/*/*/*/*/*/*/*/ ")
println("your code is : $LoggedUserId")
println("Attempting to Fetch JSON")
val url = "http://www.deraah-rs.com/1mahamatonline/html/Restful/get_tasks.php"
val client = OkHttpClient()
val formBody = FormBody.Builder().add("UserId", LoggedUserId)
.add("serchqury", serchqury).build()
val request = Request.Builder().url(url)
.post(formBody)
.build()
client.newCall(request).enqueue(object: Callback {
override fun onResponse(call: Call?, response: Response?) {
val body = response?.body()?.string()
println("mohamed : $body")
val gson = GsonBuilder().create()
val tasksfeed = gson.fromJson(body, M_tasksFeed::class.java)
activity.runOnUiThread {
RSV.adapter = MainAdaptertasks(tasksfeed)
if(taskfragmentprogressbar != null){
taskfragmentprogressbar.visibility = View.INVISIBLE
}
//ChatAdapter(Context, tasksfeed)
}
}
override fun onFailure(call: Call?, e: IOException?) {
println("Failed to execute request")
}
})
}
// TODO: Rename method, update argument and hook method into UI event
fun onButtonPressed(uri: Uri) {
if (mListener != null) {
mListener!!.onFragmentInteraction(uri)
}
}
companion object {
fun newInstance(): Fragmenttask {
val fragment = Fragmenttask()
val args = Bundle()
fragment.arguments = args
return fragment
}
}
}// Required empty public constructor
......................................................................................................................................

Categories

Resources