Interface as variable?

Hi everyone, I am taking a mobile android development class and they are using Java but I was allowed to do it in Kotlin. In one of the examples, there is an interface being used in java as a variable.

I have been trying to get it to work in Kotlin, but it keeps crashing.

How would I be able to get it to function the same?

Java Code

public interface FragmentTracker {
 public void fragmentVisible(String s);
 public void goNext();
 public void goBack();
 public void saveNameAndLastName(String name, String lname);
 public void saveCityAndZip(String city, String zip);
 public void saveDetail(String detail);
 public void finished();
}

// class
public class Fragment1 extends Fragment {
 private FragmentTracker ft; // this is where it is being initialized as a variable
 private View v;
 public static final String fragmentTitle="Personal Info";
 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
 Bundle savedInstanceState) {
 //Toast.makeText(getContext(),"Visible",Toast.LENGTH_SHORT).show();
 ft.fragmentVisible(fragmentTitle);
 // Inflate the layout for this fragment
 v= inflater.inflate(R.layout.first_fragment, container, false);
 Button b_next=v.findViewById(R.id.next_button);
 b_next.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View view) {
 ft.goNext();
 }
 });
 return v;
 }

This is what I tried in Kotlin

interface FragmentTracker {
    fun fragmentVisible(s: String)
    fun goNext();
    fun goBack();
    fun saveNameAndLastName(name: String, lname: String);
    fun saveCityAndZip(city: String, zip: String);
    fun saveDetail(detail: String);
    fun finished();
}

// the class
    private lateinit var ft: FragmentTracker // kotlin lets me do this but it fails below
    private var v: View? = null;

    companion object {
        const val fragmentTitle = "Personal Info";
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        ft.fragmentVisible(fragmentTitle) // it fails here
        v = inflater.inflate(R.layout.fragment_1, container, false)

        v?.findViewById<Button>(R.id.next_button)?.setOnClickListener {
            ft.goNext();
        }
        return v;
    }

Any help/guidance would be awesome

Is the error “lateinit property message has not been initialized”?
Runnable example:

fun main() {
    Foo().onCreate()
}

class Foo {
	lateinit var message: String // Non-nullable
	fun onCreate() {
	    println(message.length)
	}
}

If so, the error describes it well but I suspect explaining some of the terminology may help.Initialized means “set up”. To initialize a variable is to “give it a value”.

In you Java code you have a line as follows:

private FragmentTracker ft; // this is where it is being initialized as a variable

^ Your comment is partially incorrect. Here you are declaring a variable–you are saying a thing by the name “ft” with the type of “FragmentTracker” is a variable belonging to the class. You are not initializing the variable ft with a starting value. Technically Java adds a hidden initialization to null so that the real version in Java is: private FragmentTracker ft = null;

Or in fewer words:

val myVariable: String // Declaring a variable, saying it exists
myVariable = "Hello World" // Initiailzing a variable with a value, giving it a value

In Java, you can declare a variable without providing a starting value. Java gives your object a default value of null (or 0, or 0.0, or false depending on the type). Kotlin requires that you pick the starting value yourself.

If you were trying to make a one-for-one copy of your code in Kotlin, you could have declared your ft variable as nullable, private var ft: FragmentTracker? = null. Since in Java, all variables are nullable, this version is what your classmates are using when in Java.

It’s great to force null safety but sometimes we know a variable will never be null since the first thing someone does is call some starter function that sets the value. In this case, we no longer want to declare ft as nullable and deal with null safety all over the class. Instead, we want some convenient way of temporarily allowing it to be null, and we want to tell the compiler that we will take on the responsibility of making sure it is initialized properly through some other means.

Using lateinit allows us to say, this variable should never be null*, however, we know it will be null for a brief moment until the class is initialized. Without lateinit, we’d only be able to perform this initialization in a constructor as constructors are always a valid place to give your class’s variables their starting values.

1 Like

I believe @arocnies meant it could be private var ft: FragmentTracker? = null.

1 Like

Good catch, I wrote that wrong by leaving out the null but I also accedintelly left in lateinit. What I meant was:
The Kotlin equivalent to Java would be:

private var ft: FragmentTracker? = null

I edited my original reply

2 Likes

I figured out the issue. It was not the lateinit at all.

I was trying to do something with a toolbar when I needed to edit a TextView. I was able to resolve that

Thanks for the help and suggestions!

1 Like