일주일 전엔가 잠깐 자동차 부품 삽입기 납품 건 때문에 시끄러웠던 다음 날, 대차거래 상환/체결 상위 종목을 보면서 이러다 전환사채 주식이 상장되지 않을까 했는데 그 주 금요일에 동시에 2개의 공시가 또 올라왔다. 먼저 비교적 작은(?) 건부터 보자면 미래산업 상무가 11월 24일 딱 자동차 부품 납품 공시 띄운 날에 50만주를 장내매도했다는 공시이다.

  일반적으로 이런 내용의 경우 회사 내부 직원이 가지고 있던 주식을 소량(?)이지만 장내매도했으니 악재로 여기는데, 나도 아직 이 회사에 미련을 가지고 있는 주주인지라 전체 유통 주식수에 비한다면 비중이 작고 또 그 날 고가가 635원이었던 것을 고려하면 '그냥 그 사람이 개인적으로 급전이 필요했나보다'하면서 애써 합리화할 수 있었다. 그러나 정작 더 중요한 공시는 사실 이 공시와 같이 올라온 (주)엠에스에이 라는 회사의 주식보유상황보고서였다. 이 공시 덕분에 그동안 드러나지 않았던 주주들 중 일부가 드러났고, 여기에 더 보태서 그 주주가 가지고있던 전환사채권을 매매계약으로 타인에게 넘긴 상황이 공시가 된 것이니 이건 그냥 무조건 긍정적으로 생각을 했다간 큰 일 날 수도 있는 것이었기 때문이다. 아래 사진이 해당 공시를 캡쳐한 것이다(비고란에 있던 매수인으로 추정되는 사람의 이름과 회사는 혹시라도 개인 privacy 문제가 생길까봐 지웠다. 혹시라도 이 글을 보는 분들은 공시를 확인하기를 바란다.)

  보시다시피 11월 20일에 각각 1억, 1억 5천, 2억, 3억원에 상당하는 전환사채권을 타인에게 넘겼고 해당 전환사채권의 취득단가가 작년 11월 25일에 한양증권의 전환사채권 취득단가인 143원으로 같다. 취득단가가 현재 시세보다 높으니 그냥 앞뒤 안재고 장내매도를 해도 계약당사자들이 취득한 금액보다 약 3배에 달하는 이득을 취할 수 있다. 그리고 12월 1일, 결국 걱정했던 11월 25일 전환사채물량이 12월 4일 자로 상장된다는 공시가 올라왔다. 공시에 기재되어 있는 사항을 살펴보면 작년 11월 25일의 전환사채권 물량이 맞는 것으로 추정된다.

 

 

  현재까지의 진행 상황을 보면 이 공시로 결국 실망매물이 쏟아진 것 같다. 그리고 그 매물들을 450~500원 대에서 누군가는 매수했다. 보통은 이러고 나서 기술적으로 반짝하는 뭔가가 생겼었는데, 미래산업은 어떨지 앞으로 귀추가 주목된다.

  ListView를 만들고 나니까 이번엔 ListView 안에 또 다른 ListView를 만들 필요가 생겼다. ListView 안에 객체로 다른 ListView를 선언해야 하나 하고 다시 여기저기 자료를 찾아봤는데(Google 만세!) 굳이 ListView를 두 번 선언하지 않고도 ExpandableListView라는 class를 이용하여 ParentList, ChildList 식으로 구성하면 되었다. 다만 Android Studio의 자동 완성 기능을 활용해 보니, ExpandableListViewAdapter의 Customizing이 필요했다.

1. 목적 : ExpandableListView의 기본 구조 및 사용법을 알아보자.

2. 개발 환경
 - PC : Windows 7, Android Studio 1.4.1(64-bit)
 - Phone : LG G pro Lollipop(API 21)

3. 참고자료
 1) Android Hive - Android Expandable List View Tutorial (http://www.androidhive.info/2013/07/android-expandable-list-view-tutorial/)
 2) 아라비안나이트 블로그 - ExpandableListView 제작 예시(http://arabiannight.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9CAndroid-ExpandableListView-%EB%A7%8C%EB%93%A4%EA%B8%B0)

4. 과정
 1) activity_main.xml(App에 보여질 전체적인 Layout)에 ExpandableListView를 정의하고,  ExpandableListView의 ParentList와 ChildList에 해당하는 list의 객체들을 각각 parent_listview.xml과 child_listview.xml로 다음과 같이 정의한다. 이 때, .xml 파일명의 사용자의 편의에 따라 다르게 쓸 수 있고 .java 에서 연결할 때 해당 .xml 파일명을 적용하면 된다.

<!-- activity_main.xml -->
<?
xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
    <ExpandableListView
        android:id="@+id/expandablelist"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:groupIndicator="@null">
    </ExpandableListView>
</RelativeLayout>
<!-- parent_listview.xml -->
<?
xml version="1.0" encoding="utf-8"?>

<LinearLayout 
   xmlns:
android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"  
   android
:layout_width="match_parent"
   android:layout_height="match_parent"
   android:padding="10dp">
   <TextView
       android:id="@+id/parenttext"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:padding="5dp"
       android:text="Parent TextView"
       android:textColor="#AA000000"/>
</LinearLayout

 

[xml Code] ExpandableListView에서 ParentListView에 해당하는 'parent_listview.xml'을 통해 parent는 각 원소별로 1개의 TextView로 이루어지게 설계했음을 알 수 있으며, ParentList의 원소를 선택했을 경우 나타날 ChildListView는 'child_listview.xml'에서 보이는 바와 같이 1개의 ImageView와 1개의 TextView로 구성되도록 설계했다.
<!-- child_listview.xml -->
<?
xml version="1.0" encoding="utf-8"?>

<RelativeLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:padding="10dp">
   <ImageView
       android:id="@+id/child_item_icon"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:padding="10dp"
       android:src="@mipmap/ic_launcher"/>
   <TextView
       android:id="@+id/childtext"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_toRightOf="@id/child_item_icon"
       android:layout_gravity="center_vertical"
       android:gravity="center_vertical"
       android:padding="5dp"
       android:text="Child TextView"
       android:textColor="#88000000"/>
</RelativeLayout>

 

 2) 1)의 ExpandableListView가 적용될 CustomAdapter를 다음과 같이 정의한다. 상속받은 method를 @Override 해야함을 잊으면 안된다. 그리고 아래 보기에서 나는 생성자를 통해서 받는 childList를 HashMap 변수를 통해서 연결했지만, 다른 참고자료에서 처럼 List<>등으로 바꾸어 입맛에 맞게 편집하면 된다.


public class
CustomExpandableListViewAdapter extends BaseExpandableListAdapter {

    private Context mContext;
    private ArrayList<String> mParentList;
    private ArrayList<ChildListData> mChildList;
    private ChildListViewHolder mChildListViewHolder;
    private HashMap<String, ArrayList<ChildListData>> mChildHashMap;

    // CustomExpandableListViewAdapter 생성자
    public CustomExpandableListViewAdapter(Context context, ArrayList<String> parentList, HashMap<String, ArrayList<ChildListData>> childHashMap){
        this.mContext = context;
        this.mParentList = parentList;
        this.mChildHashMap = childHashMap;
    }

    /* ParentListView에 대한 method */
   
@Override
    public String getGroup(int groupPosition) { // ParentList의 position을 받아 해당 TextView에 반영될 String을 반환
        return mParentList.get(groupPosition);
    }
    
    @Override
    public int getGroupCount() { // ParentList의 원소 개수를 반환
        return mParentList.size();
    }
    
    @Override
    public long getGroupId(int groupPosition) { // ParentList의 position을 받아 long값으로 반환 
        return groupPosition;
    }
    
    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { // ParentList의 View
        if(convertView == null){
            LayoutInflater groupInfla = (LayoutInflater) this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            // ParentList의 layout 연결. root로 argument 중 parent를 받으며 root로 고정하지는 않음
            convertView = groupInfla.inflate(R.layout.parent_listview, parent, false);
        }

        // ParentList의 Layout 연결 후, 해당 layout 내 TextView를 연결
        TextView parentText = (TextView)convertView.findViewById(R.id.parenttext);
        parentText.setText(getGroup(groupPosition));
        return convertView;
    }

    /* 여기서부터 ChildListView에 대한 method */
    @Override
    public ChildListData getChild(int groupPosition, int childPosition) { // groupPostion과 childPosition을 통해 childList의 원소를 얻어옴
        return this.mChildHashMap.get(this.mParentList.get(groupPosition)).get(childPosition);

    }
    
    @Override
    public int getChildrenCount(int groupPosition) { // ChildList의 크기를 int 형으로 반환
        return this.mChildHashMap.get(this.mParentList.get(groupPosition)).size();

    }
    
    @Override
    public long getChildId(int groupPosition, int childPosition) { // ChildList의 ID로 long 형 값을 반환
        return childPosition;
    }
    
    @Override 
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        // ChildList의 View. 위 ParentList의 View를 얻을 때와 비슷하게 Layout 연결 후, layout 내 TextView, ImageView를 연결
        ChildListData childData = (ChildListData)getChild(groupPosition, childPosition);
        if(convertView == null){
            LayoutInflater childInfla = (LayoutInflater) this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = childInfla.inflate(R.layout.child_listview, null);

            mChildListViewHolder = new ChildListViewHolder();
            mChildListViewHolder.mChildListViewIcon = (ImageView)convertView.findViewById(R.id.child_item_icon);
            mChildListViewHolder.mChildListViewText = (TextView)convertView.findViewById(R.id.childtext);
            convertView.setTag(mChildListViewHolder);
        } else{
            mChildListViewHolder = (ChildListViewHolder)convertView.getTag();
        }

        mChildListViewHolder.mChildListViewText.setText(getChild(groupPosition, childPosition).mChildText);
        mChildListViewHolder.mChildListViewIcon.setImageDrawable(getChild(groupPosition, childPosition).mChildItem);
        return convertView;

    }

    @Override
    public boolean hasStableIds() { return true; } // stable ID인지 boolean 값으로 반환

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } // 선택여부를 boolean 값으로 반환

 

 3) MainActivity.java(ExpandableListView에 객체를 입력하고 동작에 대한 code 작성)을 다음과 같이 coding한다.

