728x90

본 내용은 강의 수강 내용과 인터넷 검색해서 보강한 자료를 기록해둔다.

AsyncTask 는 Thread 보다 자주 사용하며, MySQL(PHP) 서버와의 통신에서도 사용한다.

import 추가는 Alt + Enter 를 누르라고 팝업 알림창이 나온다. 그러면 눌러주면 된다.

Android Studio 는 오프라인 강의를 들었는데, 단축키 기능이 너무 편리하다.

XML 코드 작성시에도 기본적인 것부터 작성할 수 있게 하고 명령어를 일부 넣어주면 자동으로 팝업되면서 자동완성 기능을 편하게 완성시킨다.


package com.tistory.link2me.app10;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    Button btn_alert;
    Button btn_custom;
    Button btn_progress;
    TextView txt;
    ProgressDialog progressDialog;

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

        btn_alert = (Button) findViewById(R.id.btn01);
        btn_custom = (Button) findViewById(R.id.btn02);
        btn_progress = (Button) findViewById(R.id.btn03);
        txt = (TextView) findViewById(R.id.tv01);

        btn_alert.setOnClickListener(listener);
        btn_custom.setOnClickListener(listener);
        btn_progress.setOnClickListener(listener);
    }

    View.OnClickListener listener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()){
                case R.id.btn01:
                    new AlertDialog.Builder(MainActivity.this)
                            .setTitle("2017 프로야구 우승후보")
                            .setMessage("두산 베어스")
                            .setIcon(android.R.drawable.ic_dialog_alert)
                            .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    Toast.makeText(getBaseContext(), "OK", Toast.LENGTH_LONG).show();
                                    txt.setText("두산 베어즈");
                                }
                            })
                            .setNegativeButton("NO", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    Toast.makeText(getBaseContext(), "NO", Toast.LENGTH_LONG).show();
                                    txt.setText("LG 트윈스");
                                }
                            })
                            .show();
                    break;

                case R.id.btn02:
                    LinearLayout linearLayout = (LinearLayout) View.inflate(MainActivity.this, R.layout.custom, null);
                    final EditText editText = (EditText) linearLayout.findViewById(R.id.et01);

                    new AlertDialog.Builder(MainActivity.this)
                            .setTitle("2017 프로야구 우승 후보")
                            .setView(linearLayout)
                            .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    Toast.makeText(getBaseContext(), "OK", Toast.LENGTH_LONG).show();
                                    String winner = editText.getText().toString();
                                    txt.setText(winner);
                                }
                            })
                            .setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    Toast.makeText(MainActivity.this, "CANCEL", Toast.LENGTH_SHORT).show();
                                }
                            })
                            .show();
                    break;

                case R.id.btn03:
                    DownloadTask task = new DownloadTask(MainActivity.this);
                    task.execute(100);
                    break;
            }
        }
    };

    private class DownloadTask extends AsyncTask<Integer, String, Integer> {

        ProgressDialog progressDialog;
        private Context mContext;

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

        @Override
        protected void onPreExecute() {
            progressDialog = new ProgressDialog(mContext);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            progressDialog.setIcon(android.R.drawable.ic_dialog_info);
            progressDialog.setTitle("Download");
            progressDialog.setMessage("다운로드 중...");
            progressDialog.show(); // show dialog

            super.onPreExecute();
        }

        @Override
        protected Integer doInBackground(Integer... params) {
            //doInBackground 함수는 excute() 실행시  실행됨
            final int taskCnt = params[0]; // 최대 몇인지 설정하는 변수
            publishProgress("max", Integer.toString(taskCnt));
            try {
                for (int i = 0; i < taskCnt; i++) {
                    publishProgress("progress", Integer.toString(i), "번호 " + Integer.toString(i) + "번 수행중");
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            return taskCnt; // onPostExecute()함수의 인수가 됨
        }

        @Override
        protected void onProgressUpdate(String... progress) {
            //onProgressUpdate() 함수는 publishProgress() 함수로 넘겨준 데이터들을 받아옴
            if (progress[0].equals("progress")) {
                progressDialog.setProgress(Integer.parseInt(progress[1]));
                progressDialog.setMessage(progress[2]);
            }
            else if (progress[0].equals("max")) {
                progressDialog.setMax(Integer.parseInt(progress[1]));
            }
        }

        @Override
        protected void onPostExecute(Integer result) {
            //onPostExecute() 함수는 doInBackground() 함수가 종료되면 실행됨
            progressDialog.dismiss();
            super.onPostExecute(result);
        }
    }
}


첨부한 파일은 Android Studio 에서 프로젝트 생성하고 첨부한 파일을 참조해서 작성하면 도움이 된다.

app_main.zip



블로그 이미지

Link2Me

,
728x90

Android Studio 에서 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">

<ImageButton
android:id="@+id/ib01"
android:src="@android:drawable/sym_def_app_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<EditText
android:id="@+id/et01"
android:hint="예상 우승 후보팀을 입력하세요"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</LinearLayout>

이 XML 파일을 View 객체로 만들기 위해서는 LayoutInflator를 이용해야 한다.

안드로이드에서 inflate 를 사용하면 xml 에 씌여져 있는 view 의 정의를 실제 view 객체로 만드는 역할을 한다.

자바 프로그램 코드상에서는 레이아웃 인플레이터에 직접 접근하지 못하고

getLayoutInflater() 메소드를 이용하거나, getSystemService(String) 메소드를 호출해 반환값으로 LayoutInflater 객체를 받아야 한다.

사용자의 화면에 보여지는 것들은 Activity 위에 있는 View다.


Layout Inflater
- 레이아웃 인플레이터는 레이아웃 xml 파일에 상응하는 뷰 객체를 반환받는 데 사용한다
- 자바 프로그램 코드상에서는 레이아웃 인플레이터에 직접 접근하지 못하고 getLayoutInflater() 메소드를 이용하거나
getSystemService(String) 메소드를 호출해 반환값으로 LayoutInflater 객체를 받아야 한다.
- 보통 자바 코드에서 View, ViewGroup 을 사용하거나, Adapter의 getview() 또는 Dialog, Popup 구현시
배경화면이 될 Layout을 만들어 놓고 View의 형태로 반환 받아 Acitivity에서 실행 하게 된다.


inflate(int resource, ViewGroup root, boolean attachToRoot)
- 레이아웃 XML파일을 View객체로 만들기 위해서는 LayoutInflater내의 inflater 메서드를 사용
- resource: view를 만들고 싶은 레이아웃 파일의 id (
inflate할 대상의 xml 리소스)

ex) R.layout.custom

- 두 번째 인수는 생성된 뷰의 루트로 사용할 뷰 객체. 리소스 내에 루트가 따로 있다면 null.


inflate 를 사용하기 위해서는 우선 inflater 를 얻어와야 한다.
LayoutInflater inflater = (LayoutInflater) getSystemService( Context.LAYOUT_INFLATER_SERVICE );
LinearLayout linearLayout = (LinearLayout) inflater.inflate( R.layout.custom, null);
setContentView( linearLayout ); // 가져온 View 를 화면에 그린다.


/* We get the inflator in the constructor */
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

--> getSystemService(Context.LAYOUT_INFLATER_SERVICE) = LayoutInflater 객체를 반환받는다.


