반응형

Guava: Google Core Libraries for Java

  • Base

 - Objects.equal() : equal 비교시 null 체크를 하지 않아도 된다.

 - Objects.hashCode() : hash코드 생성을 보다 쉽게 만들 수 있다.

 - Objects.toStringHelper() : toString객체를 보다 쉽게 만들 수 잇다.

  -> 일반적인 코드 :

public class Book {
private String title;
private String writer;
private int price;

public String getTitle() {
return title;
}

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

public String getWriter() {
return writer;
}

public void setWriter(String writer) {
this.writer = writer;
}

public int getPrice() {
return price;
}

public void setPrice(int price) {
this.price = price;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Book book = (Book) o;

if (price != book.price) return false;
if (title != null ? !title.equals(book.title) : book.title != null) return false;
return !(writer != null ? !writer.equals(book.writer) : book.writer != null);

}

@Override
public int hashCode() {
int result = title != null ? title.hashCode() : 0;
result = 31 * result + (writer != null ? writer.hashCode() : 0);
result = 31 * result + price;
return result;
}

@Override
public String toString() {
return "Book{" +
"title='" + title + '\'' +
", writer='" + writer + '\'' +
", price=" + price +
'}';
}
}

  -> Guava를 이용한 코드

public class Book {
private String title;
private String writer;
private int price;

public Book(String title, String writer, int price) {
this.title = title;
this.writer = writer;
this.price = price;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
Preconditions.checkNotNull(title);
this.title = title;
}

public String getWriter() {
return writer;
}

public void setWriter(String writer) {
this.writer = writer;
}

public int getPrice() {
return price;
}

public void setPrice(int price) {
this.price = price;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Book book = (Book) o;
return Objects.equal(this.title, book.title) && Objects.equal(this.writer, book.writer)
&& this.price == book.price;

}

@Override
public int hashCode() {
return Objects.hashCode(this.title, this.writer, this.price);
}

@Override
public String toString() {
return Objects.toStringHelper(this)
.add("title", title)
.add("writer", writer)
.add("price", price)
.toString();
}
}

작성하다보니 Objects.toStringHelper 가 deprecated가 되었네요.. 이건 MoreObject.toStringHelper()를 이용하면 됩니다.

 - Preconditions : 객체 정보의 null과 같은 정보가 있는지를 미리 확인하여 exception을 낸다.

  -> 일반적인 코드

public void setTitle(String title) {

if(title == null) {
throw new NullPointerException("title must not be null!");
}

this.title = title;
}

  -> Preconditions를 이용

public void setTitle(String title) {
Preconditions.checkNotNull(title);
this.title = title;
}

 - Joiner : Collections객체들이나 array객체들의 정보들을 string으로 변경해준다.

List names = new ArrayList<>();
names.add("test1");
names.add("test2");
names.add("test3");

Joiner.on(", ").join(names); // test1, test2, test3

 - Splitter : Joiner와 반대로 split 캐릭터를 기준으로 Iterator객체로 변환하여 준다.

Iterator names = Splitter.on(",")
.trimResults()
.omitEmptyStrings()
.split("test1, test2, test3").iterator();

names.next(); //test1
names.next(); //test2
names.next(); //test3

  • Collections
 - Collections객체를 생각하면 기본적으로 List, Set, Map등을 생각합니다. 그리고 이런 Collection 객체들을 생성할 때 new 를 통해 객체 생성을 하죠.
기본적으로 List 를 본다면 new ArrayList<Strig>();와 같이 합니다. 하지만 Guava에서는 static factory 생성자를 이용합니다.

Lists.newArrayList();
Sets.newHashSet();
Maps.newHashMap();

 - Immutable Collections : 변경 불가능한 Collection.. 객체들에 대한 의도하지 않은 변경을 막고 Thread-Safe 한 객체를 만들 수 있다.

Set<String> nameSet = Collections.unmodifiableSet(new LinkedHashSet<String>(Arrays.asList("test1", "test2", "test3")));
Set<String> nameSet = ImmutableSet.of("test1", "test2", "test3");

이와 같이 변경불가능 객체를 만들 때 기존 코드보다 간결하게 만들 수 있다. Set 이와에 Map에 대해서도 알아보면.

Map<String, Integer> mapValue1 = new LinkedHashMap<>();
mapValue1.put("test1", 1);
mapValue1.put("test2", 2);
mapValue1.put("test3", 3);
Map<String, Integer> unModifiedMap = Collections.unmodifiableMap(mapValue1);

