Android - Handle the finish of webview loading from the Activity? - android

I have the following Activity :
import android.graphics.Bitmap
import android.os.Bundle
import android.provider.Settings
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.webkit.WebView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class ShowOneContactHtmlActivity : AppCompatActivity() {
private lateinit var maddress :String
private lateinit var mcontact_name : String
private lateinit var mavatar_to_str_base64: String
private lateinit var dialog: MyViewDialog
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_show_html)
val webview = findViewById<WebView>(R.id.webview)
dialog = MyViewDialog(ShowAddressessActivity#this)
dialog.showDialog()
maddress = intent.getStringExtra(SENT_ADDRESS_FROM_ADDRESSES_TO_SHOWONECONTACT_ACTIVITY)
mcontact_name = intent.getStringExtra(SENT_CONTACT_NAME_FROM_ADDRESSES_TO_SHOWONECONTACT_ACTIVITY)
val avatar = intent.getParcelableExtra<Bitmap>(SENT_BITMAP_FROM_ADDRESSES_TO_SHOWONECONTACT_ACTIVITY)
mavatar_to_str_base64 = bitmaptoStringBase64(avatar)
lateinit var htmlstring :String
GlobalScope.launch {
htmlstring = takeHtmlStringofThisContact()
withContext(Dispatchers.Main) {
webview.loadDataWithBaseURL(
"file:///android_asset/",
htmlstring,
"text/html",
"UTF-8",
""
)
dialog.hideDialog()
}
}
}
suspend private fun takeHtmlStringofThisContact():String {
lateinit var onecntcthtmlmaker: HtmlMaker
if (maddress == mcontact_name) {
onecntcthtmlmaker =
HtmlMaker(ShowOneContactHtmlActivity# this, mavatar_to_str_base64, maddress)
} else {
onecntcthtmlmaker =
HtmlMaker(
ShowOneContactHtmlActivity# this,
mavatar_to_str_base64,
mcontact_name
)
}
var smsparser = SmsParser(ShowOneContactHtmlActivity# this)
withContext(Dispatchers.Default) {
var all_messages_of_one_contact = smsparser.loadInboxAndSentOfAddress(maddress)
var sortedlist =
all_messages_of_one_contact.sortedWith(compareBy({ it.m_date_in_milli }))
for (msg in sortedlist) {
onecntcthtmlmaker.putHtmlMessageInCurrentHtml(msg)
}
onecntcthtmlmaker.clearHtmlAtLast()
}
return onecntcthtmlmaker.current_html
}
}
Rather it is unnecessary to see the whole code, my focus is on the dialog which displays a loading.gif. With this code my loading gif disappears when the loading of the url still happens.
I want the loading gif to disappears when the loading of the url has finished.
As I know (correct me if I am wrong) I have to make my WebViewClient and when onPageFinished() is executed then I have to notify the Activity and the dialog to disappear.
Is there another way ? Is there a function that is called, after the webview has stopped loading , in the activity to override it and to set there the disappearance of dialog(i.e loading gif)???

You can use WebViewClient and override onPageFinished:
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
// Here
}
}

Related

I encountered a problem while following a tutorial on building an app with Kotlin

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

Running itch.io game in my android app webview

I have a game made with unity on itch.io I want to open and play this game in my custom android app webview.
For this I'm using.
myWebView.loadUrl("https://teamwood.itch.io/super-auto-pets")
myWebView.settings.javaScriptEnabled = true
Url is being load but on tapping Run Game nothing happen. Can I even perform this in webview
Itch.io supports fullscreen webgl games altough that games can be run in web view if It is not in full screen. For full screen mode you can follow the code like, below is the code of my Game Activity code Which consists simply a web view.
package com.example.game
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Bundle
import android.view.View
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.FrameLayout
import androidx.appcompat.app.AppCompatActivity
class GameActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_game)
val webView: WebView = findViewById(R.id.gameView)
webView.settings.javaScriptEnabled = true
supportActionBar?.hide()
webView.webViewClient= MyBrowser()
webView.webChromeClient = MyWebClient(this#GameActivity.applicationContext,this#GameActivity)
webView.loadUrl("https://teamwood.itch.io/super-auto-pets")
}
internal class MyBrowser : WebViewClient() {
override fun shouldOverrideUrlLoading(paramWebView: WebView, paramString: String): Boolean {
paramWebView.loadUrl(paramString)
return true
}
}
}
open class MyWebClient(private val context: Context,private val activity: GameActivity) : WebChromeClient() {
private var mCustomView: View? = null
private var mCustomViewCallback: CustomViewCallback? = null
protected var mFullscreenContainer: FrameLayout? = null
private var mOriginalOrientation = 0
private var mOriginalSystemUiVisibility = 0
override fun getDefaultVideoPoster(): Bitmap? {
return if (this == null) {
null
} else BitmapFactory.decodeResource(
context.resources, 2130837573
)
}
override fun onHideCustomView() {
(activity.window.decorView as FrameLayout).removeView(mCustomView)
mCustomView = null
activity.window.decorView.systemUiVisibility = mOriginalSystemUiVisibility
activity.requestedOrientation = mOriginalOrientation
mCustomViewCallback!!.onCustomViewHidden()
mCustomViewCallback = null
}
override fun onShowCustomView(
paramView: View?,
paramCustomViewCallback: CustomViewCallback?
) {
if (mCustomView != null) {
onHideCustomView()
return
}
mCustomView = paramView
mOriginalSystemUiVisibility =
activity.window.decorView.systemUiVisibility
mOriginalOrientation = activity.requestedOrientation
mCustomViewCallback = paramCustomViewCallback
(activity.window.decorView as FrameLayout).addView(
mCustomView,
FrameLayout.LayoutParams(-1, -1)
)
activity.window.decorView.systemUiVisibility = 3846
}
}

"evaluateJavascript()" returns "null" as localStorage value of webView

(Sorry for my poor English)
I have a web page which set a local storage value like localStorage.setItem('name', 'myName') , I load this web page inside a webView and I want to access to this local storage value inside the android app so I used below code but it returns "null", it takes half a day but i can't fix it, I'm not android developer so explain me a little more please.
package com.example.myWebViewApp
import android.os.Bundle
import android.os.Handler
import android.util.Log
import android.webkit.ValueCallback
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val myWebView: WebView = findViewById(R.id.webview)
val webSettings = myWebView.settings
webSettings.javaScriptEnabled = true
webSettings.javaScriptCanOpenWindowsAutomatically = true
webSettings.allowFileAccess = true
webSettings.allowContentAccess = true
webSettings.domStorageEnabled = true
webSettings.textZoom = 100
webSettings.allowFileAccess = true
myWebView.loadUrl("http://192.168.1.99:3333")
myWebView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
myWebView.evaluateJavascript(
"window.localStorage.getItem('name');",
ValueCallback<String?> {
n -> run { Log.d("nameTag", "$n") }
}
)
}
}
val refreshLayout = findViewById<SwipeRefreshLayout>(R.id.swipeRefresher)
refreshLayout.setOnRefreshListener {
refreshLayout.isRefreshing = true
Handler().postDelayed(Runnable {
refreshLayout.isRefreshing = false
myWebView.reload()
}, 2000)
}
}
}

Unresolved reference in Kotlin Android Studio fragment

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.

how to check whether asynctask is finshed or not from another class

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)
}

Categories

Resources