Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use refactoring to exchange the type of a variable for another?

Tags:

Android Studio provides powerful refactoring, for example Rename. I can use it to change the name of variables, fields, parameters, however I cannot seem to find a way to rename a type. For example:

LinearLayout layout = (LinearLayout) v.findViewById(....);
// ........
// A bunch of code using `layout` many times

How can I quickly refactor LinearLayout to RelativeLayout and have it be applied to the rest of the code too? And can I do the same thing for fields?

like image 418
kiruwka Avatar asked Apr 30 '15 13:04

kiruwka


People also ask

What is Extract variable refactoring?

If you come across an expression that is hard to understand or it is duplicated in several places throughout your code, the Extract Variable refactoring Ctrl+Alt+V can help you deal with those problems placing the result of such expression or its part into a separate variable that is less complex and easier to ...

How do you extract a variable?

Highlight the code you want to extract to a variable and press ⌥⌘V (macOS), or Ctrl+Alt+V (Windows/Linux), to extract it. Extracting parameters can be useful in improving the readability of your code.


1 Answers

Short Answer

The function you are looking for is Type Migration!

A Type Migration can be performed by right clicking on the type of a variable or field and then selecting Refactor -> Type Migration. Alternatively you can use these keyboard shortcuts:

  • On a Mac: Shift + + F6
  • On Windows: Shift + Ctrl + F6

Just choose the type you want to migrate to, click refactor and Android Studio starts working its magic!


Long and more detailed Answer

You seem to misunderstand what Rename actually does.

Rename can be used to literally rename elements. So you can change the name of a variable, parameter, method or class with it. For example if you have a class named Foo and you want to change its name to Bar you can do that easily with Rename.

But you cannot rename LinearLayout since it is framework class and those of course cannot be modified. This however shouldn't be a problem at all because you don't actually want to rename LinearLayout, do you? What you actually want to do is change the type from LinearLayout to RelativeLayout. And there is another very useful refactor feature to do exactly that, it is called Type Migration.

You can perform a Type Migration by right clicking on any variable whose type you want to exchange for another and then selecting Refactor -> Type Migration. After that a Dialog pops up and you can enter the type you want to migrate to, in your case RelativeLayout. Then just click Refactor and Android Studio starts working its magic. There may be an additional popup window informing you of all the things in your code which cannot be migrated automatically. Just scan through the list of conflicts and when you are done hit Ignore and fix those conflicts manually.

Here is an example of Type Migration at work. I started out with this code:

private LinearLayout mLayout;

private void doStuff(ViewGroup container) {
    LinearLayout layout = (LinearLayout) container.findViewById(0);

    layout.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ...
        }
    });

    mLayout = layout;
    fooTheBar(layout);   
}

private void fooTheBar(LinearLayout layout) {
    ...
}

Now I performed a Type Migration to RelativeLayout on the local variable layout in doStuff(). The result looks like this:

private RelativeLayout mLayout;

private void doStuff(ViewGroup container) {
    // Here is the only conflict which could not be refactored automatically.
    // I had to change the cast to RelativeLayout manually.
    RelativeLayout layout = (LinearLayout) container.findViewById(R.id.linearLayout);

    layout.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ...
        }
    });

    mLayout = layout;
    fooTheBar(layout);
}

private void fooTheBar(RelativeLayout layout) {
    ...
}

As you can see Type Migration did excellent work. The type of the field and even the type of the parameter of fooTheBar() was changed to RelativeLayout. There was only one conflict. Android Studio couldn't automatically change the type of the cast at the very top of doStuff(). I had to fix that manually. As I mentioned earlier I was warned about this conflict while performing the refactoring.

You could of course ask yourself why it could change the type of the field and the parameter automatically but couldn't change the type of a cast, but if you think about it that actually makes a lot of sense:

The part of the code it couldn't migrate automatically was (LinearLayout) container.findViewById(R.id.linearLayout). This method of course looks for a View with the id R.id.linearLayout. This View might be defined in a layout xml or it may be added to the container dynamically at runtime but in any case it is not something which can just be refactored automatically without the risk of breaking functionality. It is something only the developer can decide how to handle and that's why you are warned about it.

like image 59
Xaver Kapeller Avatar answered Sep 28 '22 13:09

Xaver Kapeller