public class MainActivity extends Activity {
    public ExpandableListView expandableListView; // ExpandableListView 변수 선언
    public CustomExpandableListViewAdapter mCustomExpListViewAdapter; // 위 ExpandableListView를 받을 CustomAdapter(2번 class에 해당)를 선언
    public ArrayList<String> parentList; // ExpandableListView의 Parent 항목이 될 List 변수 선언
    public ArrayList<ChildListData> fruit; // ExpandableListView의 Child 항목이 될 List를 각각 선언
    public ArrayList<ChildListData> vegetables;
    public ArrayList<ChildListData> etc;
    public HashMap<String, ArrayList<ChildListData>> childList; // 위 ParentList와 ChildList를 연결할 HashMap 변수 선언

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); // activity_main.xml을 MainActivity에 연결

        // ExpandableListView의 ParentList에 해당할 항목을 입력
        parentList = new ArrayList<String>();
        parentList.add("과일");
        parentList.add("채소");
        parentList.add("기타");

        // 앞서 ParentList에 연결할 ChildList 항목을 선언 및 입력
        ChildListData apple = new ChildListData(getResources().getDrawable(R.mipmap.apple), "사과");
        ChildListData pair = new ChildListData(getResources().getDrawable(R.mipmap.pair), "배");
        ChildListData persimmon = new ChildListData(getResources().getDrawable(R.mipmap.persimmon), "감");
        fruit = new ArrayList<ChildListData>();
        fruit.add(apple);
        fruit.add(pair);
        fruit.add(persimmon);

        ChildListData onion = new ChildListData(getResources().getDrawable(R.mipmap.onion), "양파");
        ChildListData cabbage = new ChildListData(getResources().getDrawable(R.mipmap.cabbage), "양배추");
        ChildListData potato = new ChildListData(getResources().getDrawable(R.mipmap.potato), "감자");
        ChildListData sweetPotato = new ChildListData(getResources().getDrawable(R.mipmap.sweetpotato), "고구마");
        ChildListData pumpkin = new ChildListData(getResources().getDrawable(R.mipmap.pumpkin), "호박");
        vegetables = new ArrayList<ChildListData>();
        vegetables.add(onion);
        vegetables.add(cabbage);
        vegetables.add(potato);
        vegetables.add(sweetPotato);
        vegetables.add(pumpkin);

        ChildListData seaweed = new ChildListData(getResources().getDrawable(R.mipmap.seaweed), "미역");
        ChildListData bread = new ChildListData(getResources().getDrawable(R.mipmap.bread), "빵");
        ChildListData mackerel = new ChildListData(getResources().getDrawable(R.mipmap.mackerel), "고등어");
        etc = new ArrayList<ChildListData>();
        etc.add(seaweed);
        etc.add(bread);
        etc.add(mackerel);

        // 위에서 선언한 ParentList와 ChildList를 HashMap을 통해 
        childList = new HashMap<String, ArrayList<ChildListData>>();
        childList.put(parentList.get(0), fruit);
        childList.put(parentList.get(1), vegetables);
        childList.put(parentList.get(2), etc);

        // 앞서 정의해 놓은 ExpandableListView와 그 CustomAdapter를 선언 및 연결한 후
      // ExpandableListView에 대한 OnClickListener 등을 선언

        expandableListView = (ExpandableListView)findViewById(R.id.expandablelist);
        mCustomExpListViewAdapter = new CustomExpandableListViewAdapter(this, parentList, childList);
        expandableListView.setAdapter(mCustomExpListViewAdapter);
        expandableListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
            @Override
            public void onGroupExpand(int groupPosition) {
            }
        });
        expandableListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
            @Override
            public void onGroupCollapse(int groupPosition) {
            }
        });
        expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
                return false;
            }
        });
    }
}

 

(위 Code의 실행 결과)

   

    

 

  이전에 CustomListView를 만들다 보니 ListView에 기본적으로 속할 사진을 미리 project 내부에 등록할 필요가 있었다. 방법을 까먹기 전에 기록해 두려 한다.

1. 목적 : 기본 ListView를 customizing하여 사용해 보자.

2. 개발 환경
 - PC : Windows 7, Android Studio 1.4.1(64-bit)
 - Phone : LG G pro Lollipop(API 21)

3. 과정
 1) App.의 project 내에서 [res] - [drawable] directory를 찾아 우클릭을 누르면 나오는 menu들 중에 [New] - [Image Asset]을 찾아 들어간다.

 

 2) [Image Asset] 창에서 'Asset Type'으로 'launcher Icons'를 선택한 뒤, Image file의 경로로 원하는 image를 찾아 지정한다. 그리고 Resource name으로 App. 개발 중 불러들일 때 사용할 변수명을 입력하고 [Next] 버튼을 눌러 적용 사항을 확인하고 [Finish] 한다.

  

 3) 다음과 같이 image를 반영할 때, 앞에서 지정한 'Resource Name'을 사용한다. 앞서 CustomListView에서 예시를 빌려 왔다.

 

  앞서 기본 ListView code를 보다가 Adapter를 잘 이용하면 사용자의 입맛에 맞는 ListView layout을 적용하여 Custom ListView를 생성할 수 있지 않을까 싶었다. 실제로 검색해보니 많은 분들이 CustomListView를 구성하여 활용하였고, 그 방법 또한 구체적으로 설명을 하고 있었다. 이제 나도 Customizing을 해 봐야지.



[사진 1] Android Studio에서 해당 App의 External Libraries 중 Android API로 주어진 자료들을 뒤져보면 앞서 Adapter에 적용된 'simple_list_view_1.xml'을 사진과 같이 찾을 수 있었다. 이를 통해서 Custom ListView를 만들려면 ListView에 대한 .xml 작성이 필요할 것이라는 추측이 들었다.


1. 목적 : 기본 ListView를 customizing하여 사용해 보자.

2. 개발 환경
 - PC : Windows 7, Android Studio 1.4.1(64-bit)
 - Phone : LG G pro Lollipop(API 21)

3. 참고자료
 1) Using lists in Android (ListView) - Tutorial (http://www.vogella.com/tutorials/AndroidListView/article.html)
 2) berabue 블로그 - ListView의 사용 및 Customizing (http://berabue.blogspot.kr/2014/05/android-listview.html)
 3) 미르의 IT 정복기 (http://itmir.tistory.com/477)

4. 과정
 1) 원하는 모양의 ListView Layout을 만들기 위해 listview_custom.xml을 다음과 같이 만든다. 필요에 따라 TextView를 추가하고 그림(ImageView)를 빼는 등 사용자의 입맛에 맞게 제작하면 된다. 나는 ImageView 1개와 TextView 2개를 다음과 같이 구성하였다.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:padding="10dp">

    <ImageView
        android:id="@+id/listview_pic01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:src="@mipmap/ic_launcher"/>
    <TableLayout
        android:id="@+id/text_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/listview_pic01"
        android:layout_gravity="center_horizontal"
        android:gravity="center"
        android:padding="5dp">
        <TableRow>
            <TextView
                android:id="@+id/listview_text01"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_toRightOf="@id/listview_pic01"
                android:padding="2dp"
                android:text="Text01" />
            </TableRow>
        <TableRow>
            <TextView
                android:id="@+id/listview_text02"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:padding="2dp"
                android:text="Text02"/>
        </TableRow>
    </TableLayout>

