使用Android Studio對代碼進行重構

簡介

2013年Google I/O大會上,谷歌推出新的Android開發環境——Android Studio,今後Android程序員有了新的選擇,使用Android Studio進行App開發。AndroidStudio是一項全新的基於IntelliJ IDEA的Android開發環境。相似於Eclipse ADT插件,如今已經成爲了官方推薦的ide,同時Eclipse再也不進行更新。 java

軟件開發中,通過幾個版本迭代,很多程序員會覺的之前的代碼架構可能不知足日益增加的需求,這時候都會想到了重構,關於重構網上也有很多用於的資料。 android

重構資料 程序員

資料裏面列舉了以下幾種方法,對代碼進行重構。 安全

31天重構學習筆記01. 封裝集合
31天重構學習筆記02. 移動方法
31天重構學習筆記03. 提高方法
31天重構學習筆記04. 下降方法
31天重構學習筆記05. 提高字段
31天重構學習筆記06. 下降字段
31天重構學習筆記07. 重命名(方法,類,參數)
31天重構學習筆記08. 使用委派代替繼承
31天重構學習筆記09. 提取接口
31天重構學習筆記10. 提取方法
31天重構學習筆記11. 使用策略類
31天重構學習筆記12. 分解依賴
31天重構學習筆記13. 提取方法對象
31天重構學習筆記14. 分離職責
31天重構學習筆記15. 移除重複內容
31天重構學習筆記16. 封裝條件
31天重構學習筆記17. 提取父類
31天重構學習筆記18. 使用條件判斷代替異常
31天重構學習筆記19. 提取工廠類
31天重構學習筆記20. 提取子類
31天重構學習筆記21. 合併繼承
31天重構學習筆記22. 分解方法
31天重構學習筆記23. 引入參數對象
31天重構學習筆記24. 分解複雜判斷
31天重構學習筆記25. 引入契約式設計
31天重構學習筆記26. 避免雙重否認
31天重構學習筆記27. 去除上帝類
31天重構學習筆記28. 爲布爾方法命名
31天重構學習筆記29. 去除中間人對象
31天重構學習筆記30. 儘快返回
31天重構學習筆記31. 使用多態代替條件判斷

Android Studio是基於優秀的ide的,ide提供了豐富的功能,很方便的對代碼進行重構,下圖是個人Android Studio Refactor菜單,部分快捷鍵與默認快捷鍵不一樣是由於方便而修改的。 架構

Android Studio Refactor

古人云『工欲善其事必先利其器』,因此在對代碼進行重構前,須要詳細瞭解Android Studio提供的功能,下面對AS(Android Studio,後面簡稱AS)菜單進行簡單示例。 app

如何使用

鼠標光標選中或者放在代碼上,按下快捷鍵就能夠彈出當前代碼可使用的功能。 
以下所示: ide

如何使用

代碼與操做示例

  • ChangeSignature,改變函數簽名,能夠修改函數的名字,參數的順序,參數的名字。

Before: 函數

// 改變簽名
    void testChangeSignature(int second, int first) {
        System.out.println(first + "->" + second);
    }

Gif: 工具

改變簽名

After: 佈局

// 改變簽名
    void testChangeSignature(int one, int two) {
        System.out.println(one + "->" + two);
    }

修改前參數依次是second、first,修改是one、two。

  • ChangeClassSignatuere,改變類的簽名,能夠修改類的泛型簽名

Before:

// 改變類的簽名
    void testChangeClassSignatuere() {
        String second = "second";
        int first = 100;
        new ChangeClassSignatuere(second, first);
    }

// **********************分割線******************************* 

public class ChangeClassSignatuere {

    private int first;
    private String second;

    public ChangeClassSignatuere(String second, int first) {
        this.first = first;
        this.second = second;
    }

    @Override
    public String toString() {
        return "ChangeClassSignatuere{" +
                "second='" + second + '\'' +
                ",first=" + first +
                '}';
    }
}

Gif:

改變類簽名

