https://kotlinlang.org logo
#android
Title
# android
g

Gavin Ray

03/11/2020, 5:07 PM
Kotlin as a language is comfy though, barring the Android bit.
m

Mikael Alfredsson

03/11/2020, 5:09 PM
Moving to a thread since you have a big question. I think you have over-engineered the dialog popup, but I don’t know all requirements so im not sure.
you can inherit from DialogFragment and just open it as a normal fragment instead of dealing with “window” objects directly.
g

Gavin Ray

03/11/2020, 5:11 PM
I didn't engineer any of this at all, which is part of the problem (I have never even done Android development before). This app was outsourced to foreign developers before I came on to the company =/
Sorry for the long series of texts, I should have definitely put it in a thread on the first comment, my mistake.
👍 1
m

Mikael Alfredsson

03/11/2020, 5:13 PM
so you basically just want to add a new button opening the same dialog as you can open from another page as well?
g

Gavin Ray

03/11/2020, 5:14 PM
Yeah, if you see the image, that pop-up screen on the bottom of the two screens is currently triggered from the join button on the left screen. I just need to trigger that from the new floating Join button on the right screen
m

Mikael Alfredsson

03/11/2020, 5:15 PM
where does the
joinGameButton()
function live? (in which class)
g

Gavin Ray

03/11/2020, 5:16 PM
The function to trigger it is coded as a private method into
GameFragment
though. I tried making it public, doing
val gameFragment = GameFragment.newInstance()
inside of
DetailFragment
and then
gameFragment.joinGamePopup()
but it breaks because of
Dialog(context)
inside of the
joinGamePopup()
method in
GameFragment
where does the
joinGameButton()
function live? (in which class) 
GameFragment
m

Mikael Alfredsson

03/11/2020, 5:17 PM
does it use alot of other data from GameFragment, or could you extract it to a new class?
context is easy to pass in as an argument to the new class, but do you need anything else?
let me explain the problem. a fragment doesn’t actually have a context, the context is the activity that the fragment is attached to, so if you just create a new instance of a fragment and then try to get the context, you will get
null
g

Gavin Ray

03/11/2020, 5:19 PM
So the arguments that it takes are an instance of
JoinGameModel
, which has some information about the game the player is trying to join, and
position
, which after several hours I figured out is a magic variable that gets passed into fragments denoting their index. I was able to recreate the
JoinGameModel
instance because it gets
gameData
from the parent fragment (GameFragment), and I tried hardcoding `0`/`1` as the
position
to try to trigger it on the first or second fragment.
m

Mikael Alfredsson

03/11/2020, 5:21 PM
so if you can extract the function to its own class, make sure that you pass JoinGameModel in as a parameter (from either screen that opens this dialog) and context as a second parameter, this should work nicely
g

Gavin Ray

03/11/2020, 5:21 PM
It looks like
Dialog(context)
is where most of the stuff happens in that method. This seems to create the pop-up window and populate it with info. So assuming I can have the right
context
value in there, it should work right?
Yeah but what is
context
Copy code
class GamesFragment: Fragment(), SwipeRefreshLayout.OnRefreshListener{