</RelativeLayout>

 

 

 

 

 

[사진 2] Custom ListView의 Layout으로 TextView  2개와 ImageView 1개로 위 사진과 같이 구성하려 한다.

 2) Layout을 Customizing했으면 해당 Layout을 받을 ListViewAdapter도 Customizing한다. BaseAdapter를 받아 필수 요소는 아래와 같이 Override하는데, 특히 해당 위치를 보여주는 getView() 같은 경우에는 미리 Custom ListView의 요소를 Holder하여 값을 받도록 지정한다.


public class CustomListViewAdapter extends BaseAdapter {
    // CustomListView의 원소를 각각 배열(Array)로 보관할 ArrayList.
   // 현재 Code에서는 선언만 했을 뿐 사용하지 않았다. 제작자의 기호에 따라 고치면 되겠다.

    private ArrayList<ImageView> m_ListPic;
    private ArrayList<String> m_List01;
    private ArrayList<String> m_List02;

    // CustomListView의 ImageView와 TextView들을 묶어서 Array로 보관할 ArrayList와 자료를 받을 Context, adapter 선언
    private Context mContext = null;
    public ArrayList<CustomListData> mListData = new ArrayList<CustomListData>();
    private CustomListViewAdapter mAdapter = this;

    public CustomListViewAdapter(Context mContext) { // CustomListViewAdapter 생성자
        super();
        this.mContext = mContext;
    }

    @Override
    public int getCount() { // List에 속한 원소의 갯수 count method
        return mListData.size();
    }

    @Override
    public Object getItem(int position) { // CustomListView의 position 위치에 있는 Item을 반환
        return mListData.get(position);
    }

    @Override
    public long getItemId(int position) { // CustomListView의 Item의 position을 반환
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) { // CustomListView를 목록으로 보여줌
        CustomListViewHolder holder; // 이전에 정의한 CustomListView의 원소에 맞춘 Holder를 선언
        if (convertView == null) { // 아직 CustomListView의 구성이 반영되지 않은 경우, 다음과 같이 listview_custom.xml을 반영
            holder = new CustomListViewHolder();

            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.listview_custom, null);

            holder.mListPicHolder = (ImageView) convertView.findViewById(R.id.listview_pic01);
            holder.mListText01Holder = (TextView) convertView.findViewById(R.id.listview_text01);
            holder.mListText02Holder = (TextView) convertView.findViewById(R.id.listview_text02);
            convertView.setTag(holder);
        }else{ // convertView에 구성이 이미 반영되어 있으면(null이 아니면) holder에 연결
            holder = (CustomListViewHolder) convertView.getTag();
        }

        CustomListData mData = mListData.get(position); // 위와 같이 layout 연결 후, position에 ListData를 받아와 
        if (mData.mListPic != null) { // ImageView에 입력될 data가 있을 경우 반영하고
            holder.mListPicHolder.setVisibility(View.VISIBLE);
            holder.mListPicHolder.setImageDrawable(mData.mListPic);
        }else{
            holder.mListPicHolder.setVisibility(View.GONE);
        }

        // holder에 text도 각각 반영. 필요에 따라 위와 같이 mText01/mText02 == null 여부를 따져 반영할 수 있다.
        holder.mListText01Holder.setText(mData.mText01);
        holder.mListText02Holder.setText(mData.mTest02);

        return convertView;
    }

    public void addItem(Drawable icon, String mTitle, String mDate){ // 필수 method는 아니나 ListView에 item을 반영하기 위해 필요
        CustomListData addInfo = null;
        addInfo = new CustomListData();
        addInfo.mListPic = icon;
        addInfo.mText01 = mTitle;
        addInfo.mTest02 = mDate;

        mListData.add(addInfo); // 앞에서 선언한 CustomListData를 받아 ArrayList에 통째로 add
    }

    public void remove(int position){ // 해당 position의 값을 제거하는 method
        mListData.remove(position);
        dataChange();
    }
    public void dataChange(){ // 위 remove(int position) method에서 CustomAdapter에 변경사항이 반영되도록 하는 method
        mAdapter.notifyDataSetChanged();
    }
}

public class CustomListData {
    /* CustomListView가 담을 객체에 대한 Class 생성 */
    // ImageView에 상응
    public Drawable mListPic;
    // TextView01에 상응
    public String mText01;
    // TextView02에 상응
    public String mTest02;
}
public class CustomListViewHolder {
    / * CustomListView의 구성요소에 대한 Holder 생성 */
    // Drawable을 받을 ImageView
    public ImageView mListPicHolder;
    // String mText01을 받을 TextView
    public TextView mListText01Holder;
    // String mText02를 받을 TextView
    public TextView mListText02Holder;
}

 3) 마지막으로 CustomListView를 App에 반영한다. 여기서는 MainActivity.java에 다음과 같이 사용하였다.