After:

// 改變類的簽名
    void testChangeClassSignatuere() {
        String second = "second";
        int first = 100;
        new ChangeClassSignatuere<Activity>(second, first);
    }
// **********************分割線******************************* 

public class ChangeClassSignatuere<A> {

    private int first;
    private String second;

    public ChangeClassSignatuere(String second, int first) {
        this.first = first;
        this.second = second;
    }

    @Override
    public String toString() {
        return "ChangeClassSignatuere{" +
                "second='" + second + '\'' +
                ",first=" + first +
                '}';
    }
}
  • 修改匿名類爲內部類

Before:

// 匿名類改爲內部類
    void testConvertAnonymousToInner() {
        View.OnClickListener clickListener = new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                System.out.println("onClick");
            }
        };
    }

Gif:

改變類簽名

After:

// 匿名類改爲內部類
    void testConvertAnonymousToInner() {

        View.OnClickListener clickListener = new Abc123();
    }

    private static class Abc123 implements View.OnClickListener {

        @Override
        public void onClick(View v) {
            System.out.println("onClick");
        }
    }

這個是我最喜歡的一個功能,有時候匿名類剛剛開始邏輯很簡單,過不了多久邏輯太多,就可使用快捷鍵變成一個內部類。

  • ConvertToInstanceMethod,修改一個方法變成成員方法

Befor:

// 變成成員方法
    void testConvertToInstanceMethod() {
        TestClass.convertToInstanceMethod(this, "test");
    }

public class TestClass {

    static void convertToInstanceMethod(RefactorDemo demo, String string) {
        System.out.println("convertToInstanceMethod = " + demo);
        System.out.println("convertToInstanceMethod = " + string);
    }
}

After:

// 變成成員方法
    void testConvertToInstanceMethod() {
        this.convertToInstanceMethod("test");
    }

    void convertToInstanceMethod(String string) {
        System.out.println("convertToInstanceMethod = " + this);
        System.out.println("convertToInstanceMethod = " + string);
    }

在修改前,調用convertToInstanceMethod方法,第一個參數相是RefactorDemo,傳遞是this, 修改後就那個方法直接移動到本類中。

  • Copy,複製一個類

Before:

// 複製一個類
    void testCopy() {
        new FirstClass();
    }

public class FirstClass implements Serializable {

    public String first;

    @Override
    public String toString() {
        return "FirstClass{" +
                "first='" + first + '\'' +
                '}';
    }
}

Gif:

複製一個類

After:

public class SecondClass implements Serializable {

    public String first;

    @Override
    public String toString() {
        return "SecondClass{" +
                "first='" + first + '\'' +
                '}';
    }
}
  • EncapsulateFields,壓縮一個字段,間接訪問

Before:

String filed = "filed";

    // 壓縮一個字段,間接訪問
    void testEncapsulateFields() {
        System.out.println(filed);
    }

After:

private String filed = "filed";

    // 壓縮一個字段,間接訪問
    void testEncapsulateFields() {
        System.out.println(getFiled());
    }

    public String getFiled() {
        return filed;
    }

    public void setFiled(String filed) {
        this.filed = filed;
    }

至關於簡介訪問一個field,自動生成setter和getter。

  • GenerifyRefactoring,泛型重構

Before:

// 泛型重構
    void testGenerifyRefactoring() {
        List list = new ArrayList();
        list.add("one");
        list.add("two");
        list.add("three");
    }

After:

// 泛型重構
    void testGenerifyRefactoring() {
        List<String> list = new ArrayList<String>();
        list.add("one");
        list.add("two");
        list.add("three");
    }

自動添加泛型的參數。

  • Inline,內聯函數

Before:

// 內聯
    void testInline() {
        int a = 100;
        int b = 200;
        System.out.println(add(a, b));
    }

    int add(int a, int b) {
        return a + b;
    }

Gif:

After:

// 內聯
    void testInline() {
        int a = 100;
        int b = 200;
        System.out.println(a + b);
    }