// 인플레이트를 얻어오는 다른 방법
LinearLayout linearLayout = (LinearLayout) View.inflate(MainActivity.this, R.layout.custom, null);
// Inflate된 View에서 Child인 EditText를 얻어 오기
EditText editText = (EditText) linearLayout.findViewById(R.id.et01);




블로그 이미지

Link2Me

,
728x90

기본 알림창인 AlertDialog 다이얼로그

AlertDialog 는 사용자에게 메세지나 경고를 알리기 위한 기능으로 Android 에서 지원하는 Dialog 이다. Toast 와는 다르게 Dialog 라서 Activity의 Focus를 가져간다.

=== activity_main.xml ===
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.tistory.link2me.app9.MainActivity">

    <Button
        android:id="@+id/btnAlert"
        android:layout_centerInParent="true"
        android:text="대화상자 보기"
        android:textSize="20dp"
        android:onClick="btnClicked"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tv01"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="대화상자를 표시하려면 아래 버튼을 누르세요"
        android:textSize="15dp"
        android:textColor="#999"
        android:gravity="center_horizontal"
        android:layout_above="@id/btnAlert"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

</RelativeLayout>


=== MainActivity.java ===

package com.tistory.link2me.app9;

import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    TextView textView;
    String msg;
    Button btn;

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

        textView = (TextView) findViewById(R.id.tv01);
    }

    public void btnClicked(View view){
        AlertDialog alertDialog = makeDialog();
        alertDialog.show();
    }

    // 알림 대화상자 생성
    private AlertDialog makeDialog(){
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("알림");
        builder.setMessage("항목중에 하나를 선택하세요.");
        builder.setIcon(android.R.drawable.ic_dialog_alert);

        builder.setPositiveButton("확인", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                msg="OK 버튼 선택 : "+ Integer.toString(which);
                textView.setText(msg);
            }
        });

        builder.setNegativeButton("NO", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                msg="NO 버튼 선택 : "+ Integer.toString(which);
                textView.setText(msg);
                dialog.dismiss();
            }
        });

        // Cancel 버튼 설정
        builder.setNeutralButton("CANCEL", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                msg="CANCEL 버튼 선택 : "+ Integer.toString(which);
                textView.setText(msg);
            }
        });

        // Builder 클래스의 create() 메소드를 호출하여 대화상자 생성
        AlertDialog dialog = builder.create();

        return dialog;
    }
}



블로그 이미지

Link2Me

,
728x90

Debugging
F8 : Step over
F7 : Step into
Shift + F7 : Smart step into
Shift + F8 : Step out
Alt + F9 : Run to cursor
Alt + F8 : Evaluate expression
F9 : Resume program
Ctrl + F8 : Toggle breakpoint
Ctrl + Shift + F8 : View breakpoints

Alt + Delete : 안전하게 삭제(지우기전에 사용된 곳 확인 가능)
Alt + Enter : 캐스팅 자동완성 등 빠른 수정
Alt + F7 / Ctrl + F7 : 사용내용 전체찾기 / 파일에서 사용한것 찾기
Alt + Insert : Generate code( Getters, Setters, Constructors, hashCode/equals, toString )
Alt + Right/Left : 문서탭이동
Alt + Up/Down : 이전/다음 함수 이동

Alt + Shift + up/down : 선택한 위치의 줄을 위/아래로 움직임