public class
MainActivity extends AppCompatActivity {

    public ListView listView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = (ListView)findViewById(R.id.listview); // 이전에 activity_main.xml에 선언되어 있던 ListView와 연결
        final CustomListViewAdapter mAdapter = new CustomListViewAdapter(this);
        listView.setAdapter(mAdapter);

        // CustomListViewAdapter의 addItem() method를 통해 Item 추가
        mAdapter.addItem(getResources().getDrawable(R.mipmap.apple), "과일", "사과");
        mAdapter.addItem(getResources().getDrawable(R.mipmap.pair), "과일", "배");
        mAdapter.addItem(getResources().getDrawable(R.mipmap.potato), "채소", "감자");
        mAdapter.addItem(getResources().getDrawable(R.mipmap.pumpkin), "채소", "호박");
        mAdapter.addItem(getResources().getDrawable(R.mipmap.onion), "채소", "양파");

        // CustomListView의 Item을 누를 경우 Toast를  출력하도록 작성
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
            @Override
            public void onItemClick(AdapterView<?> parent, final View view, int position, long id){
                CustomListData mData = mAdapter.mListData.get(position);
                Toast.makeText(getApplicationContext(), mData.mText01+" "+mData.mTest02+" is selected!", Toast.LENGTH_SHORT).show();
            }
        });
    }
}


(위 Code의 실행 결과)

     

 

  App을 만들다 보니 목록을 만들어 사용자가 목록에서 선택한 값을 받아 처리할 일이 생겼다. 일단 가볍게 ListView의 기본 구조를 살펴보고 그 동작 원리를 파악하여 응용을 하려 한다.

1. 목적 : ListView의 사용법을 습득해 보자.

2. 개발 환경
 - PC : Windows 7, Android Studio 1.4.1(64-bit)
 - Phone : LG G pro Lollipop(API 21)

3. 참고자료
 1) Using lists in Android (ListView) - Tutorial (http://www.vogella.com/tutorials/AndroidListView/article.html)
 2) berabue 블로그 - ListView의 사용 및 Customizing (http://berabue.blogspot.kr/2014/05/android-listview.html)
 3) 미르의 IT 정복기 (http://itmir.tistory.com/477)

4. 과정
 1) activity_main.xml(layout을 설정)에 ListView layout을 다음과 같이 선언해 둔다.


<?
xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
     android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
     android:paddingTop="@dimen/activity_vertical_margin"
     android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

      <ListView
          android:id="@+id/listview"
          android:layout_width="match_parent"
          android:layout_height="wrap_content" />

</RelativeLayout>

 

 2) MainActivity.java(ListView의 Activity와 관련된 code 작성)에 App 생성시 ListView의 동작에 관한 code를 다음과 같이 작성한다. 이 때, 다른 variable과는 달리 ListView는 ListView 자체의 layout을 위 activity_main.xml과 같은 app의 layout에 적용시키는 역할을 하는 "Adapter"가 필요하다.


public class
MainActivity extends AppCompatActivity {

    public ListView listView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = (ListView)findViewById(R.id.listview); // 앞서 activity_main.xml에서 정의한 listview에 대하여 ListView 변수 정의
        String[] listVal = new String[] { "감자", // listView에 반영될 항목을 String[] (배열, Array) 변수로 정의
                "사과",
                "배",
                "양파",
                "호박"
        };

        final ArrayList<String> list = new ArrayList<String>(); // String 변수들을 받는 ArrayList 변수를 선언하여 위 String[] 변수를 반영
        for (int i = 0; i < listVal.length; ++i) {
            list.add(listVal[i]);
        }

        // ArrayAdapter를 통해 Android API platform의 'res' library에 simple_list_item_1.xml에 상응하는 형태로 위의 list를 listView에 반영
        final ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
        listView.setAdapter(mAdapter);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){ // listView에 반영된 item을 Click할 경우 다음 동작을 수행
            @Override
            public void onItemClick(AdapterView<?> parent, final View view, int position, long id){
                final String item = (String) parent.getItemAtPosition(position); // 선택한 값을 String 문자열로 받아들여 Toast 출력
                Toast.makeText(getApplicationContext(), item + " is selected!", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

 

(위 Code의 실행 결과)

      

 

 

 

 

 

 

 

  앞에서 스마트폰에 내장되어 있던 기본 camera 기능을 intent로 불러와 사진을 촬영하는 기능을 살펴보았다. 동작이 제대로 되는 것을 확인했으니 촬영한 사진 경로를 가져다가 ImageView를 받아오는 것은 간단하리라 생각했었다. 그러나 생각은 그냥 생각일 뿐, 역시나 쉽게 되지 않았다. 단순히 Imageview 변수를 선언한 뒤 imageview01.setImageBitmap("Bitmap file"); 혹은 imageview01.setImageURI("URI값");와 같은 method를 사용하면 되리라 생각하고 해당 code를 추가하고 실행해 봤더니 그런 file은 찾을 수 없다는 Log가 나를 반기며, imageview는 텅 빈 채로 출력되는 것이 아닌가?

  아무래도 App에서 직접 camera hardware에 접근하여 사진을 촬영해 저장할 때처럼 FileOutputStream으로 data를 write하고 난 후 바로 해당 파일을 Bitmap 변수로 읽어 ImageView에 반영해야 겠다는 생각이 들었다(이런 방식으로 만들었을 때는 ImageView에 사진이 반영이 안되는 문제는 없었기 때문이다). 그러기 위해 기본 camera intent가 종료된 후 동작할 onActivityResult();를 @Override 하여 다음과 같이 작성하였다.

1. 목적 : Camera App을 직접 만들어 보자.

2. 개발 환경
 - PC : Windows 7, Android Studio 1.4.1(64-bit)
 - Phone : LG G pro Lollipop(API 21)

3. 참고자료
 1) Android Developers - API Guide(http://developer.android.com/intl/ko/guide/topics/media/camera.html)
 2) smile8916님 블로그(http://smile8916.tistory.com/92)

4. 과정
 (시작하기에 앞서, 이전 게시글에 따른 Camera intent 관련 설정을 해주어야 한다.)
 1) activity_main.xml(layout을 설정)에 촬영 결과를 보여줄 ImageView를 다음과 같이 선언해 놓는다.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <TextView
        android:id="@+id/imgpath"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"/>

    <ImageView
        android:id="@+id/resultview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center_horizontal"
        android:layout_below="@id/imgpath" />
</LinearLayout

 

 2) MainActivity.java(앞서 camera intent를 불러들였던 Activity에 해당)에 intent가 정상적으로 동작한 후에 해당 경로로 FileOutputStream을 이용하여 data를 write 할 onActivityResult()를 다음과 같이 Override 한다.


    @Override
   protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == RESULT_OK) // intent 결과 정상적으로 마쳐질 경우
        {
            /* 앞서 수행한 intent request 값이 image capture와 관련된 것일 경우 다음을 수행한다. */
            if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE
            {
                ImageView resultView = (ImageView)findViewById(R.id.resultview); // .xml 에서 선언한 ImageView 변수를 Activity에도 선언한 후
                File tempImg = new File(fileUri.getPath()); // 앞서 지정한 경로에 파일의 경로에
                if(!tempImg.exists()){ // file이 존재하지 않으면
                    Log.d(TAG, "The image doesn't exist : " + tempImg.toString());
                    try {
                        FileOutputStream fos = new FileOutputStream(new File(fileUri.getPath())); // FileOutputStream 변수를 선언한 후
                        try {
                            fos.write(data.getExtras().getByte("data")); // Intent의 data 값을 write 하여 저장
                            fos.close(); // 그러고 나서 FileOutputStream을 종료한다.
                        } catch(IOException e){
                            Log.d(TAG, "IOException occur : " + e.getMessage());
                        }
                    } catch (FileNotFoundException e){
                        Log.d(TAG , "The image doesn't exist : "+ tempImg.toString());
                    }
                }
                Bitmap bm = BitmapFactory.decodeFile(fileUri.getPath()); // 해당 file을 Bitmap으로 decode 하여 저장한 후
                resultView.setImageBitmap(bm); // setImageBitmap() method로 앞서 선언한 ImageView에 촬영한 사진을 입력
                resultView.setRotation(imageViewRotation); // ImageView의 회전
            }
        }
    }

 