原先須要調用一個函數的地方,直接把那個函數裏面的代碼複製過來。

  • InvertBoolean,重構Boolean

Before:

// 重構Boolean
    void testInvertBoolean() {
        System.out.println(checkPaswd(null));
        System.out.println(checkPaswd(""));
        System.out.println(checkPaswd("admin"));
    }

    boolean checkPaswd(String passwd) {
        if (passwd != null && passwd.length() != 0) {
            return true;
        }
        return false;
    }

Gif:

After:

// 重構Boolean
    void testInvertBoolean() {
        System.out.println(checkPaswd(null));
        System.out.println(checkPaswd(""));
        System.out.println(checkPaswd("admin"));
    }

    boolean checkPaswd(String passwd) {
        return passwd != null && passwd.length() != 0;
    }
  • MakeClassStatic,使類變成靜態的

Before:

// 使類變成靜態的
    void testMakeClassStatic() {
        new MyClass().fun();
    }

    String myClassField = "abc";

    class MyClass {
        void fun() {
            System.out.println("myClassField = " + myClassField);
        }
    }

Gif:

After:

// 使類變成靜態的
    void testMakeClassStatic() {
        new MyClass(myClassField).fun();
    }

    String myClassField = "abc";

    static class MyClass {
        private String myClassField;

        public MyClass(String myClassField) {
            this.myClassField = myClassField;
        }

        void fun() {
            System.out.println("myClassField = " + myClassField);
        }
    }

修改前須要調用外部內的成員變量myClassField,實際編譯事後MyClass的class是持有外部類的對象,這樣才能訪問myClassField,經過重構,使得myClassField經過構造方法傳入進去,而後再在fun方法中使用,這樣重構會減小類的依賴。

  • MakeMethodStatic,使方法變成靜態的

Before:

// 使方法變成靜態的
    void testMakeMethodStatic() {
        myFun();
    }

    void myFun() {
        System.out.println("myFun");
    }

After:

// 使方法變成靜態的
    void testMakeMethodStatic() {
        myFun();
    }

    static void myFun() {
        System.out.println("myFun");
    }
  • Move,移動一個類

Before:

// 移動一個類
    void testMove() {
        new MoveClass().fun();
    }

    static class MoveClass {

        String movde;

        @Override
        public String toString() {
            return "MoveClass{" +
                    "movde='" + movde + '\'' +
                    '}';
        }

        void fun() {
            System.out.println(this);
        }
    }

Gif:

After:

// 移動一個類
    void testMove() {
        new MoveClassxxxxxx().fun();
    }

class MoveClassxxxxxx {

    String movde;

    @Override
    public String toString() {
        return "MoveClass{" +
                "movde='" + movde + '\'' +
                '}';
    }

    void fun() {
        System.out.println(this);
    }
}
  • PullMenmberUp,上移

Before:

public class Base {

    public String baseString;

    public Base(String baseString) {
        this.baseString = baseString;
    }

    public void funBase() {
        System.out.println(baseString);
    }
}
public class Sub extends Base {


    public Sub(String baseString) {
        super(baseString);
    }

    public void funSub() {
        System.out.println(baseString);
    }
}

    // 上移
    void testPullMenmberUp() {
        new Sub("base").funSub();
    }

Gif:

After:

public class Base {

    public String baseString;

    public Base(String baseString) {
        this.baseString = baseString;
    }

    public void funBase() {
        System.out.println(baseString);
    }

    public void funSub() {
        System.out.println(baseString);
    }
}

public class Sub extends Base {


    public Sub(String baseString) {
        super(baseString);
    }

}

實際上就是把子類中的方法移動到父類中。

  • PullMenmberDown,下移

Before:

public class Base {

    public String baseString;

    public Base(String baseString) {
        this.baseString = baseString;
    }

    public void funBase() {
        System.out.println(baseString);
    }
}
public class Sub extends Base {


    public Sub(String baseString) {
        super(baseString);
    }