Ctrl + / : 한줄주석
Ctrl + Shift + / : 블럭주석
Ctrl + ] / [ :  코드블럭 처음/끝 이동
Ctrl + Alt + B : Go to implementation(s)
Ctrl + Alt + F7 : 사용된 것 새창으로 보여줌.
Ctrl + Alt + I : Auto-indent line(s)
Ctrl + Alt + J : Surround with Live Template
Ctrl + Alt + L : 소스 코드 정리
Ctrl + Alt + O : import 정리
Ctrl + Alt + Shift + N : Go to symbol
Ctrl + Alt + T : Surround with… (if..else, try..catch, for, synchronized, etc.)
Ctrl + B  : Go to declaration (XML 파일에서 참조되는 리소스의 값을 확인할 수 있음)
Ctrl + Backspace : 단어처음까지 삭제
Ctrl + D : 라인복제 또는 선택블록 복제
Ctrl + Delete : 단어끝까지 삭제
Ctrl + E : 이전에 열었던파일 목록창 열기
Ctrl + Enter : 라인분리(Smart line split)
Ctrl + F : 찾기
Ctrl + F12 : 파일 구조보기
Ctrl + G : 줄번호로 이동.
Ctrl + I : Implement methods
Ctrl + J : Insert Live Template
Ctrl + mouse over code : 간단한 설명.
Ctrl + N : 클래스 열기
Ctrl + O : Override methods
Ctrl + Q : 빠른 문서보기
Ctrl + R : 바꾸기
Ctrl + Shift + ] / [ : 코드블럭 처음또는 끝까지 선택
Ctrl + Shift + B : Go to type declaration
Ctrl + Shift + F : 경로에서 찾기(Find in path)
Ctrl + Shift + F7 : 현재파일에서 하이라이트
Ctrl + Shift + I : Open quick definition lookup
Ctrl + Shift + J : 라인합치기(Smart line join)
Ctrl + Shift + N : 파일열기
Ctrl + Shift + R : 경로에서 바꾸기(Replace in path)
Ctrl + Shift + Space : 스마트 코드 완성(예상되는 타입의 메소드또는 변수명 )
Ctrl + Shift + U : 대소문자 변환
Ctrl + Shift + V : 이전에 클립보드에 복사한 히스토리 열기.
Ctrl + Space : 기본 코드 완성(클래스/메서드 입력하다가 Ctrl + Space 를 누르면 사용할 수 있음)
Ctrl + U : super-method/super-class 이동.
Ctrl + W : 연속적인 코드블럭 선택
Ctrl + Y : 라인삭제
F12 : 이전에 사용한 도구창 열기
F2 / Shift + F2 : 다음/이전 하이라이트된 에러로 이동.
F3 : 다음찾기
F4 : 해당 소스로 이동
F5 : 복사
F6 : 이동
Shift + Esc : 마지막에 사용한 도구창 닫기
Shift + F1 : 외부 문서보기(http://developer.android.com/reference로 이동)
Shift + F3 : 이전찾기
Shift + F6 : 이름바꾸기



MAC 용 단축키는 https://gist.github.com/stkent/349cdda974fdb9697be5 를 참조하면 된다.

블로그 이미지

Link2Me

,
728x90

ArrayList
- 배열 기반, 데이터의 추가와 삭제 유용하지 못함, 순차적인 추가 삭제는 제일 빠름, 인덱스가 있어 임의의 요소에 대한 접근성이 뛰어남.
- 대량의 자료를 추가/삭제하는 경우에 내부적인 처리량이 늘어나서 상당한 성능저하를 가져온다.
- 각 데이터의 인덱스를 가지고 있기 때문에, 필요한 데이터의 접근이 한번만에 가능하다.
  많은 데이터를 한 번에 다 가져와서 여러번 참조해 쓸 때 최상의 성능을 나타낸다.
- 레퍼런스 타입의 데이터만 저장할 수 있다.
- 데이터 내용의 중복이 가능하다. null값을 허용한다.

ArrayList<String> list = new ArrayList<String>();
list.add("apple")'; // 추가
String str = list.get(2); // 데이터 가져오기
list.remove(1); // 데이터 삭제
list.set(0, "오렌지"); // 데이터 수정
int index = list.indexOf("apple"); // 인덱스 알아내기


ArrayList<Calendar_Item> list = new ArrayList<Calendar_Item>();

와 같이 String 대신에 Calendar_Item 이 오면 데이터 수정을 어떻게 해야 할까?

Calendar_Item item = new Calendar_Item();
item.setYear(year);
item.setMonth(month);
item.setDay(day);
item.setWeekday(weekday);
item.setColor(color);
item.setName(name);

item.setKey(key);

list.set(0,item);

즉, String 값 대신에 Calendar_Item item 값을 넣어주면 된다.

초보자로서 이렇게 생각하는 것이 참 어렵다.


검색으로 index 값인 0 를 찾아내는 로직이 구조상 속도가 빠르지 않는거 같다.

public int getIndexOfList(String search_key) {
    for (int temp = 0; temp < list.size(); temp++) {
        String key = list.get(temp).getKey();
        if (key != null && key.equals(search_key)) {
            return temp;
        }
    }
    return -1;
}

하나의 index 값을 찾아내는데 ArrayList 배열 전체를 순환하면서 일치하는 걸 찾아낸다.

검색으로 찾아야 할 데이터가 많다면 속도 저하는 당연히 발생할 것이다.



컬렉션 프레임웍에서는 컬렉션에 저장된 요소들을 읽어오는 방법을 표준화하였다.

컬렉션에 저장된 각 요소에 접근하는 기능을 가진 Iterator 인터페이스를 정의하고, Collection 인터페이스에는 Iterator를 반환하는 iterator()를 정의하고 있다.

List list = new ArrayList();
Iterator it = list.iterator();
while(it.hasNext()){
    System.out.println(it.next());
}



HashMap

- Map 인터페이스의 한 종류로, key와 value 를 묶어 하나의 entry 로 저장한다는 특징을 갖는다.

- key는 중복을 허용하지 않고, value는 중복 허용한다.

  동일한 key 가 입력되면, 나중에 입력된 데이터(key, value)로 덮어 씌워진다.

- Map에 종류에는 Hashtable, HashMap, LinkedHashMap, SortedMap, TreeMap 등이 있다.

- 배열과 연결이 결합된 형태, 추가, 삭제, 검색, 접근성이 모두 뛰어남, 검색에는 최고 성능을 보인다.
HashMap<키의타입, 데이터의 타입> 해쉬테이블 이름 = new HashMap<키의 타입, 데이터의 타입>();
- 해쉬 테이블에 저장할 데이터 타입과, 키 타입 두 가지 데이터 타입을 정해야 한다.
- HashMap<String, Integer> hashtable = new hashmap<String, Integer>();
- hashtable.put("apple", new Integer(100)); // 해쉬 테이블에 데이터 저장
- Integer num = hashtable.get("apple"); // 해쉬테이블에 저장된 데이터를 읽어온다.
- hashtable.remove("apple"); // 해쉬테이블에 있는 데이터 삭제

※ 멀티쓰레드에서는 HashTable을 쓴다


* Map 인터페이스의 주요 메소드


HashMap 메소드 

설명 

put() 

- 키(Key)와 값으로 구성된 새로운 데이터를 추가한다. 

get() 

- 지정한 키(Key)에 해당하는 데이터를 반환한다. 

remove() 

- 지정한 키(Key)에 해당하는 데이터를 삭제한다. 

containKey() 

- 지정한 키(Key)가 존재하는지 여부를 반환한다. 

containsValue() 

- 지정한 값이 존재하는지 여부를 반환한다. 

size() 

- Map의 요소 개수를 반환한다. 

isEmpty() 

- Map이 비어 있는지의 여부를 반환한다. 



*



출처: http://hyeonstorage.tistory.com/230 [개발이 하고 싶어요]

* Map 인터페이스의 주요 메소드


HashMap 메소드 

설명 

put() 

- 키(Key)와 값으로 구성된 새로운 데이터를 추가한다. 

get() 

- 지정한 키(Key)에 해당하는 데이터를 반환한다. 

remove() 

- 지정한 키(Key)에 해당하는 데이터를 삭제한다. 

containKey() 

- 지정한 키(Key)가 존재하는지 여부를 반환한다. 

containsValue() 

- 지정한 값이 존재하는지 여부를 반환한다. 

size() 

- Map의 요소 개수를 반환한다. 

isEmpty() 

- Map이 비어 있는지의 여부를 반환한다. 



*



출처: http://hyeonstorage.tistory.com/230 [개발이 하고 싶어요]

* Map 인터페이스의 주요 메소드


HashMap 메소드 

설명 

put() 

- 키(Key)와 값으로 구성된 새로운 데이터를 추가한다. 

get() 

- 지정한 키(Key)에 해당하는 데이터를 반환한다. 

remove() 

- 지정한 키(Key)에 해당하는 데이터를 삭제한다. 

containKey() 

- 지정한 키(Key)가 존재하는지 여부를 반환한다. 

containsValue() 

- 지정한 값이 존재하는지 여부를 반환한다. 

size() 

- Map의 요소 개수를 반환한다. 

isEmpty() 

- Map이 비어 있는지의 여부를 반환한다. 




출처: http://hyeonstorage.tistory.com/230 [개발이 하고 싶어요]

* Map 인터페이스의 주요 메소드

HashMap 메소드 

설명 

put(Object Key, Object Value)

 - 키(Key)와 값으로 구성된 새로운 데이터를 추가한다. 

get(Object Key)

 - 지정한 키(Key)에 해당하는 데이터를 반환한다. 

remove(Object Key)

 - 지정한 키(Key)에 해당하는 데이터를 삭제한다. 

boolean containsKey(Object Key)

출처: http://vaert.tistory.com/107 [Vaert Street]

boolean containsKey(Object Key)

 - 지정한 키(Key)가 존재하는지 여부를 반환한다. 

boolean containsValue(Object Value)

 - 지정한 값이 존재하는지 여부를 반환한다. 

clear()

 - HashMap에 저장된 모든 객체를 제거한다

Object clone()

 - 현재 HashMap을 복제하여 반환한다.
    newmap = (HashMap)map.clone();

newmap = (HashMap)map.clone();

출처: http://vaert.tistory.com/107 [Vaert Street]

int size() 

 - HashMap에 저장된 요소의 개수를 반환한다. 

isEmpty() 

 - Map이 비어 있는지의 여부를 반환한다. 

Collection values()

 - HashMap에 저장된 모든 값을 컬렉션 형태로 반환한다.


HashTable과 HashMap의 차이는 null 값을 허용하는데에 있다.
HashTable은 null 값을 허용하지 않지만, HashMap은 null 값을 허용한다.

HashMap의 경우 동기화를 지원하지 않지만 Hashtable은 동기화를 지원하여 다중 스레드 환경에서 사용하면 된다.
보통은 HashMap을 활용하고 동기화가 필요한 시점에서는 Java 5부터 제공하는 ConcurrentHashMap을 사용하는 것이 더 좋은 방법이라 표현한다.
HashMap은 저장된 요소들의 순회를 위해 Fail-Fast Iterator를 반환한다.
Hashtable은 같은 경우 Enumeration을 반환한다.


there are many differences between HashMap and Hashtable classes that are given below.

HashMapHashtable

1) HashMap is non synchronized. It is not-thread safe and can't be shared between many threads without proper synchronization code.

Hashtable is synchronized. It is thread-safe and can be shared with many threads.

2) HashMap allows one null key and multiple null values.

