Custom ListView 예제

|

Android에서 ListView 샘플입니다. ListView는 제일 많이 사용하는 UI 컴포넌트 중 하나이다보니 코드 재활용이 빈번합니다. 그래서 여기 템플릿으로 활용할 수 있는 예제를 하나 포스팅해봅니다. 참고로 GridView도 똑같은 방법으로 사용하면 됩니다.

ListView의 스크롤 속도를 부드럽고 빠르게 하기 위해서는 디자인 패턴 중 ViewHolder Pattern을 사용합니다. Android에서 XML에서 리소스를 읽어오는 findViewById 함수는 시간이 많이 걸리는 함수입니다. ViewHolder 패턴을 사용하면 최초에 한 번 findViewById 함수로 찾은 리소스를 Holder 안의 변수에 맵핑을 해놓아서 다음 번에 찾을 때 훨씬 빠르게 찾을 수 있습니다. (Cache와 같은 원리입니다.)

아래는 ViewHolder 패턴을 적용한 예제입니다.

item_view_log.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/layout_background"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingLeft="15dp"
  android:paddingRight="15dp"
  android:orientation="vertical">

  <TextView
    android:id="@+id/timestamp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="timestamp"
    android:textColor="@color/ics_theme_darkblue"
    android:textSize="14sp" />

  <TextView
    android:id="@+id/desc"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Description"
    android:textColor="@color/darkgray"
    android:textSize="14sp" />

</LinearLayout>


LogListAdapter.java

public class LogListAdapter extends BaseAdapter {

  private final Context mContext;
  private ArrayList<BaseInfo> mList;

  public LogListAdapter(Context context) {
    mContext = context;
  }

  public void refresh(ArrayList<BaseInfo> list) {
    mList = list;
    notifyDataSetChanged();
  }

  @Override
  public int getCount() {
    if(mList == null) {
      return 0;
    }

    return mList.size();
  }

  @Override
  public BaseInfo getItem(int position) {
    if(mList == null) {
      return null;
    }

    return mList.get(position);
  }

  @Override
  public long getItemId(int position) {
    if(mList == null) {
      return 0;
    }

    return position;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    ItemHolder holder = null;
    View row = convertView;

    if(row == null) {
      LayoutInflater inflator = (LayoutInflater) mContext
          .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      row = inflator.inflate(R.layout.item_view_log, null);

      holder = new ItemHolder();

      holder.timestamp = (TextView) row.findViewById(R.id.timestamp);
      holder.desc = (TextView) row.findViewById(R.id.desc);

      row.setTag(holder);
    } else {
      holder = (ItemHolder) row.getTag();
    }

    final BaseInfo item = getItem(position);
    if(item != null) {
      if(item.getTimestamp() == 0) {
        holder.timestamp.setVisibility(View.GONE);
      } else {
        String timestamp = SnowTimeUtil
            .getTimeAsString(STRING_FORMAT.TIMESTAMP_FORMAT, item.getTimestamp());
        holder.timestamp.setText(timestamp);
        holder.timestamp.setVisibility(View.VISIBLE);
      }

      holder.desc.setText(item.toString());
    }

    return row;
  }

  class ItemHolder {

    TextView timestamp;
    TextView desc;
  }

  ;
}


그 다음에는 ListView나 GridView를 배치해놓고 setAdapter() 메소드를 이용해서 위의 Adapter를 세팅해주면 됩니다.

dp와 px간 관계

|

각 화면 밀도에서의 dp와 px간 비율

각 화면 밀도에서 dppx간의 환산표입니다. 하지만, 모든 단말에 대해 100% 일치하지는 않습니다. 단말에 따라 같은 밀도라도 비율이 조금 다른 경우도 있으니 주의해야 합니다.

밀도 dp px
ldpi 1dp 0.75 px
mdpi 1dp 1 px
hdpi 1dp 1.5 px
xhdpi 1dp 2 px
xxhdpi 1dp 3 px
xxxhdpi 1dp 4 px