Map<String, Integer> mapValue2 = ImmutableMap.<String, Integer>builder()
.put("test1", 1).put("test2", 2).put("test3", 3)
.build();

Map<String, Integer> mapValue3 = ImmutableMap.of("test1", 1, "test2", 2, "test3", 3);

이와 Immutable Collection이 있는 것들은
  • ImmutableCollection
  • ImmutableList
  • ImmutableSet
  • ImmutableSortedSet
  • ImmutableMap
  • ImmutableSortedMap
  • ImmutableMultiset
  • ImmutableSortedMultiset
  • ImmutableMultimap
  • ImmutableListMultimap
  • ImmutableSetMultimap
  • ImmutableBiMap
  • ImmutableClassToInstanceMap
  • ImmutableTable
이렇게 존재한다. 기존 java 코드보다는 훨씬 간결한 코드를 이용할 수 있다.
 - BiMap : key에 대한 unique한 값을 보장하는게 아니라 value에 대한 unique 성을 보장한다.
 - MultiSet : element의 중복을 허용한다.
 - MultiMap : Map이 Key의 중복을 허용하지 않지만,  MultiMap은 Key의 중복을 허용한다. MultiMap은 Map<K, Collection<V>>의 특성을 가지고 있다.

  • Functional programming

public interface Function {
@Nullable T apply(@Nullable F input);
}

이와 같이 F를 입력 받아서 T의 결과를 리턴한다.
예를 든다면 마일을 입력받아서 킬로미터로 출력한다.

Function<Integer, Double> calcMileToKillometer = new Function<Integer, Double>() {
@Override
public Double apply(@Nullable Integer input) {
return input * 1.60934;
}
};

double miles = calcMileToKillometer.apply(1);

- filter / transform
 객체에 있는 특정 값들이 속한 객체들만 골라낸 Collection을 만들거나, 특정 값들만 뽑아낸 새로운 Collection을 만들어 낼 수 있다.

List<Book> bookList = ImmutableList.of(new Book("Android", "test", 100), new Book("Java", "test2", 200), new Book("Object", "test3", 300));
List<Book> androidBookList = ImmutableList.copyOf(Collections2.filter(bookList, new Predicate<Book>() {
@Override
public boolean apply(@Nullable Book input) {
return "Android".equals(input.getTitle());
}
}));

List<String> titleList = ImmutableList.copyOf(Collections2.transform(bookList, new Function<Book, String>() {
@Override
public String apply(@Nullable Book input) {
return input.getTitle();
}
}));


우선 제가 자주 사용하는 것들로만 정리..
내부적으로 아직 @Beta annotation이 된 것들도 많아서.. 아직 그것들에 대해서는 적어두진 않았습니다. 


반응형
반응형


안드로이드 개발하는 개발 패턴으로는 MVC( Model - View, Controller)와, MVVM(Model - View, ViewModel), 그리고 MVP(Model - View - Presenter)방법이 있습니다. 이 세가지 방법에는 각자만의 스타일과 장단점을 가지고 있구요. 안드로이드 개발자들이 많이 늘어나고 좀더 편한 개발 방법들을 추가하면서 나오는 방법들이지 않을 까 합니다.

1. MVC ( Model - View - Controller )

 - Model : 안드로이드에서 사용될 데이터들.

 -  View : activity_main.xml 과 같은 view layout

 - Controller : Activity, Fragment 들...

알게 모르게 가장 많이 사용된 패턴이지 않을 까 생각됩니다. 그런데 View와 Controller의 coupling이 너무 강합니다. 누구 하나 땔래야 땔 수 없는 구조이죠. 우리가 알고 있는 좋은 구조는 loose coupling이 많아야 좋은 구조라고 배웠을 겁니다. 그래서 장기적으로 봤을 대 어떤 구조로 가야 좋을 지 생각해 볼 필요가 있습니다.


2. MVVM ( Model - View - ViewModel )

ViewModel은 Controller와 View의 구조를 통합적으로 가지고 있다고 보시면 될 거 같습니다. ViewModel을 독립적으로 가져갈 수 있지만, 나중에 View가 변경된다면 ViewModel을 한번에 다 변경해야 할 필요도 있어 보입니다. 가끔 Git에서 안드로이드 ui 라이브러리나 componet를 보면 mvvm으로 구현된 것들이 많았던 것으로 기억됩니다. 이 방법이 그나마 View에 대한 가장 독립적인 방법이지 않았을 까 생각됩니다. 