Hashtable doesn't allow any null key or value.

3) HashMap is a new class introduced in JDK 1.2.

Hashtable is a legacy class.

4) HashMap is fast.

Hashtable is slow.

5) We can make the HashMap as synchronized by calling this code
Map m = Collections.synchronizedMap(hashMap);

Hashtable is internally synchronized and can't be unsynchronized.

6) HashMap is traversed by Iterator.

Hashtable is traversed by Enumerator and Iterator.

7) Iterator in HashMap is fail-fast.

Enumerator in Hashtable is not fail-fast.

8) HashMap inherits AbstractMap class.

Hashtable inherits Dictionary class.



ArrayList 다음에 <T>,<String>,<Integer>,<Class명> 라고 쓰여진 형식을 많이 보았을 것이다.

이 <>를 제네릭(Generics)이라 하는데, 이 <>안에 어떠한 타입을 선언해주어 해당 ArrayList, List 등이 사용할 객체의 타입을 지정해준다는 뜻이다. 이는 다룰 객체의 타입을 미리 명시하여 객체의 형변환을 사용할 필요없게 하며, 내가 사용하고 싶은 데이터 타입만 사용할 수 있게 해주는 효과가 있다.


ArrayList 의 제네릭스로 HashMap<String,String> 을 사용한 예제다.

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

public class ArrayList_EX01 {

    public static void main(String[] args) {
        ArrayList <HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
        HashMap<String, String> map = new HashMap<String,String>();
        map.put("1", "고양이");
        map.put("3", "송아지");
        map.put("2", "강아지");
        //key, value로 String의 값들을 넣어준다.
        list.add(map);

        for(int i = 0; i < list.size(); i++){
            // ArrayList 사이즈 만큼 for문을 실행한다.
            System.out.println("list 순서 " + i + "번쨰");
            for( Entry<String, String> elem : list.get(i).entrySet() ){
                // list 각각 HashMap받아서 출력한다.
                System.out.println( String.format("키 : %s, 값 : %s", elem.getKey(), elem.getValue()) );
            }
        }

    }
}


'안드로이드 > Java 문법' 카테고리의 다른 글

[Java] 정보은닉과 캡슐화  (0) 2017.10.16
자바 기본 데이터형과 크기  (0) 2017.10.11
Java 클래스(Class) ★★★★★  (0) 2017.05.04
Java foreach 문  (0) 2017.03.01
자바 배열과 기본 문법  (0) 2016.07.11
블로그 이미지

Link2Me

,
728x90

동영상 강좌를 수강하면서 보니까 Android Studio 2.1.2 버전과 2.2.3 버전의 단축키 사용법이 좀 다른가보다.

동영상 강좌에서는 단축키를 사용해서 코드를 생성하는 방법이 나오지 않는다.

오프라인 강의를 통해서 Android Studio 강의를 들었던 단축키 사용법이 없다.


Android Eclipse 기반으로 작년도 6월에 잠깐 연습을 해보고 나서 회사 업무때문에 Android 독학하는 것이 어렵다는 생각에 포기하고 있다가 올해 2월에 야간 강의를 들으면서 다시 Android Studio 연습하면서 간단하게 정리를 해두려고 한다. 전문적인 개발이 아니다보니, 업무를 이것저것 하다보면 금새 잊어버리게 된다.







7번까지 실행하고 나면 자동으로 아래 화면이 만들어진다.



여기까지가 기본적인 Android Studio 사용법을 위한 준비과정이다.

이제 Layout 부분과 MainActivity.java 파일에 내용을 추가하면 된다.


Exercise_app1.zip


Android Studio 파일은 실행파일을 생성하고 나면 파일 사이즈가 상당히 커서 파일을 전부 올릴 수가 없다.

그래서 핵심적인 것만 첨부한다.

이 첨부된 코드를 보면서 필요한 부분을 복사해서 붙여넣기 해가면서 테스트하면 된다.


Java 의 정석 책도 같이 보고 있다.

DoIt 안드로이드 앱 프로그램 책의 동영상 강좌에 보면, Java 를 몰라도 Anroid 배울 수 있다고 설명한다.

하지만 Java 에 대한 기본개념이 약하면 응용력이 생길수 없다.

PHP도 잘 하는 것은 아니지만 프로그램을 좀 해보면서 느끼는 것은 배열 다루는 것이 정말 중요하다는 걸 많이 배웠다. Java 에서는 Class 개념과 배열, ArrayList 에 대한 개념이 강해야 할 거 같아서 Java 정석 책을 병행 공부중이다.


public class MainActivity extends AppCompatActivity

- C++에서는 여러 클래스로부터 상속받은 다중상속을 허용하지만, 자바에서는 단일 상속만을 허용한다.


접근제어자

- private : 같은 클래스 내에서만 접근이 가능하다.

- protected : 같은 패키지 내에서, 그리고 다른 패키지의 자손 클래스에서 접근이 가능하다.

- public : 접근 제한이 전혀 없다.


==== MainActivity.java ====

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import static android.R.attr.data;

public class MainActivity extends AppCompatActivity {

    public static final int REQUEST_Code = 100;

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

        Button btn = (Button) findViewById(R.id.btn_01);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // new 액티비티로 전환
                Intent intent = new Intent(getApplicationContext(),NewActivity.class);
                intent.putExtra("name","mike");
                startActivityForResult(intent,REQUEST_Code);
            }
        });

        // 버튼의 배경색 지정
        btn.setBackgroundColor(Color.parseColor("#FF00FF"));
    }

    // new 액티비티에서 응답을 받았을 때 처리사항
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == REQUEST_Code){
            Toast.makeText(getBaseContext(), "요청코드:"+resultCode, Toast.LENGTH_SHORT).show();

            if(resultCode == Activity.RESULT_OK){
                String name = data.getExtras().getString("name");
                Toast.makeText(getBaseContext(), "응답이름:"+name, Toast.LENGTH_SHORT).show();
            }
        }
    }
}




==== NewActivity.java ===

import android.app.Activity;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class NewActivity extends AppCompatActivity {

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

        Intent intent = getIntent();
        String name = intent.getExtras().getString("name");
        Toast.makeText(getApplicationContext(), "onCreate 호출됨:"+name, Toast.LENGTH_SHORT).show();

        Button btn = (Button) findViewById(R.id.backBtn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(), "돌아가기 버튼이 눌렸어요.", Toast.LENGTH_LONG).show();
                close();
            }
        });
    }

    // Back 키를 눌렀을 때 액티비티를 닫고 메인화면으로 이동
    public boolean onKeyDown(int keyCode, KeyEvent key){
        if(keyCode == key.KEYCODE_BACK){
            close();
            return true;
        }
        return false;
    }

    protected void close(){
        // 응답값을 전달하기 위한 인텐트 생성
        Intent resultIntent = new Intent();
        resultIntent.putExtra("name","Link2me");

        // 응답값을 전달
        setResult(Activity.RESULT_OK,resultIntent);
        finish(); // 액티비티 닫기(현재 화면을 종료)
    }
}