    public void funSub() {
        System.out.println(baseString);
    }
}
    // 下移
    void testPullMenmberDown() {
        new Sub("base").funBase();
    }

After:

public class Base {

    public String baseString;

    public Base(String baseString) {
        this.baseString = baseString;
    }

}

public class Sub extends Base {

    public Sub(String baseString) {
        super(baseString);
    }

    public void funSub() {
        System.out.println(baseString);
    }

    public void funBase() {
        System.out.println(baseString);
    }
}

實際上就是把父類中的方法移動到子類中。

  • Rename,重命名

這個功能也是我最喜歡的,只要選擇重命名一個對象或者資源,全部使用到這個對象或者資源的地方,都會進行從新命名。

Before:

// 重命名
    void testRename() {
        String first = "second";
        System.out.println(first);
    }

Gif:

After:

// 重命名
    void testRename() {
        String second = "second";
        System.out.println(second);
    }
  • ReplaceConstructorWithBuilder,構造方法變成builder

還在羨慕Picasso,Fresco人性化調用方式嗎?很簡單,經過這個功能就能夠快速生成代碼

Before:

public class MyAlertDialog {

    private String title;
    private String message;
    private String okButton;
    private String cancelButton;

    public MyAlertDialog(String title, String message, String okButton, String cancelButton) {
        this.title = title;
        this.message = message;
        this.okButton = okButton;
        this.cancelButton = cancelButton;
    }
}    
    // 構造方法變成builder
    void testReplaceConstructorWithBuilder() {
        new MyAlertDialog("title", "message", "ok", "cancel").show();
    }

Gif:

After:

// 構造方法變成builder
    void testReplaceConstructorWithBuilder() {
        new MyAlertDialog.Builder()
                .setTitle("title")
                .setMessage("message")
                .setOkButton("ok")
                .setCancelButton("cancel")
                .createMyAlertDialog()
                .show();
    }

public static class Builder {
    private String title;
    private String message;
    private String okButton;
    private String cancelButton;

    public Builder setTitle(String title) {
        this.title = title;
        return this;
    }

    public Builder setMessage(String message) {
        this.message = message;
        return this;
    }

    public Builder setOkButton(String okButton) {
        this.okButton = okButton;
        return this;
    }

    public Builder setCancelButton(String cancelButton) {
        this.cancelButton = cancelButton;
        return this;
    }

    public MyAlertDialog createMyAlertDialog() {
        return new MyAlertDialog(title, message, okButton, cancelButton);
    }
}
  • ReplaceConstructorWithFactory,構造方法變成工程方法

Before:

// 構造方法變成工程方法
    void testReplaceConstructorWithFactory() {
        new MyAlertDialog("title", "message", "ok", "cancel").show();
    }

Gif:

After:

// 構造方法變成工程方法
    void testReplaceConstructorWithFactory() {
        MyAlertDialog.newInstance("title", "message", "ok", "cancel")
                .show();
    }
public class MyAlertDialog {    
    private MyAlertDialog(String title, String message, String okButton, String cancelButton) {
        this.title = title;
        this.message = message;
        this.okButton = okButton;
        this.cancelButton = cancelButton;
    }

    public static MyAlertDialog newInstance(String title, String message, String okButton, String cancelButton) {
        return new MyAlertDialog(title, message, okButton, cancelButton);
    }
}

經過上面代碼發現,若是構造方法變成了工廠方式,那麼它的構造參數是private的,這樣調用者只能經過工廠方式來生成對象。

  • ReplaceInheritanceWithDelegation,代理代替繼承

Before:

public abstract class AbsClass {

    public abstract void sayHello();
}

public class ExtClass extends AbsClass {

    @Override
    public void sayHello() {
        System.out.println("hello");
    }
}
    // 代理代替繼承
    void testReplaceInheritanceWithDelegation() {
        new ExtClass().sayHello();
    }

Gif:

After:

public class ExtClass {

    private final AbsClassImpl abs = new AbsClassImpl();