3. MVP ( Model - View - Presenter )

전체적인 패턴이 MVC와 비슷합니다. Controller가 Presenter로 보시면 될 듯 하지만 틀린 점이라면 View에 대한 관리와 접근은 Activity에서 하고, Model에 대한 컨트롤러 역활은 Presenter에서 하게 됩니다. 


이 세 방법에 대한 생각은 제 주관적인 생각입니다. MVC, MVVM, MVP 뭐 하나 나쁘다 좋다 할 방법은 없다고 생각 됩니다.  각자만의 장단점이 있고 누가 어떻게 사용하느냐 그리고 어떤 프로젝트 인지에 따라서도 많이 틀려질 것으로 보입니다. 저는 최근에 프로젝트를 MVP방법으로 진행했습니다. MVP를 사용하면서 경험을 해봤을 대 각각 구조에 대해서 loose coupling적인 방법으로 구현을 할 수 있었지만, 너무 독립적으로 진행하다보니 해당 interface에 대한 구현이 많아지는 것을 느낄 수 있었습니다. 다른 프로젝트를 진행한다면 다시 MVP방법을 사용해 볼려고는 합니다. 단지 저는 MVC, MVVM방법보다는 그래도 가장 느슨한 결합도를 가졌다고 보여집니다.

공부하면서 만든 샘플은 git에 올려 둡니다. 그냥 참고 자료에요.

https://github.com/drcarter/AndroidDevPattern

반응형
반응형

Dagger2

url : http://google.github.io/dagger/

요즘 안드로이드 개발에서 Dependency Injection방법을 이용한 개발 방법이 이슈로 자리잡고 있는 듯 합니다. 더군다나 네임드 개발자로 알려진 Jake Wharton 형님이 발표한 자료도 있습니다.

https://speakerdeck.com/jakewharton/dependency-injection-with-dagger-2-devoxx-2014

2라는 숫자가 있는 것을 보면 Dagger1이 있다는 얘기가 됩니다. 처음 Dagger는 Square에서 나왔습니다. 

http://square.github.io/dagger/

이 사이트에 가시면 자세한 설명을 보실 수 있어요. 나중에 Dagger에 대한 샘플을 작성해 볼 생각입니다.


Dagger2를 얘기한 이유는 프로젝트가 google github에 있다는 것 때문입니다. 믿고 써보는 google??이라서?


Dagger2에서 중요한 Annotation은  @Module, @Provides, @Component, @Inject 정도 일 것 같습니다.

@Module : Module로 구성되고, 내부에서 주입될 객체들을 provide해주는 것.

@Provides : 객체 주입에 필요한 내용을 리턴해주는것

@Component : Module과 Inject간의 Bridge같은 역활.

@Inject : 객체의 주입.

대충 이런정도의 설명... 저는 참 설명을 못하네요 ㅡ.ㅡ


Dagger2를 이용하기 위한 전반적인 순서 입니다.

gradle 스크립트에 아래와 같은 내용을 추가 해 줍니다.

apply plugin: 'com.neenbedankt.android-apt'

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
    }
}

android {
    ........

    dependencies {
        .......
        provided 'javax.annotation:jsr250-api:1.0'
        apt 'com.google.dagger:dagger-compiler:2.0'
        compile 'com.google.dagger:dagger:2.0'
    }
}


그리고 사용할 모델들을 정의 해 줍니다. 저는 아래와 같은 예제를 만들어 보았습니다.

Motor.java

public class Motor {

    private int speed;

    public Motor() {
        this.speed = 0;
    }

    public int getSpeed() {
        return speed;
    }

    public void accelerate(int value) {
        speed = speed + value;
    }

    public void setSpeed(int value) {
        speed = value;
    }

    public void brake() {
        speed = 0;
    }
}


Bike.java

public class Bike {

    private Motor motor;

    public Bike(@NonNull Motor motor) {
        this.motor = motor;
    }

    public void increaseSpped() {
        this.motor.setSpeed(this.motor.getSpeed() + 1);
    }

    public void decreaseSpeed() {
        if (this.motor.getSpeed() > 0) {
            this.motor.setSpeed(this.motor.getSpeed() - 1);
        }
    }

    public int getSpeed() {
        return this.motor.getSpeed();
    }
}


그리고 Module을 정의 합니다.

우선 MotorModule.java 입니다. 이건 단순히 Motor객체를  제공해 주는 역활만 합니다.