keyCode

 상수 설명 
 KEYCODE_DPAD_LEFT  왼쪽 이동키
 KEYCODE_DPAD_RIGHT  오른쪽 이동키
 KEYCODE_DPAD_UP  위쪽 이동키
 KEYCODE_DPAD_DOWN  아래쪽 이동키
 KEYCODE_DPAD_CENTER  이동키 중앙의 버튼
 KEYCODE_A  알파벳 A (B부터는 KEYCODE_B 방식)
 KEYCODE_0  숫자 0 (1부터는 KEYCODE_1 방식)
 KEYCODE_CALL  통화
 KEYCODE_ENDCALL  통화종료
 KEYCODE_HOME  홈
 KEYCODE_BACK  뒤로
 KEYCODE_VOLUME_UP  볼륨증가버튼
 KEYCODE_VOLUME_DOWN  볼륨감소버튼


==== activity_main.xml ====

본인이 생성하는 부분과 달라지는 부분이 뭔지부터 알아보자면 색깔이 표시된 부분이 다르다.

Android Studio 2.2.3 에서는 자동완성 기능이 워낙 뛰어나서 코드 작성이 정말 편하다.

개념을 잘 이해하고 있다면 쉽게 코드를 작성할 수가 있겠더라.


<?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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.a05rg.app4.MainActivity">

    <Button
        android:id="@+id/btn_01"
        android:layout_centerInParent="true"
        android:text="new activity make"
        android:textAllCaps="false"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

블로그 이미지

Link2Me

,
728x90

android.telephone.SmsManager class를 이용하여, API 코드 2줄로 SMS를 자동으로 보낼 수 있다.


SMS 메시지 보내는 코드

SmsManager smsManager = SmsManager.getDefault(); // Get the default instance of SmsManager

smsManager.sendTextMessage(phoneNumber, null, smsBody, null, null); // Send a text based SMS


MMS 메시지 보내는 코드

SmsManager sms = SmsManager.getDefault();
ArrayList<String> parts = sms.divideMessage(message);
sms.sendMultipartTextMessage(phoneNumber, null, parts, null, null); 


참고 : http://codetheory.in/android-sms/ 에 설명이 잘 나와있다.

private void SendSMS(String phonenumber, String message) {
    SmsManager smsManager = SmsManager.getDefault();
    if(smsManager == null) {
    return;
    }
    String sendTo = phonenumber;
    ArrayList<string> partMessage = smsManager.divideMessage(message);
    if(partMessage.size() > 1){
        Log.d("SMS", "Sending " + partMessage.size() + " parts");
    smsManager.sendMultipartTextMessage(sendTo, null, partMessage, null, null);
    } else {
    smsManager.sendTextMessage(sendTo, null, message, null, null);
    }


phoneNumber 를 다중(여러전화번호)으로 보낼 수 있는지 확인해보니 1건(한 전화번호)씩 보낸다.

SMS를 분할해서 보내는 코드에 대한 예제코드가 위 사이트에 잘 나와 있다.

이 방식을 이용하면 발송건수만큼 문자 보낸갯수가 생성된다.

문자를 보낸 개수를 지우는 방법을 강구해봐야겠다.


25개씩 잘라서 보내는 방법을 찾아보려고 코드를 구현한 건데 전혀 의미가 없는거 같다.

그냥 for문을 처음부터 끝까지 돌리면 될 일인듯.....


import java.util.Arrays;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class SendSMS extends Activity {

    Context mContext;
    EditText smsTextContext;
    String[] telNumArr;
    int mobileCnt;
    int selectedCnt;
    int limitCnt;
    int mod;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.send_sms);
       
        mContext = this;
        Intent intent = getIntent(); // 값을 받아온다.
        telNumArr = intent.getStringArrayExtra("mobileNOArr");
       
        smsTextContext = (EditText) findViewById(R.id.smsText);
        selectedCnt = telNumArr.length;
        limitCnt = 25;
        mod = (selectedCnt%limitCnt==0)?selectedCnt/limitCnt:selectedCnt/limitCnt+1;
       
    }   
   
    @SuppressLint("NewApi")
    public void sendSMS(View v){
        String smsText = smsTextContext.getText().toString();
       
        if (smsText.length()>0){
            String sumTelNum = "";
            for(int i=0;i < mod;i++){
                int startIndex = i*limitCnt;
                int endIndex = startIndex + limitCnt <= telNumArr.length ? startIndex + limitCnt : telNumArr.length;
                String[] subArray = Arrays.copyOfRange(telNumArr, startIndex, endIndex);
               System.out.println(i + "번째 서브배열"); 
                for (String telNum : subArray) {
                    System.out.println("telNum" + telNum);

                    telNum = telNum.replaceAll("[^0-9]", ""); // 숫자를 제외한 모든 문자 제거

                    if(telNum.length() == 0) continue;       
                    if(telNum.matches("(01[016789]{1})(\\d{3,4})(\\d{4})")){
                        telNum = telNum.replaceAll("(\\d{3})(\\d{3,4})(\\d{4})", "$1-$2-$3");
                    }
                    sumTelNum += telNum + ";";
                }
                   
                sendSMS(sumTelNum, smsText);               
               
                System.out.println("sumTelNum....." + sumTelNum);
                subArray = null;
                sumTelNum = "";
            }
        } else {
            Toast.makeText(this, "모두 입력해 주세요", Toast.LENGTH_SHORT).show();
        }
    }
   
    public void sendSMS(String smsNumber, String smsText){
        PendingIntent sentIntent = PendingIntent.getBroadcast(this, 0, new Intent("SMS_SENT_ACTION"), 0);
        PendingIntent deliveredIntent = PendingIntent.getBroadcast(this, 0, new Intent("SMS_DELIVERED_ACTION"), 0);
       
        // SMS가 발송될때 실행
        registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                switch(getResultCode()){
                    case Activity.RESULT_OK:
                        // 전송 성공
                        Toast.makeText(mContext, "전송 완료", Toast.LENGTH_SHORT).show();
                        break;
                    case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
                        // 전송 실패
                        Toast.makeText(mContext, "전송 실패", Toast.LENGTH_SHORT).show();
                        break;
                    case SmsManager.RESULT_ERROR_NO_SERVICE:
                        // 서비스 지역 아님
                        Toast.makeText(mContext, "서비스 지역이 아닙니다", Toast.LENGTH_SHORT).show();
                        break;
                    case SmsManager.RESULT_ERROR_RADIO_OFF:
                        // 무선 꺼짐
                        Toast.makeText(mContext, "휴대폰이 꺼져있습니다", Toast.LENGTH_SHORT).show();
                        break;
                    case SmsManager.RESULT_ERROR_NULL_PDU:
                        // PDU 실패
                        Toast.makeText(mContext, "PDU Null", Toast.LENGTH_SHORT).show();
                        break;
                }
            }
        }, new IntentFilter("SMS_SENT_ACTION"));
       
        // SMS가 도착했을때 실행
        registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                switch (getResultCode()){
                    case Activity.RESULT_OK:
                        // 도착 완료
                        Toast.makeText(mContext, "SMS 도착 완료", Toast.LENGTH_SHORT).show();
                        //finish();
                        break;
                    case Activity.RESULT_CANCELED:
                        // 도착 안됨
                        Toast.makeText(mContext, "SMS 도착 실패", Toast.LENGTH_SHORT).show();
                        break;
                }
            }
        }, new IntentFilter("SMS_DELIVERED_ACTION"));
       
        SmsManager mSmsManager = SmsManager.getDefault();
        mSmsManager.sendTextMessage(smsNumber, null, smsText, sentIntent, deliveredIntent);
    }
}