(위 code를 실행한 결과) 

 

 

 

 

 

 

 

 

 

 [Camera Intent 촬영 장면]

 [Camera Intent 종료 후 App 화면]

 [촬영된 사진 경로 확인]

 

 

 

 

 

 

 

  가끔 폰을 사용하다보면 Camera 기능을 여기저기에 응용해서 활용하고 있는 본인의 모습을 더러 볼 수 있을 것이다. 어떤 사람은 셀카에 포토샵처럼 보정하는 기능을 더해 사용하기도 하고, 또 어떤 사람은 놓치지 말아야 할 중요한 내용을 부랴부랴 받아 적기를 뒤로 하고 바로 사진으로 포착한다. 이렇듯 가끔 도촬이나 몰카같은 문제가 발생하지 않는다면 camera 기능은 참 유용하다는 생각이 든다. 이제 이 기능을 직접 구현하기 위해 공부해 보자. 오늘은 일단 Android 내의 기본 Camera App을 Intent로 불러다가 쓰는 방법을 살펴보려고 한다.

1. 목적 : Camera App을 직접 만들어 보자.

2. 개발 환경
 - PC : Windows 7, Android Studio 1.4.1(64-bit)
 - Phone : LG G pro Lollipop(API 21)

3. 참고자료 : Android Developers - API Guide(http://developer.android.com/intl/ko/guide/topics/media/camera.html)

4. 과정

 1) AndroidManifest.xml 내 Camera 기능 활용 permission 추가
   : 먼저 카메라 기능과 촬영한 사진을 저장하기 위해 카메라와 외부 저장소에 대한 permission을 설정해 놔야 한다.


 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.zip.camaraexample" >

    <!-- intent로 불러올 기본 camera feature 설정 -->
    <uses-feature android:name="android.hardware.camera2" />
    <!-- 사진을 외부 저장소(SD Card)에 저장할 수 있도록 외부 저장소 write permission 설정 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application ...

 2) MainActivity.java 내 onCreate()에 App을 실행하자 마자 camera intent가 실행되도록 기본 intent code 추가
    : 우선 Android Developer Guide에 기재된 기본 code를 추가해 본다. 그 결과 해당 경로를 따라가면 camera로 촬영한 사진 file이 생성되어 있었다.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // create Intent to take a picture and return control to the calling application
    // 기본 내장 되어 있는 IMAGE CAPTURE 기능을 해당 app.에서 intent로 선언한다. 
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    // 아래 정의한 capture한 사진의 저장 method를 실행 한 후
    fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
    // 먼저 선언한 intent에 해당 file 명의 값을 추가로 저장한다.
    
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name

    // start the image capture Intent
    // 해당 intent를 시작한다. 
    startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);

}

/** Create a file Uri for saving an image or video */
/** 저장할 image file의 이름(URI)을 값을 반환. onCreate()에서 fileUri 값에 반영되는 값을 반환하도록 설계되어 있음 */
private static Uri getOutputMediaFileUri(int type){
    // 아래 capture한 사진이 저장될 file 공간을 생성하는 method를 통해 반환되는 File의 URI를 반환
    return Uri.fromFile(getOutputMediaFile(type));
}

