In my application I have two fragments Fragment Card, Fragment Note. I am using ViewPager and TabLayout to sliding between two fragments. I want to implement a search function in my application.
This is my MainActivity class in Kotlin
class MainActivity : AppCompatActivity() {
private lateinit var viewPager:ViewPager
private lateinit var tabLayout:TabLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
//toolbar.title = "Cards"
initComponent()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
val sv: SearchView = menu!!.findItem(R.id.action_bar_search).actionView as SearchView
val sm = getSystemService(Context.SEARCH_SERVICE) as SearchManager
sv.setSearchableInfo(sm.getSearchableInfo(componentName))
sv.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(p0: String?): Boolean {
//loadQuery("%"+p0+"%")
return false
}
override fun onQueryTextChange(p0: String?): Boolean {
//loadQuery("%"+p0+"%")
return false
}
})
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
if (item != null) {
when (item.itemId) {
R.id.sort -> {
Toast.makeText(context, "sort note", Toast.LENGTH_SHORT).show()
}
R.id.settings -> {
Toast.makeText(context, "settings note", Toast.LENGTH_SHORT).show()
}
}
}
return super.onOptionsItemSelected(item)
}
private fun initComponent() {
viewPager = findViewById(R.id.view_pager)
setupViewPager(viewPager)
tabLayout = findViewById(R.id.tab_layout)
tabLayout.setupWithViewPager(viewPager)
viewPager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
override fun onPageSelected(position: Int) {
changeFabIcon(position)
toolbar.title = tabLayout.getTabAt(position)!!.text.toString()
super.onPageSelected(position)
}
})
fabT.setOnClickListener {
//var text = ""
when (viewPager.currentItem) {
0 -> {
// open add new card page
startActivity(Intent(this, AddCardActivity::class.java))
//text = "Add Card"
}
1 -> {
// open add new note page
startActivity(Intent(this, AddNoteActivity::class.java))
//text = "Add note"
}
}
//Toast.makeText(applicationContext, text, Toast.LENGTH_SHORT).show()
}
}
private fun changeFabIcon(index: Int) {
fabT.hide()
Handler().postDelayed({
when(index) {
0 -> {
fabT.setImageResource(R.drawable.ic_card)
}
1 -> {
fabT.setImageResource(R.drawable.ic_note)
}
}
fabT.show()
}, 400)
}
private fun setupViewPager(view_pager: ViewPager) {
val mAdapter = ViewPagerAdapter(supportFragmentManager)
mAdapter.addFragment(FragmentCard(), "Cards")
mAdapter.addFragment(FragmentNote(), "Notes")
view_pager.adapter = mAdapter
}
internal inner class ViewPagerAdapter(manager: FragmentManager) : FragmentPagerAdapter(manager) {
private val mFragmentList = ArrayList<Fragment>()
private val mFragmentTitleList = ArrayList<String>()
override fun getItem(position: Int): Fragment {
return mFragmentList[position]
}
override fun getCount(): Int {
return mFragmentList.size
}
fun addFragment(fragment: Fragment, title: String) {
mFragmentList.add(fragment)
mFragmentTitleList.add(title)
//fragment.arguments = args
}
override fun getPageTitle(position: Int): CharSequence? {
return mFragmentTitleList[position]
}
}
}
This is my FragmentNote class in Kotlin
class FragmentNote: Fragment() {
private var listNotes = ArrayList<Note> ()
private lateinit var mRecyclerViewNote: RecyclerView
private lateinit var mAdapterNote: RecyclerViewAdapterNote
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val v = inflater.inflate(R.layout.note_fragment, container, false)
mAdapterNote = RecyclerViewAdapterNote(context!!, listNotes, this)
mRecyclerViewNote = v.findViewById(R.id.noteRecView) as RecyclerView
mRecyclerViewNote.layoutManager = LinearLayoutManager(context)
mRecyclerViewNote.addItemDecoration(DividerItemDecoration(context, LinearLayoutManager.VERTICAL))
mRecyclerViewNote.adapter = mAdapterNote
setHasOptionsMenu(true)
NoteLoadQuery("%")
return v
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_main, menu)
super.onCreateOptionsMenu(menu, inflater)
}
private fun NoteLoadQuery(title: String) {
var dbManager = DbManagerNote(context!!)
val projections = arrayOf("ID", "Title", "Description")
val selectionArgs = arrayOf(title)
// sort by title
val cursor = dbManager.Query(projections, "ID like ?", selectionArgs, "ID")
listNotes.clear()
// ascending
if (cursor.moveToLast()) {
do {
val ID = cursor.getInt(cursor.getColumnIndex("ID"))
val Title = cursor.getString(cursor.getColumnIndex("Title"))
val Description = cursor.getString(cursor.getColumnIndex("Description"))
listNotes.add(Note(ID, Title, Description))
} while (cursor.moveToPrevious())
}
mAdapterNote.notifyDataSetChanged()
}
}
and finally this is my FragmentCard class
class FragmentCard: Fragment() {
private var listCards = ArrayList<Card>()
private lateinit var myRecyclerViewCard: RecyclerView
private lateinit var mAdapter: RecyclerViewAdapterCard
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val v = inflater.inflate(R.layout.card_fragment, container, false)
mAdapter = RecyclerViewAdapterCard(context!!,listCards, this)
myRecyclerViewCard = v.findViewById(R.id.cardRecView) as RecyclerView
myRecyclerViewCard.layoutManager = LinearLayoutManager(context)
myRecyclerViewCard.addItemDecoration(DividerItemDecoration(context, LinearLayoutManager.VERTICAL))
myRecyclerViewCard.adapter = mAdapter
setHasOptionsMenu(true)
CardLoadQueryAscending("%")
return v
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_main, menu)
super.onCreateOptionsMenu(menu, inflater)
}
private fun CardLoadQueryAscending(title: String) {
var dbManager = DbManagerCard(context!!)
val projections = arrayOf("ID", "CardName", "CardNum")
val selectionArgs = arrayOf(title)
// sort by title
val cursor = dbManager.Query(projections, "CardName like ?", selectionArgs, "CardName")
listCards.clear()
// ascending
if (cursor.moveToFirst()) {
do {
val ID = cursor.getInt(cursor.getColumnIndex("ID"))
val CardName = cursor.getString(cursor.getColumnIndex("CardName"))
val CardNum = cursor.getString(cursor.getColumnIndex("CardNum"))
listCards.add(Card(ID, CardName, CardNum))
} while (cursor.moveToNext())
}
mAdapter.notifyDataSetChanged()
}
}
I am trying to implement my search view in MainActivity, but I am unable to do. can anyone please give me your valuable suggestions to get my problem solve. thanks in advance.
I have done this, it is quite simple.
Just make your MainActivity own the SearchView. As you already did.
Then make a simple interface
ISearchChangedListener
onTextChanged(newString: String?)
onSearchSubmitted()
Setup your BaseFragment to implement this interface.
Override the implementation in your child fragments of the BaseFragment
Then keep track of mSelectedFragment on PageChanged.
Then you simply call
mSelectedFragment?.onTextChanged(newString)
whenever the parent gets a text changed and handle appropriately.
Related
I use view bidning in my all fragments. and I use Fragment vinding on viewpager. the code is below
class dayspager22 : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
private var _binding: FragmentDayspager22Binding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentDayspager22Binding.inflate(inflater, container, false)
val fragmentList = arrayListOf<Fragment>(
pagertest(),
days_1(),
days_2(),
days_3()
)
val adapter = ViewPagerAdapter(
fragmentList,
requireActivity().supportFragmentManager,
lifecycle
)
binding.views.adapter = adapter
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
}
and I use findViewById on my viewbinding Fragment pages
class pagertest : Fragment() {
private var _binding: FragmentPagertestBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
_binding = FragmentPagertestBinding.inflate(inflater, container, false)
binding.button.setOnClickListener{
val pager = activity?.findViewById<ViewPager2>(R.id.dayspager22)
pager?.currentItem = 1
}
return binding.root
}
}
I check 'pager' data, It's always 'null'. I tried to move setOnClickListener to onViewCreated. but It's not also worked. please help me
I have prepared recyclerview to show pdf files but when I try some functions to put pdfs into recyclerview they didin't show. Is any function to do this?
This is my adapter and here probably all is well
class AdapterKarty(private val fileList: ArrayList<plik>): RecyclerView.Adapter<AdapterKarty.ViewHolder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AdapterKarty.ViewHolder {
val a = LayoutInflater.from(parent.context).inflate(R.layout.karta_pliku,parent, false)
return ViewHolder(a);
}
override fun onBindViewHolder(holder: AdapterKarty.ViewHolder, position: Int) {
var item = fileList[position]
holder.dokument.text = item.Name
}
override fun getItemCount(): Int {
return fileList.size
}
inner class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
var dokument: TextView = itemView.tv_dokment
}
}
In list I use class plik where i declare only name because here i try put name of pdf
class plik( var Name: String?=null){
}
And here I have my main class where I try put those files to recyclerview
class Dokumenty : AppCompatActivity() {
private var stor: FirebaseStorage?=null
private var storageReference = stor?.reference
lateinit var recyclerView: RecyclerView
private lateinit var listaPlikow : ArrayList<plik>
private lateinit var myAdapter: AdapterKarty
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_dokumenty)
stor = FirebaseStorage.getInstance()
recyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.setHasFixedSize(true)
listaPlikow = arrayListOf()
myAdapter = AdapterKarty(listaPlikow)
getFiles()
}
private fun getFiles() {
var pliki = storageReference?.child("Pliki/")
}
}
I can't fill in the date class from the database. I don't understand why it doesn't work, everything seems to be written correctly.
In the initUser function, the date of the User Model class is filled in, but if you write the USER variable to println, it will be empty. Below is the code of the MainActivity class, which has the initUser function
class MainActivity : AppCompatActivity() {
private lateinit var btn_settings: ImageButton
private lateinit var btn_add_friend: ImageButton
private lateinit var btn_search_main: ImageView
private lateinit var search_main: EditText
private lateinit var nickname_main: TextView
private lateinit var Id_main: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initFirebase()
initUser()
init()
initFunc()
btn_settings.setOnClickListener {
val intent = Intent(this, SettingsActivity::class.java)
startActivity(intent)
}
btn_search_main.setOnClickListener {
if (search_main.text.toString() == "Happy") {
val intent = Intent(this, psh::class.java)
startActivity(intent)
}
}
nickname_main.text = USER.username
Id_main.text = CURRENT_UID
println(USER)
}
private fun initFunc() {
if (AUTH.currentUser != null) {
} else {
val intent = Intent(this, LoginActivity::class.java)
startActivity(intent)
}
}
private fun init(){
btn_settings = findViewById(R.id.btn_settings)
btn_add_friend = findViewById(R.id.btn_add_friend)
btn_search_main = findViewById(R.id.btn_search_main)
search_main = findViewById(R.id.search_main)
nickname_main = findViewById(R.id.nickname_main)
Id_main = findViewById(R.id.Id_main)
}
private fun initUser(){
REF_DATABASE_ROOT.child(NODE_USERS).child(CURRENT_UID)
.addListenerForSingleValueEvent(AppValueEventListener{
USER = it.getValue(UserModel()::class.java) ?:UserModel()
})
}
fun initFirebase(){
AUTH = FirebaseAuth.getInstance()
REF_DATABASE_ROOT = FirebaseDatabase.getInstance("https://ert-d167-default-rtdb.europe-west1.firebasedatabase.app").reference
USER = UserModel()
CURRENT_UID = AUTH.currentUser?.uid.toString()
}
}
class AppValueEventListener (val onSuccess:(DataSnapshot)->Unit) : ValueEventListener{
override fun onCancelled(error: DatabaseError) {
}
override fun onDataChange(snapshot: DataSnapshot) {
onSuccess(snapshot)
}
}
data class UserModel(
var id: String = "",
var username: String = ""
)
If you insert the USER variable into print, it will be User Model(id=, username=)
The data in the database is
I would like to add a "delete" button in a RecyclerView showing a list of "Users" present in a Room Database. The button should permit to delete the single user when clicking on the button. I have tried to insert a function in Myviewholder, but when I call it in OnBindViewHolder the error concerns the initialization of the mUserViewModel. Do you have any suggestion on it?
This is the adapter:
class ListAdapterUser: RecyclerView.Adapter<ListAdapterUser.MyViewHolder>() {
private var UserList = emptyList<User>()
private lateinit var mUserViewModel: UserViewModel
class MyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
val button = itemView.findViewById<Button>(R.id.deleteoption)
fun deleteitem(item: User, viewModel: UserViewModel){
button.setOnClickListener{
viewModel.deleteUser(item)
}}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.custom_rowUser, parent, false))
}
override fun getItemCount(): Int {
return UserList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = UserList[position]
holder.itemView.textview_valueUser.text = currentItem.Uservalue.toString()
holder.deleteitem(currentItem, mUserViewModel)
}
fun setUserData(User: List<User>){
this.UserList = User
notifyDataSetChanged()
}
}
Thank you!
Solved obtaining the viewmodel initialized in the fragment passing it with setUserData function. Here the final code:
class ListAdapterUser: RecyclerView.Adapter<ListAdapterUser.MyViewHolder>() {
private var UserList = emptyList<User>()
private lateinit var mUserViewModel: UserViewModel
class MyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
val button = itemView.findViewById<Button>(R.id.deleteoption)
fun deleteitem(item: User, viewModel: UserViewModel){
button.setOnClickListener{
viewModel.deleteUser(item)
}}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.custom_rowUser, parent, false))
}
override fun getItemCount(): Int {
return UserList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = UserList[position]
holder.itemView.textview_valueUser.text = currentItem.Uservalue.toString()
holder.deleteitem(currentItem, mUserViewModel)
}
fun setUserData(User: List<User>, viewModel: UserViewModel)){
this.UserList = User
this.mUserViewModel = viewModel
notifyDataSetChanged()
}}
I'm using retrofit to login to my API, but if, for example, I insert a wrong password and try to login again, the service is not called again.
It seems that the second call gets "stuck" in the repository, never reaches the service.
This is my first android app and i'm struggling with this situation.
Tks in advance for any help you can provide on this.
This is the code for my app.
DI
class Fiscalizacao : Application(), KodeinAware {
override val kodein = Kodein.lazy {
import(androidModule(this#Fiscalizacao))
bind() from singleton {
Autenticacao(
instance()
)
}
bind<IAutenticacaoDataSource>() with singleton {
AutenticacaoDataSourceImpl(
instance()
)
}
bind<IAuthenticationRepository>() with singleton {
AuthenticationRepositoryImpl(
instance()
)
}
bind() from provider { AutenticacaoViewModelFactory(instance(), instance()) }
}
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
}
}
Service
interface Autenticacao {
#POST("auth")
fun authAsync(#Body user: RequestBody): Deferred<AutenticacaoResponseResource>
companion object {
operator fun invoke(connectivityInterceptor: IConnectivityInterceptor): Autenticacao {
val okHttpClient = OkHttpClient.Builder()
.build()
return Retrofit
.Builder()
.client(okHttpClient)
.baseUrl("http://10.110.100.216/identity/")
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(Autenticacao::class.java)
}
}
}
DataSource
class AutenticacaoDataSourceImpl(
private val autenticacao: Autenticacao
) :
IAutenticacaoDataSource {
private val _authResponse = MutableLiveData<AutenticacaoResponseResource>()
override val authResponse: LiveData<AutenticacaoResponseResource>
get() = _authResponse
override suspend fun auth(user: CredentialsResource?): LiveData<AutenticacaoResponseResource> {
try {
val userJsonObject = JsonObject()
userJsonObject.addProperty(Parameters.USERNAME.value, user?.utilizador)
userJsonObject.addProperty(Parameters.PASSWORD.value, user?.password)
val result = autenticacao
.authAsync(
userJsonObject.toString()
.toRequestBody(contentType = "application/json; charset=utf8".toMediaTypeOrNull())
)
.await()
_authResponse.postValue(result)
} catch (e: Exception) {
Log.e(e.cause.toString(), e.message, e)
}
return authResponse
}
}
Repository
class AuthenticationRepositoryImpl(
private val autenticacaoDataSource: IAutenticacaoDataSource
) : IAuthenticationRepository {
override suspend fun auth(user: CredentialsResource?): LiveData<AutenticacaoResponseResource> {
return withContext(Dispatchers.IO) {
return#withContext autenticacaoDataSource.auth(user)
}
}
}
ViewModel
class AutenticacaoViewModel(
private val authenticationRepository: IAuthenticationRepository,
) : ViewModel() {
lateinit var user:CredentialsResource
val login by lazyDeferred {
authenticationRepository.auth(user)
}
}
View Model Factory
class AutenticacaoViewModelFactory(private val authenticationRepository: IAuthenticationRepository, ) :
ViewModelProvider.NewInstanceFactory() {
#Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return AutenticacaoViewModel(authenticationRepository) as T
}
}
Coroutines
fun <T> lazyDeferred(block: suspend CoroutineScope.() -> T): Lazy<Deferred<T>>{
return lazy {
GlobalScope.async(start = CoroutineStart.LAZY) {
block.invoke(this)
}
}
}
class AutenticacaoFragment : ScopedFragment(), KodeinAware {
override val kodein by closestKodein()
private val authViewModelFactory: AutenticacaoViewModelFactory by instance()
private lateinit var viewModel: AutenticacaoViewModel
val gson = Gson()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding: AutenticacaoFragmentBinding =
DataBindingUtil.inflate(inflater, R.layout.autenticacao_fragment, container, false)
binding.model =
AppGlobalObject
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProvider(this, authViewModelFactory)
.get(AutenticacaoViewModel::class.java)
mAutenticacao.setOnClickListener(listenerService)
}
private val listenerService =
View.OnClickListener {
when (it.id) {
R.id.mAutenticacao -> {
login(this.requireContext())
}
}
}
private fun login(context: Context) = launch {
viewModel.user = gson.fromJson(
gson.toJson(AppGlobalObject.autenticacao.user),
CredentialsResource::class.java
)
val result = viewModel.login.await()
result.observe(viewLifecycleOwner, Observer { response ->
if (response == null) return#Observer
val login = Utilities().validateStatusCodeOK(response.error)
when {
login -> {
Utilities().setLoginStatus(login, context)
}
else -> {
mPassword.error = "Erro no Login"
}
}
})
}