----------------------------------------------------------------------

MMS 발송코드를  http://stackoverflow.com/questions/6580675/how-to-send-the-sms-more-than-160-character 에서 찾았는데 아직 테스트는 못해봤다. 테스트를 하면 글 내용을 다시 수정하련다.


SmsManager sm = SmsManager.getDefault();
ArrayList<String> parts =sm.divideMessage(LONG_TEXT);
int numParts = parts.size();

ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>();
ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>();

for (int i = 0; i < numParts; i++) {
sentIntents.add(PendingIntent.getBroadcast(getContext(), 0, mSendIntent, 0));
deliveryIntents.add(PendingIntent.getBroadcast(getContext(), 0, mDeliveryIntent, 0));
}

sm.sendMultiPartTextMessage(mDestAddr,null, parts, sentIntents, deliveryIntents)

블로그 이미지

Link2Me

,
728x90

Android 어플을 실행하면 문자를 보낼 화면을 제공해준 방법이다.


이런 방식으로 SMS를 발송하는 것은 ...

전화번호를 여러개 등록하는 것은 통신사에게 제공하는 한도만큼 가능하다.

화면이 보이는 상태에서 보낼 메시지를 적어서 보내기 때문에 많은 사용자에게 문자를 발송하는 것은 어렵다.


Uri smsUri = Uri.parse("tel:" + sumTelNum);
Intent intent = new Intent(Intent.ACTION_VIEW, smsUri);
// 보내는 화면이 팝업됨

intent.putExtra("address", sumTelNum); // 받는 번호
intent.putExtra("sms_body", smsText); // 보낼 문자내용
intent.setType("vnd.android-dir/mms-sms");
startActivity(intent);


Intent intent = new Intent( Intent.ACTION_SENDTO );
intent.putExtra("sms_body", smsText);
intent.setData( Uri.parse( "smsto:"+sumTelNum ) );
startActivity(intent);


둘다 같은 화면이 나온다.


참고 : http://gogorchg.tistory.com/entry/Android%ED%8E%8C%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-Intent-%EC%82%AC%EC%9A%A9%EB%B2%95

에 여러가지 설명이 잘 나와있다.

블로그 이미지

Link2Me

,
728x90

Intent에서 putExtra를 해주게 되면 값을 넘겨 주고 getIntent를 이용해서 값을 받아 사용할 수 있다


Intent intent = new Intent(this, ClassB);
String[] telNumArr = new String[] {"test", "test2"};
intent.putExtra("strings", telNumArr);
startActivity(intent);


public void onCreate() {
  Intent intent = getIntent();
  String[] telNumArr = intent.getStringArrayExtra("strings");
}


Intent intent = new Intent(context,SendSMS.class);
intent.putExtra("mobileNoArr", telNumArr);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // 스택에 기존에 사용하던 Activity가 있다면 그 위의 스택을 전부 제거해 주고 호출
context.startActivity(intent);


배열의 길이는 telNumArr.length

System.out.println(telNumArr.length);


배열에서 일정한 개수로 분할해서 처리해야 할 경우에 사용하는 함수

copyOfRange
int[] subArray = Arrays.copyOfRange(array, startIndex, endIndex);
int[] array = new int[]{1, 2, 3, 4, 5};
int[] subArray = Arrays.copyOfRange(array, 1, 3);

결과 : subArray = [2, 3]


1. 가져올 배열의 개수를 구한다.
   Array.length;


2. 배열 개수를 25개로 나누어 몫을 구한다.

   int limitCnt= 25;

   Array.length /limitCnt ;
   3항 연산자 : 몫의 개수 =
(Array.lenght % limitCnt == 0) ? Array.lenght / limitCnt : Array.lenght / limitCnt + 1;


3. 몫의 개수만큼 foreach 문을 돌린다.
   - String[] newArray = Arrays.copyOfRange(oldArray, startIndex, endIndex);
   for(i=0;i<몫의개수;i++){
    startIndex = i*
limitCnt ;
    int endIndex = startIndex + limitCnt <= telNumArr.length ? startIndex + limitCnt : telNumArr.length;

    String[] subArray = Arrays.copyOfRange(Array, startIndex, endIndex);

    System.out.println(subArray);
   }



기타 addFlags

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);



블로그 이미지

Link2Me

,
728x90

C#에서 사용하는 foreach 문과 동일한 형태의 Java for 문을 적어둔다.


C#

 public List<Address_Item> SelectCreature(String Name)
{
    List<
Address_Item> foundCreature = new List<Address_Item>();

    //For the customer name that equals what has been searched...
    foreach (
Address_Item c in m_creature)
    {
        if (c.CreatureName.Equals(Name, StringComparison.OrdinalIgnoreCase))
            foundCreature.Add(c);
    }

    return foundCreature;
}

 foreach 루프를 사용하면 IEnumerable 인터페이스를 지원하는 배열 같은 컨테이너 클래스의 각 항목을 반복할 수 있다.

 Java

 public List<Address_Item> SelectCreature(String Name)
{
    // List is an interface, you must use a specific implementation
    // like ArrayList:
    List<
Address_Item> foundCreature = new ArrayList<Address_Item>();

    //For the customer name that equals what has been searched...
    for ( Address_Item c : m_creature)
    {
        if (c.CreatureName.equalsIgnoreCase(Name))
            foundCreature.add(c);
    }

    return foundCreature;
}


C# 에서는 foreach 문으로 표기를 하는데 Java 에서는 for 문으로 표기하고 괄호안의 내용만 foreach 문 형태로 되어 있다.


String array[] = { "윤아", "수영", "윤시윤", "전소민", "정소민" };

for(int i=0; i<array.size(); i++){   // 조건식에 array.size()를 사용하면 for문을 돌 때마다 size 를 호출한다.
    System.out.println(array.get(i));
}

for(int i=0,size = array.size(); i<size; i++){  // for문을 돌 때마다 size를 호출하는 걸 방지목적
    System.out.println(array.get(i));
}

foreach 문
// 배열의 일부가 아닌, 배열의 전체를 참조할 필요가 있을 경우에 유용하게 사용
// 배열의 값을 수정할 수는 없다.
// JDK 5.0 버전부터는 향상된 for문을 지원한다.
// for(변수타입 변수이름 : 배열이름)
for(String s : array){
    System.out.println(s);
}

'안드로이드 > Java 문법' 카테고리의 다른 글

[Java] 정보은닉과 캡슐화  (0) 2017.10.16
자바 기본 데이터형과 크기  (0) 2017.10.11
Java 클래스(Class) ★★★★★  (0) 2017.05.04
ArrayList and HashMap  (0) 2017.03.06
자바 배열과 기본 문법  (0) 2016.07.11
블로그 이미지

Link2Me

,
728x90

스마트폰에서 동보문자를 발송할 수 있는 한도에 대한 것이 궁금해서 삼성전자서비스 사이트에서 가져와서 적어둔다.


http://www.samsungsvc.co.kr/online/diagnosisgoVw.do?domainId=NODE0000033866&node_Id=NODE0000143559&kb_Id=KNOW0000020397


한 내용의 메시지를 여러 명에게 한 번에 전송할 수 있다.


