Android official documentation on the topic of pasting says:
Get the global ClipboardManager object using getSystemService(CLIPBOARD_SERVICE). Also declare a global variable to contain the pasted text:
var clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
var pasteData: String = ""
When I do the exact same thing on my fragment, it tells me to create getSystemService function. Here's what I did:
My imports (I clicked import on everything Android Studio told me to):
import android.content.ClipboardManager
import android.content.Context
import android.content.Context.CLIPBOARD_SERVICE
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.core.content.ContextCompat.getSystemService
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import com.google.android.material.textfield.TextInputEditText
My code:
class FirstFragment : Fragment() {
var clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
var pasteData: String = ""
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.pgn_page, container, false)
}
private fun pasteText():String {
val abc = clipboard?.primaryClip
val item = (abc?.getItemAt(0))
return item?.text.toString()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//val pgnBar: TextInputEditText = view.findViewById(R.id.pgncode)
val pgnBar: TextInputEditText = view.findViewById(R.id.pgncode)
val clipButton: Button = view.findViewById(R.id.clipboardButton)
pgnBar.setText(PGNCode.value)
clipButton.setOnClickListener{
pgnBar.setText(pasteText())
}
view.findViewById<Button>(R.id.startAnalysisButton).setOnClickListener {
PGNCode.value = pgnBar.getText().toString()
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
}
}
}
What should I change?
getSystemService() is a method in Context and a Fragment is not a Context.
You can use requireContext() to access a fragment's context when it's attached to one. Fragment init phase is too early.
So add the context access and move the
var clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
to a function such as pasteText().
getSystemService is method in Context, use below inside a fragment
var clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
Related
I am working on an Android app using Android Studio.
I want to save the values input into some editText textFields.
These textFields are in a Fragment view? (sorry I am very new to Android coding).
I have tried to use SharedPreferences but keep getting the error.
(Unresolved reference: getSharedPreference).
Here is my code:
import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
class ConnectFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_connect, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<Button>(R.id.button_connect).setOnClickListener {
val serverURIFromEditText =
view.findViewById<EditText>(R.id.edittext_server_uri).text.toString()
val clientIDFromEditText =
view.findViewById<EditText>(R.id.edittext_client_id).text.toString()
val usernameFromEditText =
view.findViewById<EditText>(R.id.edittext_username).text.toString()
val pwdFromEditText =
view.findViewById<EditText>(R.id.edittext_password).text.toString()
val mqttCredentialsBundle = bundleOf(
MQTT_SERVER_URI_KEY to serverURIFromEditText,
MQTT_CLIENT_ID_KEY to clientIDFromEditText,
MQTT_USERNAME_KEY to usernameFromEditText,
MQTT_PWD_KEY to pwdFromEditText
)
findNavController().navigate(
R.id.action_ConnectFragment_to_ClientFragment,
mqttCredentialsBundle
)
val sharedPreferences: SharedPreferences =
getSharedPreferences("MyFacts", MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.putString("UserName", usernameFromEditText)
editor.apply()
}
}
}
Not sure what is up except to think that it is not in the MainActivity view but in a Fragment. But can't figure out how to resolve it. Could someone help me.
Android studio shows errors in the lines
REPOSITORY.insert(note){ onSuccess() }
in the "AddNewNoteFragmentViewModel" and in the lines
viewModel.insert(AppNote(name = name, text = text)){ view?.findNavController()?.navigate(R.id.action_addNewNoteFragment_to_mainFragment)}
in the file "AddNewNoteFragment"
I realized that the error is related to streams, but I do not know how to solve it
If anyone knows, please help, I could not find anything worthwhile on the Internet
AddNewNoteFragment
package com.example.notes.fragments.add_new_note
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.findNavController
import com.example.notes.R
import com.example.notes.databinding.FragmentAddNewNoteBinding
import com.example.notes.model.AppNote
import com.example.notes.utilits.showToast
class AddNewNoteFragment : Fragment() {
private var _binding: FragmentAddNewNoteBinding? = null
val binding get() = _binding!!
private lateinit var viewModel: AddNewNoteFragmentViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentAddNewNoteBinding.inflate(inflater, container, false)
val view = binding.root
return view
}
override fun onStart() {
super.onStart()
initialization()
}
private fun initialization() {
viewModel = ViewModelProvider(this).get(AddNewNoteFragmentViewModel::class.java)
binding.buttonAddNote.setOnClickListener {
val name = binding.inputNameNote.text.toString()
val text = binding.inputTextNote.text.toString()
if (name.isEmpty()){
showToast("Введите имя заметки")
} else{
viewModel.insert(AppNote(name = name, text = text)){
view?.findNavController()?.navigate(R.id.action_addNewNoteFragment_to_mainFragment)
}
}
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
AddNewNoteFragmentViewModel
package com.example.notes.fragments.add_new_note
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.example.notes.model.AppNote
import com.example.notes.utilits.REPOSITORY
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class AddNewNoteFragmentViewModel(application: Application): AndroidViewModel(application) {
fun insert(note: AppNote,onSuccess:()-> Unit) =
viewModelScope.launch (Dispatchers.IO){
REPOSITORY.insert(note){
onSuccess()
}
}
}
Error screen
enter image description here
Problem solved
In AddNewNoteFragmentViewModel requires Dispatchers.IO to be changed to Dispatchers.Main
I am considering a simple example consists of the following component:
MainActivity: has editText, button, viewPager
FragmentA: has nothing
FragmentB: has a textView
So, in the screen, you can swipe to see each fragment. I want my example to have the function: if one writes a text in the editText and click the button then it shows up in Fragment B.
A tried it by using notifyDatsetChanged() but it does not work. Could anyone help? Below is the whole code of mine:
MainActivity.kt
package com.myproject.chapterfivesectionone
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.myproject.chapterfivesectionone.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
lateinit var fragmentB: FragmentB
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
val fragmentList = listOf(FragmentA(), FragmentB())
val adapter = FragmentAdapter(this)
adapter.fragmentList = fragmentList
binding.viewPager.adapter = adapter
binding.buttonSend.setOnClickListener {
var bundle = Bundle()
bundle.putString("key1", binding.editTextWriteSomething.text.toString())
fragmentB.arguments = bundle
adapter.notifyDataSetChanged()
}
}
}
FragmentAdapter.kt
package com.myproject.chapterfivesectionone
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
class FragmentAdapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) {
var fragmentList = listOf<Fragment>()
override fun getItemCount(): Int {
return fragmentList.size
}
override fun createFragment(position: Int): Fragment {
return fragmentList.get(position)
}
}
FragmentA.kt
package com.myproject.chapterfivesectionone
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
class FragmentA : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_a, container, false)
}
}
FragmentB.kt
package com.myproject.chapterfivesectionone
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.myproject.chapterfivesectionone.databinding.FragmentBBinding
class FragmentB : Fragment() {
lateinit var binding: FragmentBBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentBBinding.inflate(inflater, container, false)
if (arguments?.getString("key1") != null) {
binding.textViewInFragmentB.text = arguments?.getString("key1")
}
return binding.root
}
}
Currently, fragmentB is inside fragmentList so you can retrieve it like fragmentList[fragmentBPosition]. Then defind a function inside FragmentB for update the TextView
binding.buttonSend.setOnClickListener {
(fragmentList[1] as FragmentB).updateTheTextView("new")
// if you want code more clean, can replace hard code value by a constant or you can write some logic to find FragmentB from fragmentList
}
FragmentB
class FragmentB : Fragment() {
fun updateTheTextView(newText : String) {
binding.textViewInFragmentB.text = newText
}
}
So I'm trying to create a tabbed app in Kotlin and I have chosen the default one they made for you to practice but I can't figure out how to get the buttons working `
package com.example.android_app.ui.home
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import com.example.android_app.R
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.fragment_home.*
class HomeFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//Program Buttons
logout.setOnClickListener{
val intent = Intent(this, sign_in::class.java)
startActivity(intent)
}
}
private lateinit var homeViewModel: HomeViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
homeViewModel =
ViewModelProviders.of(this).get(HomeViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_home, container, false)
homeViewModel.text.observe(viewLifecycleOwner, Observer {
})
return root
}
}
`
As far as I know this should work. The problem is not in the button but in Intent. My button is already defined and has no errors but there is a red line under Intent even though it's imported. The error message is below.
public constructor Intent(p0: Context!, p1: Class<*>!) defined in android.content.Intent
public constructor Intent(p0: String!, p1: Uri!) defined in android.content.Intent
You need to pass context into the constructor of Intent instead of this.
val intent = Intent(context, sign_in::class.java)
I am passing arguments using safeargs. In the reciving fragment I am getting a compile error: 'Required Bundle Found Bundle?'. Cannot see where the error has crept in.
Googled around, checked text and udacity tutorial
Where error appears (at 'arguments')
package com.example.android.naveditoryoutube
import android.arch.lifecycle.ViewModelProviders
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import kotlinx.android.synthetic.main.fragment_two_fragment.*
class FragmentTwo : Fragment() {
companion object {
fun newInstance() = FragmentTwo()
}
private lateinit var viewModel: FragmentTwoViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_two_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(FragmentTwoViewModel::class.java)
}
override fun onStart() {
super.onStart()
var args = FragmentTwoArgs.fromBundle(arguments)
argText.text = args.calculated_Number
}
}
Sending code:
package com.example.android.naveditoryoutube
import android.arch.lifecycle.ViewModelProviders
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_one_fragment.*
class FragmentOne : Fragment() {
companion object {
fun newInstance() = FragmentOne()
}
private lateinit var viewModel: FragmentOneViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_one_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(FragmentOneViewModel::class.java)
var calculated_Number : String = viewModel.sendNewNumber().toString()
button_calculate.setOnClickListener{view: View ->
if (number_box.text.isNotEmpty()){
var number_entered: String = number_box.text.toString()
viewModel.findNewNumber((number_entered))
calculated_Number = viewModel.sendNewNumber()
Navigation.findNavController(view).navigate(FragmentOneDirections.actionFragmentOneToFragmentTwo(calculated_Number))
}
}
}
}
Error appears here
var args = FragmentTwoArgs.fromBundle(arguments)
arguments is expected to be Bundle but is Bundle?
I had to change it to use !!
var args = FragmentTwoArgs.fromBundle(arguments!!)
use requireArguments() instead of arguments!!
try using requireArguments() instead of arguments
var args = FragmentTwoArgs.fromBundle(requireArguments())
You shouldn't use FragmentTwoArgs.fromBundle(arguments)
just use:
val args: FragmentTwoArgsby navArgs()
And in your method call:
val amount = args.amount
It's work for me, see official guide:
https://developer.android.com/topic/libraries/architecture/navigation/navigation-pass-data
Instead of
var args = FragmentTwoArgs.fromBundle(arguments)
argText.text = args.calculated_Number
you can use
arguments?.let {
val args = FragmentTwoArgs.fromBundle(it)
argText.text = args.calculated_Number
}