    public void sayHello() {
        abs.sayHello();
    }

    private class AbsClassImpl extends AbsClass {
        @Override
        public void sayHello() {
            System.out.println("hello");
        }
    }
}

    // 代理代替繼承
    void testReplaceInheritanceWithDelegation() {
        new ExtClass().sayHello();
    }

書上說過,組合因爲繼承大概說的就是這個意思。

  • SafeDelete,安全刪除

Before:

// 安全刪除
    void testSafeDelete() {
        String unUsedString = "abc";

        unUsedString = getUnUsedString();
        System.out.println(new Date());
    }

    public String getUnUsedString() {
        return unUsedString;
    }

After:

// 安全刪除
    void testSafeDelete() {
        System.out.println(new Date());
    }

這個比較簡單,若是某個變量沒有使用,那麼直接直接刪除全部引用這個變量的地方。

  • WrapReturnValue,封裝返回值

Before:

// 封裝返回值
    void testWrapReturnValue() {
        System.out.println(getUserName());
    }

    private String getUserName() {
        return "userName";
    }

Gif:

After:

// 包裝下返回值
    void testWrapReturnValue() {
        System.out.println(getUserName().getValue());
    }

    private UserInfo getUserName() {
        return new UserInfo("userName");
    }

    public class UserInfo {
        private final String value;

        public UserInfo(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }
  • RemoveMiddleMan,去除中間人

Before:

// 去除中間人
    void testRemoveMiddleMan() {
        OrderManager manager = new OrderManager();
        manager.newOrder("new");
        manager.confirm("confir");
        manager.invalidOrder("invalid");
    }

    public static class OrderManager {
        private List<String> unProcessOrderList;
        private List<String> processedOrderList;

        public OrderManager() {
            unProcessOrderList = new ArrayList<>();
            processedOrderList = new ArrayList<>();
        }

        public void newOrder(String order) {
            unProcessOrderList.add(order);
        }

        public void confirm(String order) {
            unProcessOrderList.remove(order);
            processedOrderList.add(order);
        }

        public void invalidOrder(String order) {
            processedOrderList.remove(order);
        }

        public void display() {
            System.out.println(unProcessOrderList);
            System.out.println(processedOrderList);
        }
    }

Gif:

After:

// 去除中間人
    void testRemoveMiddleMan() {
        OrderManager manager = new OrderManager();
        manager.getUnProcessOrderList().add("new");
        manager.confirm("confir");
        manager.getProcessedOrderList().remove("invalid");
    }

    public static class OrderManager {
        private List<String> unProcessOrderList;
        private List<String> processedOrderList;

        public OrderManager() {
            unProcessOrderList = new ArrayList<>();
            processedOrderList = new ArrayList<>();
        }

        public void confirm(String order) {
            unProcessOrderList.remove(order);
            processedOrderList.add(order);
        }

        public void display() {
            System.out.println(unProcessOrderList);
            System.out.println(processedOrderList);
        }

        public List<String> getUnProcessOrderList() {
            return unProcessOrderList;
        }

        public List<String> getProcessedOrderList() {
            return processedOrderList;
        }
    }

用途就是,原先OrderManager持有一個List來保存Order,調用方直接使用OrderManager來處理訂單,去除中間人的意思就是說,調用法直接獲取保存Order的容器,調用方直接本身控制容器。

代碼抽取

代碼抽取在實際使用當中很是有用。

  • ExtraMethod,抽取一個方法

Before:

// 抽取一個方法
    void testExtraMethod() {
        Map<String, Integer> map = new HashMap<>();
        map.put("one", 1);
        map.put("two", 2);
        map.put("three", 2);

        System.out.println(map);
    }

Gif:

After:

// 抽取一個方法
    void testExtraMethod() {
        Map<String, Integer> map = initMap();

        System.out.println(map);
    }

    @NonNull
    private Map<String, Integer> initMap() {
        Map<String, Integer> map = new HashMap<>();
        map.put("one", 1);
        map.put("two", 2);
        map.put("three", 2);
        return map;
    }
  • ExtraMethodObject,抽取一個方法到一個對象中

和上面那個差很少,只不過把方法移動到另一個類中。

Before:

// 抽取一個方法到一個對象中
    void testExtraMethodObject() {
        Map<String, Integer> map = new HashMap<>();
        map.put("one", 1);
        map.put("two", 22);
        map.put("three", 33);

        System.out.println(map);
    }

After:

// 抽取一個方法到一個對象中
    void testExtraMethodObject() {
        Map<String, Integer> map = MapUtil.invoke();
        System.out.println(map);
    }

    private static class MapUtil {
        private static Map<String, Integer> invoke() {
            Map<String, Integer> map = new HashMap<>();
            map.put("one", 1);
            map.put("two", 22);
            map.put("three", 33);
            return map;
        }
    }
  • ExtractParameterObject,抽取若干參數成一個類

這個比較使用,有時候一個方法參數太多,能夠把這些參數合併成一個類。

Before:

// 抽取若干參數成一個類
    void testExtractParameterObject() {
        print(100, 200);
    }

    // widht,height --> Size Class
    void print(int width, int height) {
        System.out.println("width = " + width + ", height = " + height);
    }

Gif:

After:

// 抽取若干參數成一個類
    void testExtractParameterObject() {
        print(new Size(100, 200));
    }

    // widht,height --> Size Class
    void print(Size size) {
        System.out.println("width = " + size.getWidth() + ", height = " + size.getHeight());
    }


public class Size {
    private final int width;
    private final int height;

    public Size(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }
}
  • ExtractSuperclass,抽取到父類

Before:

// 抽取到父類
    void testExtractSuperclass() {
        sendEvent("login_success");
    }

    public void sendEvent(Object event) {
        // EventBus.getDefault().send(event);
    }

Gif:

After:

public class BaseExtractDemo {
    public void sendEvent(Object event) {
        // EventBus.getDefault().send(event);
    }
}

public class ExtractDemo extends BaseExtractDemo {
    // 抽取到父類
    void testExtractSuperclass() {
        sendEvent("login_success");
    }
}
  • ExtractConstant,抽取常量

Before:

// 抽取常量
    void testExtractConstant() {
        String email = "admin@123.com";
        String passwd = "1qaz2wsx";

        Bundle bundle = new Bundle();
        bundle.putString("email", email);
        bundle.putString("passwd", passwd);
    }

Gif:

After:

public static final String KEY_EMAIL = "email";
    public static final String KEY_PASSWD = "passwd";

    // 抽取常量
    void testExtractConstant() {
        String email = "admin@123.com";
        String passwd = "1qaz2wsx";

        Bundle bundle = new Bundle();
        bundle.putString(KEY_EMAIL, email);
        bundle.putString(KEY_PASSWD, passwd);
    }
  • ExtractField,抽取成成員變量

Before:

// 抽取成成員變量
    void testExtractField() {
        String testExtractField =  "testExtractField";
        System.out.println(testExtractField);
    }

After:

private String testExtractField;

    // 抽取成成員變量
    void testExtractField() {
        testExtractField = "testExtractField";
        System.out.println(testExtractField);
    }
  • ExtractVariable,抽取成變量

Before:

// 抽取成變量
    void testExtractVariable() {
        System.out.println("long name = " + getLoooooooooooooooooooooooooooooooooooooooooooooooooooooongName());
    }

    String getLoooooooooooooooooooooooooooooooooooooooooooooooooooooongName() {
        return "getLoooooooooooooooooooooooooooooooooooooooooooooooooooooongName";
    }

Gif:

After:

// 抽取成變量
    void testExtractVariable() {
        String name = getLoooooooooooooooooooooooooooooooooooooooooooooooooooooongName();
        System.out.println("long name = " + name);
    }

    String getLoooooooooooooooooooooooooooooooooooooooooooooooooooooongName() {
        return "getLoooooooooooooooooooooooooooooooooooooooooooooooooooooongName";
    }

有時候,一行代碼寫的很長,可使用這個方法,對代碼進行重構。

  • ExtractParameter,抽取成方法的參數

Before:

// 抽取成方法的參數
    void testExtractParameter() {
        printHelloString();
    }

    private void printHelloString() {
        String str = "printHello";
        System.out.println(str);
    }

Gif:

After:

// 抽取成方法的參數
    void testExtractParameter() {
        String str = "printHello";
        printStringAndLength(str);
    }

    private void printStringAndLength(String paramStr) {
        System.out.println(paramStr + " -> " + paramStr.length());
    }

Android資源重構

  • ExtractLayout,佈局文件抽取

Before:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>

Gif:

After:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true">

    <include layout="@layout/view_top" />

    <include layout="@layout/content_main" />

    <include layout="@layout/view_button" />

</android.support.design.widget.CoordinatorLayout>
  • ExtractStyle,樣式抽取

Before:

<TextView  android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" android:textAlignment="center" android:textColor="#f00ff0" android:textSize="18sp" android:textStyle="bold" android:typeface="normal" />

Gif:

After:

<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        style="@style/my_textview_style" />

    <style name="my_textview_style">
        <item name="android:textAlignment">center</item>
        <item name="android:textColor">#f00ff0</item>
        <item name="android:textSize">18sp</item>
        <item name="android:textStyle">bold</item>
        <item name="android:typeface">normal</item>
    </style>

綜合示例

經過一個示例演示怎麼樣重構代碼,示例是一個Activity裏面有個RecyclerView,而後重構代碼,演示怎麼樣分離Adapter,ViewHolder等。

Before:

public class StartActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_start);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        final List<String> data = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            data.add("Text " + (i + 1));
        }

        recyclerView.setAdapter(new RecyclerView.Adapter<MyViewHolder>() {

            @Override
            public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                LayoutInflater layoutInflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                return new MyViewHolder(layoutInflater.inflate(android.R.layout.simple_list_item_1, parent, false));
            }

            @Override
            public void onBindViewHolder(MyViewHolder holder, int position) {
                holder.bind(data.get(position));
            }

            @Override
            public int getItemCount() {
                return data.size();
            }
        });
    }

    class MyViewHolder extends RecyclerView.ViewHolder {

        TextView textView;

        public MyViewHolder(View itemView) {
            super(itemView);
            textView = (TextView) itemView.findViewById(android.R.id.text1);
        }

        void bind(String text) {
            textView.setText(text);
        }
    }
}