모델 SKT KT LG U+
갤럭시노트2 기준
(SHV-E250S/K/L)
25개 25개 30개
갤럭시S5 LTE-A
(SM-G906S/K/L)
100개 25개 30개
갤럭시노트4
(SM-N910S/K/L)
100개 25개 30개
갤럭시S6
(SM-G920S/K/L)
100개 25개 30개
갤럭시S6 엣지
SM-G925S/K/L)
100개 25개 30개
갤럭시S6 엣지 플러스
SM-G928S/K/L)
100개 25개 30개
갤럭시노트5
SM-N920S/K/L)
100개 25개 30개
갤럭시S7 엣지
SM-G935S/K/L)
100개 25개 30개
갤럭시S7
SM-G930S/K/L)
100개 25개 30개
갤럭시A7(2016)
SM-A710S/K/L)
100개 25개 30개
갤럭시A5(2016)
SM-A510S/K/L)
100개 25개 30개
갤럭시A8
SM-A800S)
100개 - -
갤럭시J7
SM-J700K)
- 25개 -

메시지를 한 번에 여러 명에게 보내는 기능(동보 전송)에 대한 인원 수 제한은 제조사에서 하는 것이 아니라 통신사 요구사항으로 결정되는 부분이다.

블로그 이미지

Link2Me

,
728x90

setContentView(R.layout.activity_main);


Java 소스파일에서 Android XML Layout 파일을 바로 여는 단축키는

Ctrl 를 누른 상태에서 마우스를 activity_main 에 가져다 대면 두개의 선택화면이 나온다.

여기에서 Open Declaration in layout/activity_main 을 선택하면

activity_main.xml 파일이 열린다.


블로그 이미지

Link2Me

,
728x90

안드로이드 스튜디오를 간편하게 설치하는 방법에 대해 알아보자.

안드로이드 스튜디오, Eclipse는 설치된 폴더를 그대로 다른 PC나 드라이브로 옮겨도 이용할 수 있다.

옮긴 경우 설정된 경로 정보만 설정해주면 바로 이용 가능하다.

단, PC가 교체된 경우라면, Java JDK를 먼저 설치해주고, PATH 경로를 설정해주어야 한다.

 

설치할 때 주의할 점은 디렉토리명에 절대 한글이 들어가면 안된다. (non-ASCII)

대다수 개발 입문자들이 Users 폴더에 자동 설치를 하는데 권장하고 싶지 않다.

아래 그림 예시처럼 구분하면 편하다. (C 드라이브 용량이 부족한 경우에는 외장 SSD 등 다른 디렉토리에 구성하면 된다.)

Android/Android Studio

Android/android-sdks

 

 

 

ㅇ android-sdk 는 eclipse 와 android studio 둘다 공용으로 사용할 수 있다.

    - 별도로 구분해서 설치하는게 좋다.

    - 공용으로 사용하다보니 동작이 안되는게 있더라.

 

ㅇ Android Studio 폴더 파일만 복사해서 C드라이드 특정 폴더에 붙여넣기만 해도 된다.

    (이미 설치된 PC에서 복사 또는 다른 사람이 설치한 걸 복사해서 내 PC에 붙여넣기)

    그런 다음에 bin 폴더에서 studio64.exe 파일을 실행해서 sdk 연결정보를 등록해준다.

 

ㅇ 수동 설치방법

    - 설치방법은 압축된 폴더를 하드디스크(HDD) 공간이 넉넉한 드라이브(D드라이드 등)에서 압축을 푼다.

    - android-sdks 라는 폴더를 만든다.

    - Android Studio/bin/studio64.exe 파일을 실행해서 수동으로 SDK 파일을 받는다

    - 설치된 윈도우 운영체제가 32비트 환경이면 studio.exe 파일을 실행한다.

 

 

 

 


 

 

 

 

 

 

 

 

기존 sdk 로 경로 설정을 변경하고 최신 sdk를 설치했다.

 

Android Studio 버전이 Up되면서 Setting 해주는 부분이 변경되었다.

https://link2me.tistory.com/2030 참조하면 도움될 것이다.

블로그 이미지

Link2Me

,
728x90

필요한 코드를 Part 단위로 기록하기 위해 작성한다.


MySQL DB 테이블에서 전화번호를 전부 -가 들어간 것을 변경했다.

Update Person SET mobile=replace(mobile,'-','');


안드로이드 코드

public String filterPhoneNO(String number){
    final Pattern PAT_COUNTRY_CODE_KOREA = Pattern.compile("^(\\+|\\-)?82\\-?");
    number = number.replaceAll("-", ""); // - 전부 제거
    if(number == null || number.length() == 0) {
        return null;
    }
    if (!(number = PAT_COUNTRY_CODE_KOREA.matcher(number).replaceFirst("")).startsWith("0"))
    {
        number = '0' + number;
    }
    if(number.matches("(01[016789]{1})(\\d{3,4})(\\d{4})")){
        return number.replaceAll("(\\d{3})(\\d{3,4})(\\d{4})", "$1-$2-$3");
    } else if(number.matches("(02)(\\d{3,4})(\\d{4})")){
        return number.replaceAll("(\\d{2})(\\d{3,4})(\\d{4})", "$1-$2-$3");
    } else {
        return number.replaceAll("(\\d{3})(\\d{3,4})(\\d{4})", "$1-$2-$3");
    }
}


서버에서 읽어온 정보를 메모리에 저장

protected void showList() {
    // 서버에서 읽어온 정보를 mAdapter 에 저장하고 화면에 출력
    try { 
        JSONObject jsonObj = new JSONObject(myJSON); 
        peoples = jsonObj.getJSONArray(TAG_RESULTS);
       
        for(int i=0;i<peoples.length();i++){ 
        JSONObject c = peoples.getJSONObject(i); 
        String uid = c.getString(TAG_UID); 
        String name = c.getString(TAG_NAME); 
        String mobile = filterPhoneNO(c.getString(TAG_Mobile));
        Drawable myIcon = getResources().getDrawable( R.drawable.ic_launcher );
       
        mAdapter.addItem(myIcon,uid,name,mobile);
        }
       
        runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mAdapter.notifyDataSetChanged();
        }
        });
       
    } catch (JSONException e) { 
        e.printStackTrace(); 
    }




블로그 이미지

Link2Me

,
728x90

Eclipse 는 한번 설치하고 나면 PC를 변경해도 설치된 디렉토리 파일을 그대로 복사해서 사용하면 된다.

설치할 폴더가 C 드라이브에 설정된 것인지 D 드라이브에 설치된 것인지 확인하는 방법이다.



설정된 경로를 변경하고 싶다면...



workspace 경로를 변경해주면 된다.

블로그 이미지

Link2Me

,
728x90

컴퓨터를 업그레이드 하고 나니 윈도우 재설치를 해야 하고, eclipse를 사용하기 위해서 JDK 를 재설치해야 한다.

JDK 는 기존에 받아 두었던 걸 그냥 설치하면 된다.

경로 설정을 해야 하는데 윈도우 10 에서 경로설정을 위한 화면 찾기가 쉽지 않다.


1. 시작 --> 설정을 눌러준다.





c:\Program Files\Java\jdk1.8.0_91\bin;



설치후에 경로설정을 해줘야 eclipse 에서 제대로 인식한다.