/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    // 외부 저장소에 이 App을 통해 촬영된 사진만 저장할 directory 경로와 File을 연결
    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), "MyCameraApp");
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){ // 해당 directory가 아직 생성되지 않았을 경우 mkdirs(). 즉 directory를 생성한다.
        if (! mediaStorageDir.mkdirs()){ // 만약 mkdirs()가 제대로 동작하지 않을 경우, 오류 Log를 출력한 뒤, 해당 method 종료
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
    }

    // Create a media file name
    // File 명으로 file의 생성 시간을 활용하도록 DateFormat 기능을 활용
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File mediaFile;

    if (type == MEDIA_TYPE_IMAGE){
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                "IMG_"+ timeStamp + ".jpg");
    } else if(type == MEDIA_TYPE_VIDEO) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                "VID_"+ timeStamp + ".mp4");
    } else {
        return null;
    }
    return mediaFile; // 생성된 File valuable을 반환

   (위 code의 실행 결과) 아직 App의 layout.xml을 건드리지 않은 기본 상태이기 때문에 기본 camera intent 가 finish()된 후 Hello World!가 출력된다. 그리고 App에서 지정한 경로로 접근해 보면 camera intent로 촬영한 결과 file이 생성되어 있다.

 

 

 

 

 

 

 

 

 

 

 

   3) 기본 Camera intent로 촬영한 결과물을 App의 ImageView로 확인하기[추가사항] → 다음 글 확인

  어제 .jar 파일의 repack 작업을 하면서 jar 명령어에 대해 정리할 필요가 있었다. 아무래도 각자 다른 개발환경 아래의 컴퓨터를 서로 다른 사람들이 사용하고 있으니 같은 명령어라도 다른 결과물이 나온다는 생각이 들었기 때문이다. 이제 무조건 [Ctrl] + [C] & [Ctrl] + [V] 하기 보다는 과정 하나하나를 이해하려고 노력해야지. 우선은 jar 부터 시작하자.

  먼저 .jar file 자체의 정의를 보니 Java platform에서 app과 같은 응용 프로그램이나 library로 사용할 수 있도록 여러 파일을 묶어 놓은 패키지(packaging) file format으로, 일종의 .zip과 같은 파일 묶음과 같은 것이었다. 그렇다 보니 지난 번에 참조했던 조언과 같이 unzip 명령이 jar file을 풀 수 있었던 모양이다.

"JAR(Java Archive, 자바 아카이브)는 소프트웨어에서 수많은 자바 클래스 파일과 연관 메타데이터, 리소스(텍스트, 그림 등)을 하나의 파일로 모아서 자바 플랫폼응용 소프트웨어라이브러리를 배포하기 위한 패키지 파일 포맷이다.[1]

  JAR 파일은 실제로 ZIP 파일 포맷으로 이루어진 압축 파일로서, 파일 확장자는 .jar이다. 컴퓨터 사용자들은 JDK에 포함된 jar 명령어를 이용하여 JAR 파일을 만들거나 압축을 풀 수 있다. 또, zip 도구를 사용할 수도 있으나 압축 시에는 매니페스트 파일이 처음이어야 하는 경우가 있어서 zip 파일 헤더의 엔트리 순서가 중요하다. JAR 안에서 파일 이름들은 유니코드 텍스트로 되어 있다."

[참고] Wikipedia - https://ko.wikipedia.org/wiki/JAR_(%ED%8C%8C%EC%9D%BC_%ED%8F%AC%EB%A7%B7)

 

  이렇다 보니 .jar file을 사용하고 또 생성하기 위해서는 Java platform 환경이 갖추어져 있어야 하는데, 그것이 JDK(Java Development Kit)이다. 요즘은 인터넷을 활용하는데도 Java platform이 필요하다보니 웬만해서는 다 설치되어 있겠지만, 혹시나 깔끔하게 다시 설치해야 한다면 Oracle 홈페이지 내 Java SE Development Kit를 download하여 설치하면 되겠다(2015년 11월 27일 현재 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 에 방문하면 Java SE Development Kit 8u65/8u66 을 Linux나 Windows 32-bit(x86)/64-bit(x64)와 같은 사용자의 사용 환경에 맞춰 설치할 수 있다).

 

  이렇게 설치하고 나면, 해당 JDK를 사용자가 어느 위치에서나 편하게 활용할 수 있게끔 환경변수를 설정해 주어야 하는데 Windows 7 기준으로 1) [시작] - [컴퓨터] 오른쪽 클릭해 메뉴 도출 - [속성] 순으로 접근하던가 2) [제어판] - [시스템] 순으로 들어가면 나타나는 창에서 왼쪽 상단의 메뉴 중 맨 끝에 있는 [고급 시스템 설정]을 클릭해 [시스템 속성 - 고급 탭] 을 띄워 창 하단의 [환경 변수] 버튼을 클릭, 그리고 path(혹은 Path, PATH)변수에 java.exe에 접근할 수 있도록 (컴퓨터 내 jdk 설치 directory)\bin을 추가한다(혹은 추가되었는지 확인한다). 혹시 이 과정이 귀찮다면 java.exe가 설치되어 있는 폴더 내에서 jar 명령어를 동작시키면 되긴 했는데, 환경변수를 설정하는 쪽이 추후에 더 편리했다.

   

 

  이제 console(ex. cmd)을 띄워, jar 명령어를 다음과 같이 활용한다. 기본적으로 jar {ctxu}[vfm0M] (jar file name).jar (대상이 되는 directory name) (.jar file이 생성되는 지점)으로 구성되는데 주로 중괄호 {}에 해당하는 명령어가 c이면 jar 압축, x이면 jar 압축 해제, 대괄호 []에 해당하는 명령어로 v와 조합할 경우 해당 c 또는 x 명령 수행 과정을 console에 나타내며, f의 경우 해당 manifest를 포함함을 의미한다.