Activity간 데이터 전달하기 (사용자 정의 클래스)

|

Activity간 사용자 정의 클래스 데이터를 전달하는 예제 코드입니다. Activity간 데이터를 이동시킬 때는 그 데이터를 Serializable(또는 Parcelable) 해주어야 데이터가 전달됩니다.

데이터를 Serializable 화 하는 건 다음과 같이 Serializable 인터페이스를 구현해주는 것으로 충분합니다.


MyObject.java

class MyObject implements Serializable {

  int nID;
  String strName;

  MyObject(int _id, String _Name) {
    nID = _id;
    strName = _Name;
  }
};


Activity 코드들은 각각 다음과 같습니다.

firstActivity.java

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class firstActivity extends Activity {

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Button btnTest = (Button) findViewById(R.id.btnLaunch2ndActivity);
    btnTest.setOnClickListener(myButtonClick);
  }

  Button.OnClickListener myButtonClick = new Button.OnClickListener() {
    public void onClick(View v) {
      Intent intent = new Intent(firstActivity.this, secondActivity.class);

      MyObject obj = new MyObject(314, "SnowDeer");
      intent.putExtra("StringData_1", "첫번째 String 데이터");
      intent.putExtra("StringData_2", "두번째 String 데이터");
      intent.putExtra("ObjectData", obj);

      startActivity(intent);
    }
  };
}


secondActivity.java

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class secondActivity extends Activity {

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_2);

    TextView tvView = (TextView) findViewById(R.id.tvTextView);

    Intent intent = getIntent();
    if(intent != null) {
      String strText = "";
      MyObject obj;

      obj = (MyObject) intent.getSerializableExtra("ObjectData");

      strText = "StringData_1 : " + intent.getStringExtra("StringData_1") + "\n" +
          "StringData_2 : " + intent.getStringExtra("StringData_2") + "\n" +
          "MyObject.ID : " + obj.nID + "\n" +
          "MyObject.Name : " + obj.strName;

      tvView.setText(strText);
    }
  }

  Button.OnClickListener myButtonClick = new Button.OnClickListener() {
    public void onClick(View v) {
      Intent intent = new Intent(secondActivity.this, firstActivity.class);
      startActivity(intent);
    }
  };
}

디자인 패턴 UML 모음(Headfirst 디자인 패턴 책 발췌)

|

어댑터(Adapter) 패턴

image


옵저버(Observer) 패턴

image

image


스트래티지(Strategy) 패턴

image

image


스테이트(State) 패턴

image


템플릿 메소드(Template Method) 패턴

image


데코레이터(Decorator) 패턴

데코레이터 패턴을 써야 하는 이유입니다.

image

image

image


커맨드(Command) 패턴

image


컴포지트(Composite) 패턴

image


팩토리(Factory) 패턴

image

image


추상 팩토리 메소드(Abstract Factory Method) 패턴

image


퍼샤드(Facade) 패턴

image


이터레이터(Iterator) 패턴

image

프록시(Proxy) 패턴

image

디자인 패턴 특성별 분류

|

디자인 패턴을 Creational/Structural/Behavioral 특성으로 분류하면 다음과 같습니다.


image


Organizing Design Patterns by Purpose

Creation Patterns

  • Deal with initializing and configuring classes and objects
Structural Patterns
  • Deal with decoupling interface and implementation of classes and objects

Behavioral Patterns

  • Deal with dynamic interactions among societies of classes and objects


Organizing Design Patterns by Scope

Class Patterns

  • Deal with relatinships between classes and their subclasses
  • Relationships established through inheritance, so they are fixed at compile time(static)
  • inheritance : white-box reuse

Object Patterns

  • Deal with object relatinships
  • Relationships can be changed at runtime(dynamic)
  • Composition : Black-box reuse, to avoid reaking encapsulation, and implementation dependency