SSD 를 새로 구입해서 설치하는 번거로운 문제, 그리고 설치용량이 매우 크기 때문에 HDD에 설치를 하고 패스만 새로 잡아주는 방식을 택했다.

그런데 문제는 Dirve 가 변경되었다. E 드라이브에서 다른 드라이브로 변경되어서 다시 원래의 드라이브로 변경해야 한다.

몇번의 재설치를 하면서 안전하게 HDD에 설치하는게 좋다는 걸 알게되었다.

그리고 드라이브 경로만 제대로 잡아주면 eclipse 를 재설치하지 않아도 된다.


2. 디스크관리



마우스 우클릭하여 드라이브를 변경하면 된다.



eclipse를 실행하니 에러없이 잘 읽어들인다. 성공!!!

블로그 이미지

Link2Me

,
728x90

안드로이드 소스에서 Deprecated 라고 나오는 걸 해결하기 위해 검색으로 찾은 결과를 적어둔다.


보통 deprecate 되어도 이전 코드를 지우는 건 아니기 때문에, 전처럼 동작하기는 할 것이다.

향후, 유지보수단계에서 deprecate 코드에 대해서 안정성을 보장하지 않는다는 얘기이기 때문에, 안드로이드 차기 버전 에서는 비정상 동작을 할 가능성이 높아진다.

대체코드를 찾아서 새롭게 구현하는게 현명한 판단이다.


메모리 누수를 일으키는 현상에 대한 정리가 잘된 자료이다.

http://sjava.net/2016/05/%EB%B2%88%EC%97%AD-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%95%B1%EC%9D%B4-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%88%84%EC%88%98leak%EB%A5%BC-%EB%A7%8C%EB%93%9C%EB%8A%94-8%EA%B0%80%EC%A7%80/


depricated 로 나온 걸 하나 하나 해결하기 위해 찾은 걸 적어나갈 것이다.


URLDecoder.decode(getIntent().getExtras().getString("url"), "UTF-8");

getSettings().setUserAgent(0);  => getSettings().setUserAgentString("Android");

URLEncoder.encode("","UTF-8")


Implicitly using the default locale is a common source of bugs: Use toUpperCase(Locale) instead    NetworkCheck.java
url = url.toLowerCase();  ==> url = url.toLowerCase(Locale.getDefault());

// http://beginnersbook.com/2013/12/java-string-tolowercase-method-example/


The method decode(String) from the type URLDecoder is deprecated

URLEncoder.encode(String s, String enc);
import java.net.URLEncoder;
URLEncoder.encode("This text must be encoded!", "UTF-8");



AlertDialog: BUTTON_POSITIVE, BUTTON_NEUTRAL and BUTTON_NEGATIVE.


AlertDialog alertDialog = new AlertDialog.Builder(activity).create();
       alertDialog.setTitle("  [ 알림 ]");
       alertDialog.setMessage("등록된 휴대폰 번호가 없습니다.");
       alertDialog.setButton("확인", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int which) {
           }
       });

AlertDialog.Builder alertDialog = new AlertDialog.Builder(activity);
        alertDialog.setTitle("  [ 알림 ]")
        .setMessage("등록된 휴대폰 번호가 없습니다.")
        .setCancelable(false)
        .setNegativeButton("확인",new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                dialog.cancel();
            }
        });
        AlertDialog alert = alertDialog.create();
        alert.show();



alertDialog.setButton("확인", new DialogInterface.OnClickListener() {
   public void onClick(DialogInterface dialog, int which) {

   }
});

alertDialog.setButton(DialogInterface.BUTTON_POSITIVE,"확인", new DialogInterface.OnClickListener() {
   public void onClick(DialogInterface dialog, int which) {

   }
});



// http://www.technotalkative.com/issue-using-setjavascriptenabled-can-introduce-xss-vulnerabilities-application-review-carefully/

@SuppressLint("SetJavaScriptEnabled")
public class MyActivity extends Activity
{
...
}


// 내용 파악이 필요한 부분

showDialog(DIALOG_DOWNLOAD_PROGRESS);
The method showDialog(int) from the type Activity is deprecated
https://developer.android.com/reference/android/app/Activity.html#showDialog%28int%29
This method was deprecated in API level 13.


MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);


MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE,null,Charset.forName("UTF-8"));



NameValuePair deprecated
ContentValues values = new ContentValues();
values.put("key1", "value1");
values.put("key2", 123);



블로그 이미지

Link2Me

,
728x90

안드로이드 앱 설치되는 아이콘을 변경하려면 이미지 파일에서 icon.png 파일을 전부 변경해줘야 한다.

drawable-ldpi (120 dpi, Low density screen) - 36px x 36px
drawable-mdpi (160 dpi, Medium density screen) - 48px x 48px
drawable-hdpi (240 dpi, High density screen) - 72px x 72px
drawable-xhdpi (320 dpi, Extra-high density screen) - 96px x 96px
drawable-xxhdpi (480 dpi, Extra-extra-high density screen) - 144px x 144px
drawable-xxxhdpi (640 dpi, Extra-extra-extra-high density screen) - 192px x 192px


사이즈에 맞게 아이콘을 변경해준다.


AndroidManifest.xml 파일에서 지정해준다.

어플 이름은 values/strings.xml 파일에서 지정해준다.



이 다음에 해줄 사항은

기존 이미지가 남아 있을 수 있으니 완전 clear 를 해주어야 한다.

블로그 이미지

Link2Me

,
728x90

안드로이드 개발중에 소스코드등 기타 이상한것이 없는데 자꾸
"Unparsed aapt error(s)! Check the console for output"
다음과 같이 이클립스의 problem창에 에러로그가 남을때 가 있다.


Project -> clean 으로 생성된 중간파일을 삭제하면 된다.


안드로이드 eclipse 에서 소스를 수정해주면 저장을 해야만 변경사항이 반영된다.

C#은 소스를 수정하고 컴파일을 하면 알아서 내용이 자동 변경되는데

안드로이드 eclipse 는 이런 점이 매우 불편하다.

블로그 이미지

Link2Me

,
728x90

소스에 deprecated 라고 나오는 부분이다.



AlertDialog alertDialog = new AlertDialog.Builder(Login.this).create();
    alertDialog.setTitle("네트워크 연결 오류");
    alertDialog.setMessage("사용가능한 무선네트워크가 없습니다.\n" +
                           "먼저 무선네트워크를 확인해 주세요.");
    alertDialog.setCancelable(false);
    alertDialog.setIcon(R.drawable.icon_dialog);
    alertDialog.setButton("확인", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            finish();
            //application 프로세스를 강제 종료
            android.os.Process.killProcess(android.os.Process.myPid() );
                                           
        }
    });
    alertDialog.show();



아래와 같이 수정하면 된다.


AlertDialog.Builder builder = new AlertDialog.Builder(Login.this);
    builder.setTitle("네트워크 연결 오류")
    .setMessage("사용가능한 무선네트워크가 없습니다.\n" +
                "먼저 무선네트워크를 확인해 주세요.")
    .setCancelable(false)
    .setIcon(R.drawable.icon_dialog)
    .setNegativeButton("확인",new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            finish();
            //application 프로세스를 강제 종료
            android.os.Process.killProcess(android.os.Process.myPid());
        }
    });
    AlertDialog alert = builder.create();
    alert.show();




블로그 이미지

Link2Me

,