jar {ctxu}[vfm0M] [jar-file] [manifest-file] [-C dir or files] ...

 

  1) {ctxu} 필수 option
    - c : archive 파일(.jar file)을 생성
    - t : [jar-file]에 해당하는 archive file의 content list를 설정
    - x : 뒤에 [jar-file]에 해당하는 archive 파일(.jar file)의 압축 해제
    - u : [jar-file]에 해당하는 archive 파일 내에 들어있는 파일을 수정

  2) [vfm0M] 앞의 {ctxu}의 동작을 도와주는 option
    - v : console 창으로 진행 사항에 관한 메시지를 모두 출력. 안 쓸 경우, 중요 error message만 console 창에 뿌려주었다.
    - f : archive 될 파일 이름을 지정
    - m : manifest 파일로부터 정보를 포함
    - 0 : 저장(묶기)만 하고, zip으로 압축지 않음
    - M : 추가되는 entry에 대해 manifest 파일을 생성하지 않음

  3) [jar-file] archive 대상이 되는 .jar file의 이름

  4) [manifest-file] 정보를 포함할 manifest file의 이름

  5) [-C dir or files] archive 할 directory 명 혹은 file 명. 명기한 순서대로 처리.

 

  (사용 예시) 

 

  Android app으로 word 파일(.docx/.doc)를 볼 필요가 생겨서 관련된 library를 찾다가 먼저 Apache POI를 발견했다. 아직 App 개발에 익숙하지 않아 개발 환경을 꾸미는 것만으로도 구글링하면서 진땀을 뺐는데, 겨우겨우 관련 .jar file을 import하고 compile을 해보니 이게 웬 걸. duplicate class 어쩌구 하는 error가 떡하니 뜨는게 아닌가?

 

 

  구글링으로 해당 error의 이유를 보니 애초에 배포된 xmlbeans-2.6.0.jar 내에 중복된 이름의 class가 있어 그렇다고 한다. 이 문제를 해결하려면 직접 xmlbeans-2.6.0.jar를 푼 다음(unzip) 다시 jar로 repack을 해야한다는데, 일단 개발환경 내에 jar 명령어가 동작할 수 있도록 JDK를 설치해야 했다(JDK는 android studio의 구동을 위해 필히 설치해야하는 항목이었으므로 보통은 C:\Program Files\Java 내에 jdk1.x.x_xx 따위의 directory로 정리되어 설치되어 있을 것이다). 그리고 다른 경로에서도 java.exe를 활용할 수 있도록 window의 Path 환경변수에 (내 컴퓨터 내 Java jdk 경로)\bin을 추가해 놓아야 했다.

   

  

 

  그리고 POI-bin 내에 xmlbeans-2.6.0.jar 파일을 찾아 압축을 푼다. 나는 여기서 7-Zip을 활용했다. 압축을 풀다 보면 문제가 됐었던 중복된 class 파일들에 대해 대체여부를 묻는 창이 뜨는데 '모두 예(A)'를 선택하여 대체했다.

 

  다음으로 콘솔을 실행하여 압축을 푼 해당 directory에 들어가서 'jar cf (repack할 jar file명).jar -C *'을 수행했다. 다른 분들의 조언에 따르면 'jar cf (repack할 jar file명).jar -C * .'을 해야한다는데, 내 컴퓨터 환경에서는 그렇게 하면 환경 자체의 문제점이 있는 모양인지 손상된 jar file이 생성되어 제대로 동작하지 않았다. 혹시나 나와 비슷한 문제를 겪고 있는 분들이 있다면 jar 명령어에 관한 reference를 찾아 살짝 바꿔서 실행해 보면 원하는 결과가 나올지도 모르겠다.

 

 

  이제 새로 생성된 xmlbeans-2.6.0-repack.jar를 app library에 추가하여 compile/run을 시켜보았다. 그 결과 실행은 되긴 했으나 app이 XWPFDocument(); method를 거치는 순간 중단되는 문제가 발생하였다. 그러나 이 문제는 xmlbeans-2.6.0.jar 파일의 유무와 상관없이 그전에도 일어났던 터라 해당 파일과는 상관이 없으리라 생각된다. 이제 이 다음 문제를 해결해야지.

 

 

  조금 전에 전일 대차 상환 종목 중에 눈에 띄었던 한화생명(088350)을 내친 김에 분석해 보기로 했다. 우선 다른 고수 분들이 그러했듯이 발행 주식수 및 유통 주식수을 알아본다. 일전에 유상증자를 맞아본 적이 있고 너무 유통주식수가 많은 종목에 무턱대고 진입했다가 마음 고생을 한 적이 있는터라 주식수의 중요성을 뼈 저리게 통감했다. 이제는 이 부분부터 따져서 투기가 아닌 투자를 하려고 한다.

  생각보다 유통 주식수가 많았다. 그나마 아래 주요 주주 현황과 같이 장중에 거래되는 주식보다는 보유 지분이 많아서 다행이긴 한데, 그렇다 하더라도 거의 2억 주에 달하니 많은 것 아닌가 싶다. 액면가는 5000원 인데 어쩌다 이렇게 주식 수가 많아졌는지 확인해 봐야지 싶다.

 

  기업개요를 보면 베트남, 중국 등 해외 현지의 보험시장에 진출하는 등 사업 확장에 신경을 쓰는 모양인데 분기보고서를 통해 연결 회사들의 현황을 살펴봐야 되지 않을까 싶다.

  지난 2분기때는 Earning Surprise였다가 3분기에는 급격하게 손실을 본 이유는 무엇일까? 전년동기의 매출이 지나치게 컸던걸까? 아니면 2분기에 반짝하는 호재가 있었던 것일까? 이 부분도 보고서를 살펴봐야 알 수 있을 것 같다.

+ Recent posts