I'm trying to use this package https://github.com/PierfrancescoSoffritti/android-youtube-player to play a youtube video. The error I'm getting is Unresolved reference: youTubePlayerView. I've never worked with fragments before so I'm not understanding what I'm doing wrong? After declaring the button in the oncreateview I could set up a listener for it fine, but for some reason after declaring the youtubePlayerView I cant use it and it results in an unresolved reference. What should I do?
here's my code:
package com.srm325.recyclertest.ui.features.receivesong
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.aliakberaakash.cutiehacksproject2020.R
import com.google.android.material.button.MaterialButton
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView
import kotlinx.android.synthetic.main.searchsong_layout.*
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL
import java.util.concurrent.CountDownLatch
private const val BASE_URL =
"https://www.googleapis.com/youtube/v3/search?key=AIzaSyAcqsfnhOFIyIgX1auWR-SzjcTXOoc3MDE&part=snippet,id&order=viewCount&maxResults=1&q="
class receivefragment : Fragment() {
companion object{
const val GET_FROM_GALLERY = 3
}
lateinit var videostring: String
lateinit var selectedImage:Uri
lateinit var storage: FirebaseStorage
val db = Firebase.firestore
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view: View = inflater.inflate(R.layout.receive_layout, container, false)
val youTubePlayerView: YouTubePlayerView = view.findViewById<YouTubePlayerView>(R.id.youtube_player_view)
val uploadBtn: MaterialButton = view.findViewById(R.id.uploadBtn)
return view
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
uploadBtn.setOnClickListener {
lifecycle.addObserver(youTubePlayerView)
youTubePlayerView.addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
override fun onReady(youTubePlayer: YouTubePlayer) {
var video123: String = "lOqy8cC72wA";
youTubePlayer.loadVideo(video123!!, 0f)
}
})
}
}
}
private fun requestData(urlstring: String): String? {
return try {
val response = arrayOfNulls<String>(1)
val latch = CountDownLatch(1)
Thread {
try {
Log.d("START", "Starting GET")
val url = URL(urlstring)
val connection = url.openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.connectTimeout = 5000
connection.readTimeout = 5000
connection.connect()
Log.d("INFO", urlstring)
Log.d("INFO", Integer.toString(connection.responseCode))
Log.d("INFO", connection.responseMessage)
val rd = BufferedReader(InputStreamReader(connection.inputStream))
var content = ""
var line: String
while (rd.readLine().also { line = it } != null) {
content += """
$line
""".trimIndent()
}
response[0] = content
Log.d("SUCCESS", response[0]!!)
latch.countDown()
} catch (ex: Exception) {
Log.d("ERROR", "Error Processing Get Request...")
var i = 0
while (i < ex.stackTrace.size) {
Log.d("ERROR", ex.stackTrace[i].toString())
i++
}
latch.countDown()
}
}.start()
latch.await()
response[0]
} catch (ex: Exception) {
""
}
}
That's because you try to launch it from the fragment, not from the activity. Try to use requireActivity().youTubePlayerView instead.
Related
The error that appears is as follows "Type mismatch: inferred type is String? but String is expected". How can I solve this problem?
The source code is as follows:
package com.example.submission2.Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.example.submission2.Adapter.AdapterSectionPager
import com.example.submission2.ViewModel.DetailVM
import com.example.submission2.databinding.ActivityDetailBinding
class DetailActivity : AppCompatActivity() {
companion object{
const val EXTRA_USERNAME = "extra_username"
}
private lateinit var binding: ActivityDetailBinding
private lateinit var viewModel: DetailVM
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDetailBinding.inflate(layoutInflater)
setContentView(binding.root)
supportActionBar?.apply {
setDisplayHomeAsUpEnabled(true)
setDisplayShowHomeEnabled(true)
}
val username = intent.getStringExtra(EXTRA_USERNAME)
viewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(DetailVM::class.java)
viewModel.setPenggunaDetail(username)
viewModel.getPenggunaDetail().observe(this) {
if (it != null) {
binding.apply {
tvNamaDetail.text = it.name
tvUsernameDetail.text = it.login
tvCompanyDetail.text = it.company
tvEmailDetail.text = it.email
tvFollowersDetail.text = "${it.followers} Followers"
tvFollowingDetail.text = "${it.following} Follwing"
Glide.with(this#DetailActivity)
.load(it.avatar_url)
.transition(DrawableTransitionOptions.withCrossFade())
.centerCrop()
.into(ivDetailProfil)
}
}
}
val sectionPagerAdpter = AdapterSectionPager(this,supportFragmentManager)
binding.apply {
viewPager.adapter = sectionPagerAdpter
tabs.setupWithViewPager(viewPager)
}
}
}
error appears on the line "viewModel.set User Data(username)" username is used in extra_username which will be called in main
for main activity as follows:
package com.example.submission2.Activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.KeyEvent
import android.view.View
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.submission2.Adapter.AdapterPengguna
import com.example.submission2.DataBase.Pengguna
import com.example.submission2.R
import com.example.submission2.ViewModel.MainVM
import com.example.submission2.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewModel: MainVM
private lateinit var adapter: AdapterPengguna
private fun searchPengguna(){
binding.apply {
val query = etSearch.text.toString()
if (query.isEmpty())return
showLoading(true)
viewModel.setSearchPengguna(query)
}
}
private fun showLoading(state: Boolean){
if (state){
binding.progressBarMain.visibility = View.VISIBLE
}else{
binding.progressBarMain.visibility = View.GONE
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
adapter = AdapterPengguna()
adapter.notifyDataSetChanged()
adapter.setOnItemClickCallback(object :AdapterPengguna.OnItemClickCallback{
override fun onItemCliked(data: Pengguna) {
Intent(this#MainActivity,DetailActivity::class.java).also {
it.putExtra(DetailActivity.EXTRA_USERNAME, data.login)
startActivity(it)
}
}
})
viewModel = ViewModelProvider(this,ViewModelProvider.NewInstanceFactory()).get(MainVM::class.java)
binding.apply {
rvPengguna.layoutManager = LinearLayoutManager(this#MainActivity)
rvPengguna.setHasFixedSize(true)
rvPengguna.adapter = adapter
btnSearch.setOnClickListener {
searchPengguna()
}
etSearch.setOnKeyListener { v, keyCode, event ->
if (event.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER){
searchPengguna()
return#setOnKeyListener true
}
return#setOnKeyListener false
}
}
viewModel.getSearchPengguna().observe(this,{
if (it!= null){
adapter.setList(it)
showLoading(false
)
}
})
}
}
In your code there is no such line as viewModel.setUserData
I guess that the error occurs in the line viewModel.setPenggunaDetail(username)
In this case, you should pay attention to the fact that the all intent.getExtra calls returns nullable values.
Thus, if the setPenggunaDetail call expects a non-nullable argument, you must first check username value for null
In this app, i am adding addresses to account and saving them in Realtime database (firebase).I want also to display them in recyclerview but they aren't visible.
Here visualization of my problem : https://youtu.be/OdlZNUQnA-k
The Code should work like this
Addressfragment Contains AddressesRecyclerview
AddAddressfragment for adding new Address
And it goes back to AddressFragment when new Address has been added.
Also when i tried to display all items from one array like for example postcode .It display only last added item. Even on for each loop. Like last item is deleted after adding
I understand that it need something like notifyDataSetChanged() but it doesnt work here
Here is The code:
AddressFragment:
package com.querto.fragments.address
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.FirebaseDatabase
import com.querto.R
import com.querto.adapters.AddressAdapter
import com.querto.viewmodel.MainActivityViewModel
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.fragment_address.view.*
class AddressFragment : Fragment() {
private lateinit var mMainActivityViewModel: MainActivityViewModel
private lateinit var database: DatabaseReference
private lateinit var mAuth: FirebaseAuth
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
var view = inflater.inflate(R.layout.fragment_address, container, false)
database = FirebaseDatabase.getInstance().reference
mAuth = FirebaseAuth.getInstance()
mMainActivityViewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(requireActivity().application).create(
MainActivityViewModel::class.java)
if(mAuth.currentUser==null){
Toast.makeText(requireContext(), "To add address please login",Toast.LENGTH_SHORT).show()
activity?.nav_view?.setCheckedItem(R.id.login)
activity?.supportFragmentManager?.beginTransaction()?.setCustomAnimations(R.anim.fragment_slide_in_anim, R.anim.fragment_fade_out_anim, R.anim.fragment_slide_out_anim, R.anim.fragment_fade_in_anim)?.replace(R.id.fragment_container, mMainActivityViewModel.loginFragment)?.commit()
}
view.recyclerViewAddress.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
view.recyclerViewAddress.adapter = AddressAdapter(requireContext(), mMainActivityViewModel.list_of_addresses)
view.add_address_btn.setOnClickListener {
activity?.supportFragmentManager?.beginTransaction()?.setCustomAnimations(R.anim.fragment_slide_in_anim, R.anim.fragment_fade_out_anim, R.anim.fragment_slide_out_anim, R.anim.fragment_fade_in_anim)?.replace(R.id.fragment_container, mMainActivityViewModel.addAddressFragment)?.commit()
}
return view
}
}
Adapter:
package com.querto.adapters
import android.app.Application
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.FirebaseDatabase
import com.querto.R
import com.querto.model.Address
import com.querto.viewmodel.MainActivityViewModel
import kotlinx.android.synthetic.main.my_address_row.view.*
class AddressAdapter(contextAdapter: Context, addresses: ArrayList<Address>):
RecyclerView.Adapter<AddressAdapter.MyViewHolder>() {
private var mMainActivityViewModel: MainActivityViewModel
private val context: Context = contextAdapter
private val local_addreses : ArrayList<Address> = addresses
private var database: DatabaseReference
private var mAuth: FirebaseAuth
init {
mMainActivityViewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(context.applicationContext as Application).create(
MainActivityViewModel::class.java)
database = FirebaseDatabase.getInstance().reference
mAuth = FirebaseAuth.getInstance()
}
class MyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
val currentTitle = itemView.address_title
val currentId = itemView.address_id
val currentStreet = itemView.address_street
val currentPostcode = itemView.address_postcode
val currentHouseNumber = itemView.address_number
val currentAddressCityName = itemView.address_city
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(context).inflate(R.layout.my_address_row, parent, false))
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.currentTitle.text = local_addreses[position].name
holder.currentId.text = (position + 1).toString()
holder.currentStreet.text =local_addreses[position].street
holder.currentPostcode.text =local_addreses[position].postcode
holder.currentHouseNumber.text = local_addreses[position].house_number
holder.currentAddressCityName.text = local_addreses[position].city_name
}
override fun getItemCount(): Int {
return local_addreses.size
}
fun addAddress(address: Address){
mMainActivityViewModel.list_of_addresses.add(address)
notifyDataSetChanged()
}
}
AddAddress:
package com.querto.fragments.address
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.lifecycle.ViewModelProvider
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.FirebaseDatabase
import com.querto.R
import com.querto.adapters.AddressAdapter
import com.querto.model.Address
import com.querto.viewmodel.MainActivityViewModel
import kotlinx.android.synthetic.main.fragment_add_address.view.*
class AddAddressFragment : Fragment() {
private lateinit var database: DatabaseReference
private lateinit var mAuth: FirebaseAuth
private lateinit var mMainActivityViewModel: MainActivityViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
var view = inflater.inflate(R.layout.fragment_add_address, container, false)
mMainActivityViewModel =
ViewModelProvider.AndroidViewModelFactory.getInstance(activity?.application!!)
.create(MainActivityViewModel::class.java)
view.addAddressButton.setOnClickListener {
val addressName = view.addAddressName.text.toString()
val addressStreet = view.addAddressStreet.text.toString()
val addressNumber = view.addAddressHouseNumber.text.toString()
val addressZipCode = view.addAddressCityZipCode.text.toString()
val addressCityName = view.addAddressCityName.text.toString()
if(inputCheck(addressName,addressStreet,addressNumber,addressZipCode, addressCityName)){
mAuth = FirebaseAuth.getInstance()
database = FirebaseDatabase.getInstance().reference
addAddress(addressName, addressStreet, addressNumber, addressZipCode, addressCityName)
}else{
Toast.makeText(requireContext(), "Please enter all fields", Toast.LENGTH_SHORT).show()
}
}
return view
}
private fun addAddress(addressName: String, addressStreet: String, addressNumber: String,addressZipCode: String, addressCityName: String) {
val address = Address(mAuth.currentUser?.uid, addressName, addressStreet,addressZipCode, addressNumber, addressCityName)
database.child("addresses").child(database.push().key.toString()).setValue(address).addOnCompleteListener {
if(it.isSuccessful){
val addressAdapter= AddressAdapter(requireContext(), mMainActivityViewModel.list_of_addresses)
addressAdapter.addAddress(address)
activity?.supportFragmentManager?.beginTransaction()?.setCustomAnimations(R.anim.fragment_slide_in_anim, R.anim.fragment_fade_out_anim, R.anim.fragment_slide_out_anim, R.anim.fragment_fade_in_anim)?.replace(R.id.fragment_container, mMainActivityViewModel.addressFragment)?.commit()
Toast.makeText(requireContext(), "Added address", Toast.LENGTH_SHORT).show()
}else{
Toast.makeText(requireContext(), "Fail at creating address", Toast.LENGTH_SHORT).show()
}
}
}
private fun inputCheck(addressName: String, addressStreet: String, addressNumber: String,addressZipCode: String, adressCityName: String)=
addressName.isNotEmpty() && addressStreet.isNotEmpty() && addressNumber.isNotEmpty() && addressZipCode.isNotEmpty() && adressCityName.isNotEmpty() && addressZipCode.length==5
}
MainActivityViewModel:
class MainActivityViewModel(application: Application) : AndroidViewModel(application) {
private lateinit var database: DatabaseReference
private lateinit var mAuth: FirebaseAuth
val homeFragment = HomeFragment()
val loginFragment = LoginFragment()
val registerFragment = RegisterFragment()
val detailsFragment = DetailsFragment()
val addressFragment = AddressFragment()
val addAddressFragment = AddAddressFragment()
var pizza_names: Array<String> = application.resources.getStringArray(R.array.pizza_titles)
var pizza_desc: Array<String> = application.resources.getStringArray(R.array.pizza_desc)
val pizza_small_price: IntArray = application.resources.getIntArray(R.array.pizza_small_price)
val pizza_medium_price: IntArray = application.resources.getIntArray(R.array.pizza_medium_price)
val pizza_big_price: IntArray = application.resources.getIntArray(R.array.pizza_big_price)
var pizza_img: Array<Int> = arrayOf(R.drawable.napoletana, R.drawable.margherita, R.drawable.estate, R.drawable.pepperone, R.drawable.pancetta, R.drawable.ortolana, R.drawable.marinara, R.drawable.diavola, R.drawable.messicana, R.drawable.quattro_formaggi, R.drawable.sugoza, R.drawable.semola, R.drawable.capriciossa, R.drawable.vulcano, R.drawable.romana, R.drawable.capodanno, R.drawable.primavera, R.drawable.regina, R.drawable.quattro_stagioni, R.drawable.cilento, R.drawable.tirolese, R.drawable.michele, R.drawable.pollo, R.drawable.havana, R.drawable.siciliana, R.drawable.sandra, R.drawable.bari, R.drawable.gringo, R.drawable.angelo, R.drawable.spinaci)
var focaccia_names: Array<String> = application.resources.getStringArray(R.array.foaccia_titles)
var focaccia_desc: Array<String> = application.resources.getStringArray(R.array.foaccia_desc)
val focaccia_price: IntArray = application.resources.getIntArray(R.array.foaccia_price)
var focaccia_img: Array<Int> = arrayOf(R.drawable.base, R.drawable.nutella)
var calzone_names: Array<String> = application.resources.getStringArray(R.array.calzone_titles)
var calzone_desc: Array<String> = application.resources.getStringArray(R.array.calzone_desc)
val calzone_price_normal: IntArray = application.resources.getIntArray(R.array.calzone_normal_price)
val calzone_price_big: IntArray = application.resources.getIntArray(R.array.calzone_big_price)
var calzone_img: Array<Int> = arrayOf(R.drawable.calzone)
var panuozzo_names: Array<String> = application.resources.getStringArray(R.array.panuozzo_titles)
var panuozzo_desc: Array<String> = application.resources.getStringArray(R.array.panuozzo_desc)
val panuozzo_price_normal: IntArray = application.resources.getIntArray(R.array.panuozzo_normal_price)
val panuozzo_price_big: IntArray = application.resources.getIntArray(R.array.panuozzo_big_price)
var panuozzo_img: Array<Int> = arrayOf(R.drawable.panuozzo)
val sosy_names: Array<String> = application.resources.getStringArray(R.array.sosy_titles)
val sosy_price: IntArray = application.resources.getIntArray(R.array.sosy_price)
val napoje_names: Array<String> = application.resources.getStringArray(R.array.napoje_titles)
val napoje_price: IntArray = application.resources.getIntArray(R.array.napoje_price)
val napoje_first_kind: Array<String> = application.resources.getStringArray(R.array.napoje_kinds_one)
val napoje_second_kind: Array<String> = application.resources.getStringArray(R.array.napoje_kinds_two)
val dodatki_names: Array<String> = application.resources.getStringArray(R.array.dodatki_titles)
val dodatki_small_price: IntArray = application.resources.getIntArray(R.array.dodatki_small_price)
val dodatki_medium_price: IntArray = application.resources.getIntArray(R.array.dodatki_medium_price)
val dodatki_big_price: IntArray = application.resources.getIntArray(R.array.dodatki_big_price)
var list_of_addresses = ArrayList<Address>()
private val mutableLoginStatus = MutableLiveData<Boolean>()
val loginStatus: LiveData<Boolean>
get() = mutableLoginStatus
fun checkLogin(username: String, password: String) {
viewModelScope.launch(Dispatchers.IO) {
database = FirebaseDatabase.getInstance().reference
mAuth = FirebaseAuth.getInstance()
mAuth.signInWithEmailAndPassword(username,password).addOnCompleteListener{
if(it.isSuccessful){
mutableLoginStatus.postValue(true)
}else{
mutableLoginStatus.postValue(false)
}
}
}
}
fun shareApp(context: Context) {
val openURL = Intent(android.content.Intent.ACTION_VIEW)
openURL.data = Uri.parse("https://www.facebook.com/1488596184507308/")
context.startActivity(openURL)
}
fun sendMail(context: Context) {
val sendEmail = Intent(Intent.ACTION_SEND)
val email: Array<String> = arrayOf("kontakt#cilento.pl")
sendEmail.setData(Uri.parse("mailto: kontakt#cilento.pl "))
sendEmail.putExtra(Intent.EXTRA_SUBJECT, "Problem z Usługą")
sendEmail.putExtra(Intent.EXTRA_TEXT, "Pizza którą zamówiłem nie przyszła na czas.\n\n\nMoje Dane Kontaktowe: \n\nImie: \nNazwisko: \nAdres: ")
sendEmail.setType("message/rfc822")
sendEmail.putExtra(Intent.EXTRA_EMAIL, email)
val chooser = Intent.createChooser(sendEmail, "Send mail using")
context.startActivity(chooser)
}
}
Address Class:
package com.querto.model
data class Address(
val userId: String?,
val name: String?,
val street: String?,
val postcode: String?,
val house_number: String?,
val city_name: String?
)
After Checking The MainActivityViewModel ,I See that you are not fetching data from the firebase database.
You should add this to AddressFragment class
also Add Variable called addressAdapter in the top of the class
fun getAddresses(){
val ref = FirebaseDatabase.getInstance().reference.child("addresses")
ref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (dataSnapshot.exists()) {
val address = dataSnapshot.getValue<Address>()
mMainActivityViewModel.addresses_list.add(address)
addressAdapter.notifyDataChanged()
}
}
override fun onCancelled(databaseError: DatabaseError) {
}
})
}
Also Implementing Address adapter here does not do a thing . just remove it.
private fun addAddress(addressName: String, addressStreet: String, addressNumber: String,addressZipCode: String, addressCityName: String) {
val address = Address(mAuth.currentUser?.uid, addressName, addressStreet,addressZipCode, addressNumber, addressCityName)
database.child("addresses").child(database.push().key.toString()).setValue(address).addOnCompleteListener {
if(it.isSuccessful){
val addressAdapter= AddressAdapter(requireContext(), mMainActivityViewModel.address_title, mMainActivityViewModel.address_street,mMainActivityViewModel.address_post_code, mMainActivityViewModel.address_house_number, mMainActivityViewModel.address_city_name)
addressAdapter.addAddress(addressName, addressStreet,addressZipCode, addressNumber, addressCityName)
activity?.supportFragmentManager?.beginTransaction()?.setCustomAnimations(R.anim.fragment_slide_in_anim, R.anim.fragment_fade_out_anim, R.anim.fragment_slide_out_anim, R.anim.fragment_fade_in_anim)?.replace(R.id.fragment_container, mMainActivityViewModel.addressFragment)?.commit()
Toast.makeText(requireContext(), "Added address", Toast.LENGTH_SHORT).show()
}else{
Toast.makeText(requireContext(), "Fail at creating address", Toast.LENGTH_SHORT).show()
}
}
I will try to explain it here.
When you create a custom RecyclerView adapter usually you suppose to pass data you want to be displayed in the list. For me it is better to pass array Of Class You Made To Pass Data For Single Recylcer View itemArrayList<ClassOfSingleItem>, but it is not nessesary of course.
So when you call notifyDataSetCahnged you notify your adapter that data in this ArrayList was changed. But this call will not work if you create new Adapter every time you add or remove something from the RecyclerView list.
EDIT:
Let me explain what i see: you have button with click listener, when you click it you replace current fragmen with the one where you add data.
view.add_address_btn.setOnClickListener {
activity?.supportFragmentManager?.beginTransaction()?.setCustomAnimations(R.anim.fragment_slide_in_anim, R.anim.fragment_fade_out_anim, R.anim.fragment_slide_out_anim, R.anim.fragment_fade_in_anim)?.replace(R.id.fragment_container, mMainActivityViewModel.addAddressFragment)?.commit()
}
then, when you complete editing all fields what you do? replace your addAdressFragment with addressFragment:
val addressAdapter= AddressAdapter(requireContext(), mMainActivityViewModel.list_of_addresses)
addressAdapter.addAddress(address)
activity?.supportFragmentManager?.beginTransaction()?.setCustomAnimations(R.anim.fragment_slide_in_anim, R.anim.fragment_fade_out_anim, R.anim.fragment_slide_out_anim, R.anim.fragment_fade_in_anim)?.replace(R.id.fragment_container, mMainActivityViewModel.addressFragment)?.commit()
inside this method you CREATE new AdressAdapter to call method addAdrees which has notifyDataSetChanged call inside. But recyclerView in your addressFragment has no idea about this new AddressAdapter. This is the main problem. As i mentioned in comment below my answer there are only two ways to update RecyclerView so implement one of them.
Below I show some java code (you mentioned you know java) which can give you an idea:
public class PointActivity extends BaseActivity
implements SearchView.OnQueryTextListener{
private RecyclerView mRecyclerView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_point);
mRecyclerView = findViewById(R.id.point_list);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
List<PointItem> pointItems = getFilteredAndSortedList();
mRecyclerView.setAdapter(new PointAdapter(this, pointItems));
}
//here we need to update recyclerView
#Override
public boolean onQueryTextSubmit(String query) {
searchResult(query);
return false;
}
public void searchResult(String query) {
if (query.isEmpty()) {
//just full list if query is empty
mRecyclerView.setAdapter(new PointAdapter(this, getFilteredAndSortedList()));
} else {
PointSearchManager pointSearchManager = new PointSearchManager();
List<PointItem> list;
list = Arrays.asList(pointSearchManager.toFilters(getFilteredAndSortedList().toArray(new PointItem[0]), query));
//list filtered with query result
mRecyclerView.setAdapter(new PointAdapter(this, list));
}
}
I've got a problem. I'm making an application for Android of the client of MQTT and I need to use the same parameters for MqttAndroidClient() method in different fragments. I've already tried to pass them in the bundle, with intent putExtra(), making objects of the class. The bundle and putExtra send the data to another fragment, it shows in the debug mode, but in the target fragment I get nulls.
When I'm trying to receive the value instantiating the first fragment, it sends me the lateinit variable without any value in it. I have no ideas what can I do more. I thought about using setters and getters to get it, but I'm not sure that is the solution.
First fragment where I send the data:
ConnectFragment.kt
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import androidx.fragment.app.Fragment
import com.dzichkovskii.mqttsrm.R
import kotlinx.android.synthetic.main.fragment_connect.*
import org.eclipse.paho.android.service.MqttAndroidClient
import org.eclipse.paho.client.mqttv3.*
import java.io.Serializable
class ConnectFragment : Fragment(){
companion object{
const val SUCCESS_TEXT = "Connection established successfully"
const val FAILURE_TEXT = "Connection wasn't established. Error happened."
const val BLANK_TEXT = "Your inputs cannot be empty. Please, write the correct address or ID."
const val CONNECTION_FAILURE = "Something went wrong. Probably you have no internet. Try later"
const val SENDING_NAME_ADDRESS = "mqttAndroidClientAddress"
const val SENDING_NAME_ID = "mqttAndroidClientId"
const val TAG = "ConnectFragment"
}
lateinit var mqttAndroidClient: MqttAndroidClient
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.fragment_connect, container, false)
//I will leave this values just in case I would need to test the connection
//val testClientId = MqttClient.generateClientId()
//val testAddress = "tcp://broker.hivemq.com:1883"
root.findViewById<Button>(R.id.btn_connect).setOnClickListener {
mqttAndroidClient = connect(context, view)
}
return root
}
private fun connect(context: Context?,
view: View?): MqttAndroidClient {
// val inputAddress = view?.findViewById(R.id.tv_broker_address_input) as EditText
// val inputId = view?.findViewById(R.id.tv_client_id_input) as EditText
// val inputPort = view.findViewById(R.id.tv_broker_port_input) as EditText
//
//Making the string the user needs to put more friendly
// val addressStringSimplification = "tcp://" + inputAddress.text.toString() +
// ":" + inputPort.text.toString()
val addressStringSimplification = "tcp://broker.hivemq.com:1883"
val testClientId = MqttClient.generateClientId()
mqttAndroidClient = MqttAndroidClient(context?.applicationContext, addressStringSimplification, testClientId/*inputId.text.toString()*/)
val intent = Intent(this.context, SubscribeFragment::class.java)
val bundle = Bundle()
bundle.putString("testBundle", addressStringSimplification) //bundle here
val subscribeFragment = SubscribeFragment()
subscribeFragment.arguments = bundle
intent.putExtra(SENDING_NAME_ADDRESS, addressStringSimplification) //Intents here
intent.putExtra(SENDING_NAME_ID, testClientId)
// if (inputAddress.isBlank() || inputId.isBlank()
// || inputPort.isBlank() || addressStringSimplification == "tcp://:"){
// displayErrorMessage(BLANK_TEXT, view, this)
// return
// }
// else {
try {
val token = mqttAndroidClient.connect()
token.actionCallback = object : IMqttActionListener {
override fun onSuccess(asyncActionToken: IMqttToken?) {
Log.d(TAG, "Connection is successful")
Toast.makeText(context, SUCCESS_TEXT, Toast.LENGTH_SHORT).show()
hideKeyboard()
return
}
override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
Log.d(TAG, "Connection didn't established")
Toast.makeText(context, FAILURE_TEXT, Toast.LENGTH_SHORT).show()
displayErrorMessage(FAILURE_TEXT, view, this#ConnectFragment)
return
}
}
} catch (e: MqttException) {
Log.d(TAG, "Exception caught")
displayErrorMessage(CONNECTION_FAILURE, view, this)
}
return mqttAndroidClient
}
// tv_error.visibility = View.INVISIBLE
}
/**
* This extension function makes strings look less ugly.
*/
private fun EditText.isBlank() = this.text.toString().isBlank()
//}
fun displayErrorMessage(errorString: String, view: View?, fragment: Fragment){
val errorTextView = view?.rootView?.findViewById(R.id.tv_error) as TextView
errorTextView.text = errorString
errorTextView.visibility = View.VISIBLE
fragment.hideKeyboard()
}
fun Fragment.hideKeyboard() {
view?.let { activity?.hideKeyboard(it) }
}
fun Context.hideKeyboard(view: View) {
val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
}
And here is another fragment where I receive data:
SubscribeFragment.kt
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.fragment.app.Fragment
import com.dzichkovskii.mqttsrm.R
import com.google.android.material.chip.Chip
import kotlinx.android.synthetic.main.fragment_subscribe.view.*
import org.eclipse.paho.android.service.MqttAndroidClient
import org.eclipse.paho.client.mqttv3.IMqttActionListener
import org.eclipse.paho.client.mqttv3.IMqttToken
import org.eclipse.paho.client.mqttv3.MqttException
class SubscribeFragment : Fragment() {
companion object {
const val TAG = "SubscribeFragment"
const val BLANK_TEXT = "Your inputs cannot be empty. Please, write the correct address or ID."
const val ON_SUCCESS = "You subscribed successfully."
const val ON_FAILURE = "You didn't subscribed to the topic. Probably this topic doesn't exist."
const val CONNECTION_ERROR = "The topic don't exist or you have connection problems. " +
"Check your internet connection or change the topic's name"
const val GETTING_NAME_ADDRESS = "mqttAndroidClientAddress"
const val GETTING_NAME_ID = "mqttAndroidClientId"
}
private var checkedOption: Int = 0 //Default value of qos
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.fragment_subscribe, container, false)
return root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.chip_group?.setOnCheckedChangeListener { _, checkedId: Int ->
val chip: Chip? = view.findViewById(checkedId)
val qos = chip?.text.toString().toInt()
checkedOption = qos
Log.d(TAG, "Checked option passed with value $checkedOption")
}
view.findViewById<Button>(R.id.btn_subscribe).setOnClickListener {
subscribe()
}
}
private fun subscribe(){
val connectFragment = ConnectFragment()
val mqttAndroidClient = connectFragment.mqttAndroidClient //Instantiation of the class here
val address = this#SubscribeFragment.arguments?.getString("testBundle") // Bundle here
val id = activity?.intent?.getStringExtra(GETTING_NAME_ID) // Intent string here
//val mqttAndroidClient = MqttAndroidClient(context, address, id)
val inputTopic = view?.findViewById(R.id.et_topic) as EditText
val topic = inputTopic.text.toString()
if (inputTopic.isBlank()){
displayErrorMessage(BLANK_TEXT, view, this)
}
try {
Log.d(TAG, "Checked option in subscribe method is $checkedOption")
mqttAndroidClient.subscribe(topic, checkedOption, null, object : IMqttActionListener {
override fun onSuccess(asyncActionToken: IMqttToken) {
Toast.makeText(context, ON_SUCCESS, Toast.LENGTH_SHORT).show()
Log.d(TAG, "Connected successfully")
}
override fun onFailure(
asyncActionToken: IMqttToken,
exception: Throwable
) {
Toast.makeText(context, ON_FAILURE, Toast.LENGTH_SHORT).show()
Log.d(TAG, "Didn't connected")
}
})
} catch (e: MqttException) {
displayErrorMessage(CONNECTION_ERROR, view, this)
}
}
private fun EditText.isBlank() = this.text.toString().isBlank()
}
Thanks for answering!
First of all to create a fragment you should have a newInstance method and this method should except the parameters that you want to pass to the fragment, in your case SubscriberFragment should have following function in companion object
class SubscribeFragment: Fragment() {
companion object {
const val SENDING_NAME_ADDRESS = "mqttAndroidClientAddress"
const val SENDING_NAME_ID = "mqttAndroidClientId"
// Use this function to create instance of your fragment
fun newInstance(addressStringSimplification: String,
testClientId: String): MyFragment {
val args = Bundle()
args.putString(SENDING_NAME_ADDRESS , addressStringSimplification)
args.putString(SENDING_NAME_ID , testClientId)
val fragment = SubscribeFragment()
fragment.arguments = args
return fragment
}
}
}
After this when your fragment is loaded the arguments are delivered to onCreate method and you can extract them as following.
#Override
public void onCreate(Bundle savedInstanceState) {
var sendingName = getArguments().getInt(SENDING_NAME_ADDRESS);
var sendingId = getArguments().getString(SENDING_NAME_ID);
}
Now to the most important part, you seem to think that doing SubscriberFragment() is enough to load the fragment which is not the case. when you want to start SubscriberFragment, you should do the following
// create instance of SubscriberFragment with newInstance function and pass the argguments you want
var someFragment = SubscribeFragment.newInstance(addressStringSimplification,testClientId);
var transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, someFragment); // give your fragment container id in first parameter
transaction.addToBackStack(null);
transaction.commit();
For some reason, onClick isn't being registered with my adapter. I'm using the MVVM pattern and I've made sure that all the pieces are tied together but for the life of me I can't figure out why this won't work.
StoreFragment
package com.example.brandroidtest.main
import android.os.Bundle
import android.util.Log
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 androidx.navigation.fragment.findNavController
import com.example.brandroidtest.databinding.FragmentStoreBinding
class StoreFragment : Fragment() {
//Will Create a ViewModelProivders object of class DetailViewModel the first time viewModel is used
//Allows us to move this code from on create to the declaration
private val viewModel: StoreViewModel by lazy {
val factory = StoreViewModelFactory(requireNotNull(activity).application)
ViewModelProviders.of(this, factory).get(StoreViewModel::class.java)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
Log.i("onCreateView", "StoreFragment created")
val binding = FragmentStoreBinding.inflate(inflater)
binding.setLifecycleOwner(this)
binding.viewModel = viewModel
binding.storeList.adapter = StoreAdapter(StoreAdapter.OnClickListener {
viewModel.displayStoreDetails(it)
Log.i("inside OnClickListener", "after displayDetails")
})
Log.i("between adapter.onclick", "and viewModel observe")
viewModel.selectedStore.observe(this, Observer {
Log.i("observe", "inside the selectedStore observe method")
if (null != it) {
this.findNavController().navigate(
StoreFragmentDirections.actionMainListFragmentToDetailFragment(
it
)
)
viewModel.displayStoreDetailsComplete()
}
})
return binding.root
}
}
StoreViewModel
package com.example.brandroidtest.main
import android.app.Application
import android.content.Context
import android.net.ConnectivityManager
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.example.brandroidtest.model.Store
import com.example.brandroidtest.network.StoreAPI
import kotlinx.coroutines.*
enum class StoreAPIStatus {LOADING, DONE, NO_CONNECTION}
class StoreViewModel(application: Application) : AndroidViewModel(application) {
// Response from server: Either Store Data or Failure Message
private val _status = MutableLiveData<StoreAPIStatus>()
// for status of get request
//displayed when there is no internet connection or if the connection is unstable and the data is being loaded
val status: LiveData<StoreAPIStatus>
get() = _status
//internal variable accessed within this file
private val listOfStores = MutableLiveData<List<Store>>()
//external variable for anywhere else
val stores: LiveData<List<Store>>
get() = listOfStores
private val _selectedStore = MutableLiveData<Store>()
val selectedStore: LiveData<Store>
get() = _selectedStore
private var viewModelJob = Job()
private val coroutineScope = CoroutineScope(viewModelJob + Dispatchers.Main)
/**
* Call getStoreData() in init so we can display the result immediately.
*/
init {
Log.i("viewModel init", "inside StoreViewModel init block")
if (isNetworkConnected(application.applicationContext))
getStoreData()
else
// Log.i("Bypassed network call", "")
listOfStores.value = emptyList()
_status.value = StoreAPIStatus.NO_CONNECTION
}
/**
* Sets the value of the status LiveData to the Store API data.
*/
private fun getStoreData() {
Log.i("getStoreData()", " inside getStoreData")
coroutineScope.launch {
try {
Log.i("getStoreData()", "Inside the coroutine before getData")
_status.value = StoreAPIStatus.LOADING
var storeData = async { StoreAPI.retrofitService.getData().stores }.await()
Log.i("getStoreData()", "Inside the coroutine after getData")
_status.value = StoreAPIStatus.DONE
listOfStores.value = storeData
} catch (e: Exception) {
_status.value = StoreAPIStatus.NO_CONNECTION
listOfStores.value = ArrayList()
e.printStackTrace()
}
}
}
override fun onCleared() {
super.onCleared()
viewModelJob.cancel()
}
private fun isNetworkConnected(context: Context): Boolean {
val cm =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
return cm!!.activeNetworkInfo != null && cm.activeNetworkInfo.isConnected
}
//will be called to set the store as the one that was clicked
fun displayStoreDetails(store : Store){
Log.i("displayStoreDetails", "inside this method")
_selectedStore.value = store
}
//sets the selected store's value to null so that live data can be updated when we select a new store and not show us the detail apge of the same store
fun displayStoreDetailsComplete() {
Log.i("displayStoreDetailsComplete", "inside this method")
_selectedStore.value = null
}
}
StoreAdapter
package com.example.brandroidtest.main
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.brandroidtest.model.Store
import com.example.brandroidtest.databinding.ListItemBinding
class StoreAdapter(val onClickListener: OnClickListener) :
ListAdapter<Store, StoreAdapter.StoreViewHolder>(DiffCallback) {
class StoreViewHolder(private var binding: ListItemBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(store: Store) {
binding.store = store
Log.i("Adapter bind", store.storeLogoURL)
binding.executePendingBindings()
}
}
companion object DiffCallback : DiffUtil.ItemCallback<Store>() {
override fun areItemsTheSame(oldItem: Store, newItem: Store): Boolean {
return oldItem === newItem
}
override fun areContentsTheSame(oldItem: Store, newItem: Store): Boolean {
return oldItem.storeID == newItem.storeID
}
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): StoreViewHolder {
return StoreViewHolder(ListItemBinding.inflate(LayoutInflater.from(parent.context)))
}
override fun onBindViewHolder(holder: StoreViewHolder, position: Int) {
val store = getItem(position)
Log.i("inside onBindViewHolder", "")
holder.itemView.setOnClickListener {
Log.i("inside onBindViewHolder", "setOnClickListener")
onClickListener.onClick(store)
}
holder.bind(store)
}
class OnClickListener(val clickListener: (store: Store) -> Unit) {
fun onClick(store: Store) {
Log.i("inside onClick", "click is being registered ${store.city}")
return clickListener(store)
}
}
}
StoreDetailFragment
package com.example.brandroidtest.detailed
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import com.example.brandroidtest.R
import com.example.brandroidtest.databinding.FragmentStoreDetailBinding
/**
* A simple [Fragment] subclass.
*/
class StoreDetailFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val application = requireNotNull(activity).application
val binding = FragmentStoreDetailBinding.inflate(inflater)
binding.setLifecycleOwner(this)
val store = StoreDetailFragmentArgs.fromBundle(arguments!!).selectedStore
val viewModelFactory = StoreDetailViewModelFactory(store, application)
binding.viewModel = ViewModelProviders.of(this, viewModelFactory).get(StoreDetailViewModel::class.java)
return binding.root
}
}
StoreDetailViewModel
package com.example.brandroidtest.detailed
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.example.brandroidtest.model.Store
class StoreDetailViewModel(store: Store, application: Application) : AndroidViewModel(application) {
private val _selectedStore = MutableLiveData<Store>()
val selectedStore : LiveData<Store>
get() = _selectedStore
init {
_selectedStore.value = store
}
}
I have no idea why onClick won't work and the Detail Fragment won't show because of it
Here is the project link: https://drive.google.com/open?id=1m8R8HvCt4m0KIp_IwdeO1YdB5yY8A8LK
The issue come from your adapter item layout.
The height of every item show be wrap_content. But you are using a ScrollView as the root view of your item view.
Remove the useless ScrollView and also the next LinearLayout. You layout should become like this:
<LinearLayout
...
android:padding="16dp"/>
<ImageView
android:id="#+id/store_logo"
.../>
<LinearLayout
android:id="#+id/store_detail"
...>
</LinearLayout>
i have one fragment which run asynctask to get data by parsing api and storing in array list.
but what i want to do is that i want to print that list from another class so that i can create search filter.
package com.example.rsquare_android_fixed.mywork.building
import android.os.AsyncTask
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.size
import androidx.fragment.app.Fragment
import com.example.rsquare_android_fixed.R
import com.example.test.mainF.Address_data
import kotlinx.android.synthetic.main.fragment_building.*
import org.json.JSONArray
import org.json.JSONObject
import java.net.HttpURLConnection
import java.net.URL
class buildingFragment: Fragment(){
private val list=ArrayList<Address_data>()
private val list2=ArrayList<Address_map>()
public var list3=ArrayList<Address_all>()
public var check_list3:Int = 0
override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {
val inflate=inflater.inflate(R.layout.fragment_building, container, false)
val url="https://manage-dev.rsquare.co.kr/api/sample/buildings"
AsyncTaskHandleJson().execute(url)
return inflate
}
inner class AsyncTaskHandleJson: AsyncTask<String, String, String>(){
override fun doInBackground(vararg url: String?): String {
var text:String
val connection= URL(url[0]).openConnection() as HttpURLConnection
try{
connection.connect()
text=connection.inputStream.use{it.reader().use{reader->reader.readText()}}
}
finally{
connection.disconnect()
}
return text
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
handleJson(result)
naverGeo()
}
//json parsing
private fun handleJson(jsonString: String?) {
val jsonArray= JSONArray(jsonString)
//val list=ArrayList<Address_data>()
var x=0
while(x<jsonArray.length()){
val jsonObject=jsonArray.getJSONObject(x)
list.add(
Address_data(
jsonObject.getString("address"),
jsonObject.getString("bunji"),
jsonObject.getString("streetAddress"),
jsonObject.getString("updateAt")
)
)
x++
}
val adapter=MW_Adapter_list(requireActivity(),list)
data_list.adapter=adapter
// val a = list[0]
// a.address
list.forEach { println(it) }
println("listsize1="+list.size)
}
}
fun naverGeo(){
println("naverGeo")
var query:String
println("listsize2="+list.size)
for(i in 0..list.size-1){
var a = list[i]
query=a.address
println("test : $i")
println("query : $query")
var url2 = "https://naveropenapi.apigw.ntruss.com/map-geocode/v2/geocode?X-NCP-APIGW-API-KEY-ID=key&X-NCP-APIGW-API-KEY=pw&query="+query
AsyncTaskNaver().execute(url2)
}
}
inner class AsyncTaskNaver:AsyncTask<String,String,String>(){
override fun doInBackground(vararg url2: String?): String {
var text:String
val connection=URL(url2[0]).openConnection() as HttpURLConnection
try{
connection.connect()
text=connection.inputStream.use{it.reader().use{reader->reader.readText()}}
}
finally{
connection.disconnect()
}
return text
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
handleJson2(result)
//merge to longitude and latitude with original data
if(list2.size==30){
mergeList()
}
}
private fun handleJson2(jsonString: String?){
val jsonObj=JSONObject(jsonString)
val jsonArray=JSONArray(jsonObj.get("addresses").toString())
var x=0
while(x<jsonArray.length()){
val jsonObject=jsonArray.getJSONObject(x)
list2.add(
Address_map(
jsonObject.getString("roadAddress"),
jsonObject.getString("x"), //long
jsonObject.getString("y") //lat
)
)
x++
}
//println(list2.size)
}
}
fun mergeList(){
//println(list2.size)
for (i in 0..list.size-1){
var list_api=list[i]
var list_naver=list2[i]
var query_api=list_api.address
var query_naver=list_naver.raddress
var bunji_api=list_api.bunji
var street_api=list_api.streeetAddress
var long_naver=list_naver.x
var lat_naver=list_naver.y
//by comparing first 2 letters, last 3 letters from address to merge them into one
if(query_api.takeLast(3)==query_naver.takeLast(3)&&query_api.take(2)==query_naver.take(2)){
list3.add(
Address_all(
query_api,
bunji_api,
street_api,
long_naver,
lat_naver
)
)
}
}
check_list3=1
list3.forEach { println(it) }
}
}
and below is my another code where i want to print list
package com.example.rsquare_android_fixed.mywork.search
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.widget.ListView
import android.widget.TextView
import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment
import com.example.rsquare_android_fixed.R
import com.example.rsquare_android_fixed.mywork.building.MWFragment
import com.example.rsquare_android_fixed.mywork.building.MW_Adapter_list
import com.example.rsquare_android_fixed.mywork.building.buildingFragment
import com.naver.maps.geometry.LatLng
import com.naver.maps.geometry.LatLngBounds
import com.naver.maps.map.NaverMap
import com.naver.maps.map.NaverMapSdk
import com.naver.maps.map.overlay.Marker
import kotlinx.android.synthetic.main.fragment_building.*
import kotlinx.android.synthetic.main.fragment_search.*
import kotlinx.android.synthetic.main.list_search.*
class searchFragment: Fragment(){
private var list: ListView?=null
private var adapter:SearchAdapter?=null
private var editsearch:SearchView?=null
private var addrList:Array<String>?=null
//lateinit var naverMap:NaverMap
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view:View = inflater.inflate(R.layout.fragment_search, container, false)
//list=findViewById(R.id.search_list) as ListView
val a = buildingFragment()
if(a.check_list3==0){
println("nulnunlnlunlnl")
}
else{
println(a.list3)
println("not null")
//println(a.list3)
}
return view
}
/*override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//NaverMapSdk.getInstance(requireContext()).client=NaverMapSdk.NaverCloudPlatformClient("dp3mci4foz")
val a = buildingFragment()
}
*/
}
i think my 2nd code is calling list before asynctask from 1st code is done. and this leads me to print null list.
so is there any method that 2nd code to notice that 1st code has finished asynctask?
(sry my code is way to dirty)
Create an interface
interface CallBack {
fun asyncompleted(list:ArrayList<Address_all>)
}
Implement in searchFragment.
class searchFragment: Fragment(), CallBack {
fun asyncCompleted(list:ArrayList<Address_all>) {
println(list)
}
}
Create a method in buildingFragment
var callback: CallBack
setCallback(value) { callback = value }
set callback after creating buildingFragment instance in searchFragment
val a = buildingFragment()
a.setCallback(this)
call asyncompleted method after setting list3
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
handleJson2(result)
//merge to longitude and latitude with original data
if(list2.size==30){
mergeList()
}
callback.asyncompleted(list3)
}