    var context: MainActivity? = null
Copy code
private fun joinGamePopup(gameJoin: JoinGameModel,position:Int) {
            val dialog = Dialog(context)
Copy code
2020-03-11 13:22:50.418 26091-26091/com.plei.dev E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.plei.dev, PID: 26091
    java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources$Theme android.content.Context.getTheme()' on a null object reference
        at android.app.Dialog.<init>(Dialog.java:175)
        at android.app.Dialog.<init>(Dialog.java:149)
        at com.plei.screens.games.fragment.GamesFragment.joinGamePopup(GamesFragment.kt:246)
        at com.plei.screens.games.fragment.DetailFragment$_initialize$1.onClick(DetailFragment.kt:92)
m

Mikael Alfredsson

03/11/2020, 5:23 PM
context is and object in android that holds more or less all important stuff. It tells you the current theme, language, resourcefile pointers, screen measurements and what not. Application, Activity and Services has contexts (with minor differences) but fragments doesn’t so they have to get teh context form the outside (e.g Activity)
Copy code
joinGamePopup(context:Context, gameJoin: JoinGameModel,position:Int)
g

Gavin Ray

03/11/2020, 5:24 PM
So I need to figure out how to get the context from the parent
GameFragment
into the
DetailFragment
function here to pass into context?
m

Mikael Alfredsson

03/11/2020, 5:25 PM
no, you should not try to pass contexts between fragments yourself. the OS will make sure you have a context in your fragment when its showing on the screen
refactor the method to take context as a parameter and move it to a separate class so you don’t have to instantiate GameFragment for this
(normally people use a DialogFragment instead which handles basically everything you have in line 2 to 18)
g

Gavin Ray

03/11/2020, 5:28 PM
Okay uhm, I can add the
context
as an argument but moving it to a separate class may very well be out of the scope of my abilities with 48 hours of Android/Kotlin experience.
m

Mikael Alfredsson

03/11/2020, 5:28 PM
learning by doing.. I think it will be fine.
just create a new kotlin class
GamePopup
or something
move the popup function into that new class
(not trying to make something nice right now, only getting it to work)
g

Gavin Ray

03/11/2020, 5:30 PM
Screenshot from 2020-03-11 13-30-00.png
m

Mikael Alfredsson

03/11/2020, 5:31 PM
you could also just copy the function into your other fragment as well, but that will be really ugly
g

Gavin Ray

03/11/2020, 5:31 PM
Wait how is this even working if it says
context
is a type-mismatch?
but that will be really ugly
This whole codebase is... shudder
m

Mikael Alfredsson

03/11/2020, 5:32 PM
it expects a non null variable and you are giving it a nullable variable
g

Gavin Ray

03/11/2020, 5:32 PM
The dev used ID selectors to read values from text instead of data
m

Mikael Alfredsson

03/11/2020, 5:33 PM
replace
context
with
requireContext
(runtime you will get the same exception. but the IDE might be happier)
or
context!
g

Gavin Ray

03/11/2020, 5:34 PM
`
Copy code
var context: MainActivity?
Replace
MainActivity?
with
context!
?
m

Mikael Alfredsson

03/11/2020, 5:34 PM
no, but where you use it
Activities are contexts so MainActivity can be casted to Context without any problem, but you have MainActivity? which can only be casted to Context? (notice the ?, aka nullable sign)
g

Gavin Ray

03/11/2020, 5:35 PM
Ohhh
I didn't know Kotlin allowed types to be multiple things at once
m

Mikael Alfredsson

03/11/2020, 5:37 PM
you have inheritance, so you can always just extend a base object, or/and you can add interfaces to a class allowing the class to be typecasted to any ancestor or interface type.
g

Gavin Ray

03/11/2020, 5:38 PM
Okay so select the entire
joinGamePopup
and refactor it to a new class?
m

Mikael Alfredsson

03/11/2020, 5:39 PM
Lets see if that is possible (depending on how many things it uses from the GameFragment) but yes, start with that
g

Gavin Ray

03/11/2020, 5:40 PM
image.png
They really single-purposed this ;..;
m

Mikael Alfredsson

03/11/2020, 5:40 PM
no problem, just continue 🙂
g

Gavin Ray

03/11/2020, 5:41 PM
Okay its extracted
Copy code
package com.plei.screens.games.fragment

import androidx.fragment.app.Fragment
import com.plei.models.JoinGameModel

open class GamesFragment1 : Fragment() {
    fun joinGamePopup(gameJoin: JoinGameModel, position: Int) {
m

Mikael Alfredsson

03/11/2020, 5:42 PM
you should not have it in a fragment, just a class called GamePopup
Copy code
class GamePopup {
    fun joinGamePopup(gameJoin: JoinGameModel, position: Int) {
g

Gavin Ray

03/11/2020, 5:42 PM
Which of the "refactor" options is that?
(also where should I put the class file?)
m

Mikael Alfredsson

03/11/2020, 5:43 PM
oh, sorry, with refactor i just ment the act of refactoring, not any special IDE tricks.
g

Gavin Ray

03/11/2020, 5:44 PM
Ohh kk
So just create a file called
GamePopup.kt
anywhere and paste that method in there
Put it in
screens/games/fragment
?
m

Mikael Alfredsson

03/11/2020, 5:44 PM
yep, the placement of the file is less important
g

Gavin Ray

03/11/2020, 5:44 PM
kk
Done 👌
m

Mikael Alfredsson

03/11/2020, 5:46 PM
in your GameFragment you can now create a
Copy code
val gamePopup = GamePopup()
somewhere in the beginning (still not super solution, but easiest to explain 🙂 )
g

Gavin Ray

03/11/2020, 5:46 PM
It's got a ton of un-resolved references
Because it calls other methods and imports from the fragment
m

Mikael Alfredsson

03/11/2020, 5:47 PM
GameFragment or GamePopup?
g

Gavin Ray

03/11/2020, 5:47 PM
GamePopup
m

Mikael Alfredsson

03/11/2020, 5:47 PM
ok, yea, that is what i was afraid of. Imports are easy, the IDE will help you with that
lets see which methods it complains about
g

Gavin Ray

03/11/2020, 5:49 PM
Copy code
Unresolved reference: paymentProcessPopup
Unresolved reference: Intent
Unresolved reference: startActivity
Unresolved reference: R
Unresolved reference: PaymentActivity
Unresolved reference: isPaymentAdded
Unresolved reference: joinGame
Unresolved reference: positiveButton
Unresolved reference: getButton
Unresolved reference: sharedPreference
Unresolved reference: AlertDialog
Unresolved reference: setBackgroundDrawable
Unresolved reference: Dialog
Unresolved reference: WindowManager
c

Christophe Smet

03/12/2020, 9:21 AM
Just pay a senior Android dev to look at it ?
g

Gavin Ray

03/12/2020, 5:01 PM
@Christophe Smet Lol no chance the business owners would pay money for that, but I eventually got it after 14 hours 👍
c

Christophe Smet

03/12/2020, 7:05 PM
haha too bad, welcome to Kotlin and Android tho 😉
12 Views