@Module
public class MotorModule {

    @Provides
    Motor provideMotor() {
        return new Motor();
    }
}


BikeModule.java입니다.

@Module(
        includes = MotorModule.class
)
public class BikeModule {

    @Provides
    Bike provideBike(Motor motor) {
        return new Bike(motor);
    }
}


여기서 보면 Bike객체를 제공해주는 @Provides을 보면 Motor객체가 파라미터로 존재합니다. 과연 이 파라미터는 어디서 제공받고 있을까 라는 의문이 듭니다. 이건 @Module의 includes부분에 보면 MotorModule.class를 포함하고 있고, MotorModule에서 Motor객체를 provides하고 있기에 가능합니다.

이렇게 되면 BikeModule안에서 Motor객체를 필요로 하는 곳에서는 모두 파라미터로 정의하면 Motor객체를 제공받을 수 있습니다.

그리고 Provides된 것을 Inject 하여 사용할 수 있는데 Bike객체를 Inject하여 사용해 볼까 합니다.

그럼 Bike는 어디에서 사용할 까요? 위에서 중요 Annotation중에 @Component를 알려드렸습니다. Module과 Inject간의 Brige같은 역활을 한다고 했는데 사용할 Component는 아래와 같습니다.

MainActivityComponent.java

@Component(
        ...
        modules = {
                ...
                BikeModule.class
        }
)
public interface MainActivityComponent extends ActivityComponent {
    void inject(@NonNull MainActivity mainActivity);
}


이와 같이 Component를 정의했습니다.

이렇게 Component를 정의하고 컴파일 하면 "DaggerMainActivityComponent가" 만들어 집니다. 이걸 가지고 실질적으로 객체 주입을 진행할 수 있죠.

DaggerMainActivityComponent.builder()
        ...
        .bikeModule(new BikeModule())
        .build();


이와 같이 하면 사용할 Component에 대해서는 준비가 끝납니다. 그럼 객체 주입은 어떻게 할까요?  몇가지 방법이 있지만 저는 객체에 @Inject anootation방법을 이용해서 사용 할려고 준비했습니다.


@Inject
Bike bike;

이와 같이 하여 Bike객체 사용에 대한 준비를 합니다.

이건 component에서 inejct라는 메소드를 정의해서 상용할 수 있는 부분입니다 그럼  inject라는 것을 하지 않고 사용할 방법은 있을까요? Component에서 getBike()라는 메소드를 만들어서 사용할 방법도 있긴 합니다.

이 예제에 대한 소스는

https://github.com/drcarter/Dagger2Example

에 올려둿습니다..

저도 Dagger2에 대해서 공부하고 정리하다 보니 설명이 명확하진 않은 듯 합니다.

오히려 맨 위에 Jake Wharton형님이 pt로 설명한 내용이 더 좋을지도요 ㅎㅎㅎ


반응형
반응형

안드로이드에서 onActivityResult는 이전 activity에서의 결과를 intent를 통해서 받을 수 있습니다. 개발문서 참고

당연히 Fragment안에서도 onActivityResult가 있고, fragment안에서 startActivityForResult를 통해서 해당 결과를 받을 수 있습니다.


/**
     * Call {@link Activity#startActivityForResult(Intent, int)} from the fragment's
     * containing Activity.
     */
    public void startActivityForResult(Intent intent, int requestCode) {
        if (mHost == null) {
            throw new IllegalStateException("Fragment " + this + " not attached to Activity");
        }
        mHost.onStartActivityFromFragment(this /*fragment*/, intent, requestCode);
    }

이와 같이 fragment에서 startActivityForResult를 하기 위해선 fragment가 activity에 attach되어 있어야 합니다.

fragment에서 startActivityForResult를 Activity에서 보낸 것처럼 할려면

getActivity().startActivityForResult(.......)

로 해서 보내면 됩니다. 이렇게 해서 보내면 onActivityResult로 받게 되는 결과가 fragment에서 바로 받는 것이 아니라 activity에 있는 onActivityResult에서 받게 되어서 이 결과를 바로 fragment에 전달해 줘야 하죠.... 이 부분이 조금 껄끄러운 면이 있습니다. Lollipop에서 material design을 적용하여 Activity Transition이나 Fragment Transition을 적용할려면, onStartActivityForResult의 호출지점이 fragment가 아닌 activity에서 하는 것처럼 보내야 합니다.

그럼 Activity의 onActivityResult로 받은 결과를 어떻게 fragment에 전달하는 것이 좋을까요?