Gif: 

After:

public class StartActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private List<String> data;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_start);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        initData();
        initView();
    }

    private void initData() {
        data = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            data.add("Text " + (i + 1));
        }
    }

    private void initView() {
        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(new MyViewHolderAdapter(data));
    }
}

class MyViewHolderAdapter extends RecyclerView.Adapter<MyViewHolder> {

    private List<String> data;

    public MyViewHolderAdapter(List<String> data) {
        this.data = data;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return MyViewHolder.newInstance(parent);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.bind(data.get(position));
    }

    @Override
    public int getItemCount() {
        return data.size();
    }
}


class MyViewHolder extends RecyclerView.ViewHolder {

    public static final int LAYOUT_ID = android.R.layout.simple_list_item_1;

    @NonNull
    static MyViewHolder newInstance(ViewGroup parent) {
        Context context = parent.getContext();
        LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        return new MyViewHolder(layoutInflater.inflate(LAYOUT_ID, parent, false));
    }

    TextView textView;

    public MyViewHolder(View itemView) {
        super(itemView);
        textView = (TextView) itemView.findViewById(android.R.id.text1);
    }

    void bind(String text) {
        textView.setText(text);
    }
}

總結

至此,Android Studio的重構功能講解完成,因爲Android Studio更新很快,不少功能還須要本身去發掘。

『君子生非異也,善假於物也』,好好使用工具,能夠偷個懶。

相關文章
相關標籤/搜索