여러가지 방법이 있을 듯 합니다. 가장 쉬운 방법으로는 Activity에서 해당 fragment의 instance를 두고서 전달할 public method를 만들어 전달 할 방법이 있을 것 같습니다. 

제가 이번에 소개해볼 방법은 event bus[Otto - An event bus by Square]를 이용한 방법을 소개해 볼까 합니다. 

ActivityResultEvent.java 로 만든 class 입니다.


public class ActivityResultEvent {

    private int requestCode;
    private int resultCode;
    private Intent data;

    public static ActivityResultEvent create(int requestCode, int resultCode, Intent intent) {
        return new ActivityResultEvent(requestCode, resultCode, intent);
    }

    private ActivityResultEvent(int requestCode, int resultCode, Intent data) {
        this.requestCode = requestCode;
        this.resultCode = resultCode;
        this.data = data;
    }

    public int getRequestCode() {
        return requestCode;
    }

    public int getResultCode() {
        return resultCode;
    }

    public Intent getData() {
        return data;
    }
}

이건 단순히 onActivityResult로 받는 requestCode, resultCode, intent정보를 가지고 fragment에 전달해 주는 용도 입니다.

EventBus.java


public class EventBus extends Bus {

    private static EventBus instance;

    public static EventBus getInstance() {
        if (instance == null) {
            synchronized (EventBus.class) {
                if (instance == null) {
                    instance = new EventBus();
                }
            }
        }
        return instance;
    }

    private Handler handler = new Handler(Looper.getMainLooper());

    @Override
    public void post(final Object event) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            super.post(event);
        } else {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    EventBus.super.post(event);
                }
            });
        }
    }
}

이건 ActivityResultEvent를 보내줄 Bus입니다.. 이 Bus의 이용 방법은 위에 링크 걸린 홈페이지에 자세히 설명 되어 있어요 

해당 EventBus를 Singleton으로 만들었습니다. 


이 부분의 사용 방법은

activity의 onActivityResult에서


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//        super.onActivityResult(requestCode, resultCode, data);
        EventBus.getInstance().post(ActivityResultEvent.create(requestCode, resultCode, data));
    }

이와 같이 호출하면 되고,

fragment에서는 

    @SuppressWarnings("unused")
    @Subscribe
    public void onActivityResultEvent(@NonNull ActivityResultEvent event) {
        onActivityResult(event.getRequestCode(), event.getResultCode(), event.getData());
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
//        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case Constants.RequestCode.REQUEST_CODE_NAME_INPUT: {
                if (resultCode == Activity.RESULT_OK) {
                    String text = data.getStringExtra(KeySets.KEY_NAME_INPUT);
                    if (!TextUtils.isEmpty(text)) {
                        textResult.setText(text);
                    }
                }
                break;
            }
        }
    }

이와 같이 Bus를 통해 받은 정보를 fragment의 onActivityResult로 전달하면 됩니다.

Bus를 통해서 정보 공유는 이요할 곳이 참 많아 보입니다. Service에서 activity나 fragment에 결과의 내용을 전달 할 때 사용해도 되구요.

결과를 만들어 내는 방법에는 여러 방법이 있지만, 사용하는건 개발자의 선택인 듯 합니다. 방법에는 정답이 없으니까요.

source : https://github.com/drcarter/RetriveActivityResult

샘플 소스는 제 git에 올려둡니다.

반응형
반응형


제 취미 중 하나는 검담 프라모델을 모으로 조립하는 것입니다. 그저 조용히 앉아서 조립하고 진열하고.. 

그런데 이번에 Gundam Fix Figuration을 하나 장만했습니다. 사실 구입한지는 거의 반년이 지난  듯합니다. 구매하고 그저 박스에 놓어진 채 조립을 하지 않고 회사 책상 위에 두고 있었으니까요.

처음으로 Gundam Fix를 장만했는데, 이 모델은 항상 건프라 구경하러 갔을 대 deep striker의 진열된 것을 보고 사고 싶었지만 언뜻 가격을 보고는 구입할 용기가 나질 않았습니다. 가격이 생각보다 조금?? 나갔기 때문이죠. 더군다나 나온지 상당히 시간이 지나서 이젠 국내에서 파는 곳도 거의 없었습니다. 해외구매를 해보던 중 일본 아마존에서 생각보다 저렴한? 가격에 올라왔습니다. 그때 당시 엔저 현상으로 관세와 배송비를 다 해도 국내 가격보다는 저렵했었으니까요. 























































































설명서가 있지만, 일본어를 모르다 보니....

Gundam Fix의 장점은 조립과 도색이 다 되어 있다는 것이죠. 하지만 도색이 완벽하게 깔끔?? 한 편은 아닙니다. 이 제품을 구입하고 회사로  배송받았을 대 디자이너가 보더니 도색 부분에서 실망이라고 하긴 했습니다. 하지만 일반인들이 이 정도의 퀄리티로 도색을 하기는 힘들죠. 사실 저도 도색은 힘듭니다. 이것 저것 신경 쓸 부분이 많거든요. 그리고 Gumdam Fix의 장점은 조립하기 쉽습니다. ^^


완성하고 나서 보니.. 왼쪽으로 조금 기울어져 있습니다. 워낙 파츠가 많고 오른쪽 어깨로의 빔?? 때문에 살짝 기울어져 있습니다. 그래도 이건 웅장하고 멋있어요.


와이프가 조립하는 내내 옆에서 보면서 키덜트라고 놀립니다. 건담, 레고.. 이 정도의 어른의 취미는 있어야죠? 그런데 제 두 아이들이 크면 제 취미들로 모은 건담들이 무사할까요? ㅎㅎㅎ

반응형
반응형



hexagon이미지를 만드는 방법입니다.

방법은 간단히.. 이미지의 중심점을 잡고, 반지름을 구한 뒤 중심점에서 각 0도, 60도, 120도, 180도, 240도, 360도 위치의 점을 잇는 선을 그은 뒤 그에 해당하는 이미지만 뽑아내느 방법입니다.

이걸 활용하면 android에서 사용할 HexagonImageView도 만들어 볼 수 있겠죠.

코드는 아래와 같습니다.


private Bitmap getHexagonImage(Bitmap toTransform) {
    Bitmap output = Bitmap.createBitmap(toTransform.getWidth(),
            toTransform.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(output);

    int radius = 0;
    int width = toTransform.getWidth();
    int height = toTransform.getHeight();
    int centerX = width / 2;
    int centerY = height / 2;

    if (width >= height) {
        radius = height / 2;
    } else {
        radius = width / 2;
    }

    Paint paint = new Paint();
    final Rect rect = new Rect(0, 0, toTransform.getWidth(),
            toTransform.getHeight());

    Path path = new Path();
    for (int i = 0; i < 6; i++) {

        int posX = (int) (centerX + radius * Math.cos(Math.toRadians(i * 60 - 30)));
        int posY = (int) (centerY + radius * Math.sin(Math.toRadians(i * 60 - 30)));
        if (i == 0) {
            path.moveTo(posX, posY);
        } else {
            path.lineTo(posX, posY);
        }
    }

    path.close();
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(Color.parseColor("#FFFFFF"));
    canvas.drawPath(path, paint);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    canvas.drawBitmap(toTransform, rect, rect, paint);

    return output;
}


반응형
반응형

1. SpannableString

2. setPaintFlags

3. Html.fromHtml


SpannableString

String udata="SpannableString underline sample";
SpannableString content = new SpannableString(udata);
content.setSpan(new UnderlineSpan(), 0, udata.length(), 0);
mTextView.setText(content);



setPaintFlags

mTextView.setPaintFlags(mTextView.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
mTextView.setText("Paint flag underline sample");



Html.fromHtml

String htmlString="Html from underline sample";
mTextView.setText(Html.fromHtml(htmlString));


반응형
반응형

Genymotion을 이용해서 Android개발 시 기존에 제공해 주는 Emulator에 비해서 상당히 가볍고 빠르게 개발을 할 수 있습니다. 그런데 SDK를 21로 업데이트 후 Genymotion이 계속 ADB연결이 끊기는 현상이 생기곤 합니다. 너무 빈번하게... android studio나 eclipse를 통해서 개발 할 때 restart를 하거나 adb kill-server 후 adb start-server를 하라고도 나오기도 하구요.

adb server is out of date.  killing...
cannot bind 'tcp:5037'
ADB server didn't ACK
* failed to start daemon *
error:

이와 같이 보이면 상당히 난감하죠..


근본적으로 해결 방법을 제시하면

Genymotion -> Setting -> ADB -> Use custom Android SDK tools 를 선택 후 현재 android sdk가 위차한 path를 지정해 주면 됩니다.


간단히 해결!!

반응형

+ Recent posts