728x90

eclipse 안드로이드를 처음 접하는 초보자 입장에서 프로젝트를 만드는 방법에 대해 작성했다.

http://webnautes.tistory.com/829 게시글을 토대로 다른 블로그 자료들을 참조하여 수정 보완했으며, PHP JSON 코드 부분은 내 방식대로 코딩을 했다.


※ listView 에 대한 처리 개념에 대한 설명이 잘 된 곳은 http://recipes4dev.tistory.com/42


테스트 환경 : eclipse LUNA, Mars.2 둘다 정상동작


준비를 위한 세팅과정


여기까지가 기본 세팅을 위한 준비과정이다.


ListView는 사용자가 정의한 데이터 목록을 아이템 단위로 구성하여 화면에 출력하는 ViewGroup의 한 종류다.
ListView에 표시되는 아이템은 Image, Button, CheckBox 등 여러 View의 조합으로 구성되는 Custom 형태가 일반적이다.

ListView 는 일반 위젯(TextView)가 아니라 선택위젯이기 때문에, Adapter 에서 만들어주는 getView() 를 이용해서 아이템을 표시한다.
Adapter가 하는 역할은 사용자 데이터를 입력받아 View를 생성하는 것이며, Adapter에서 생성되는 View는 ListView 내 하나의 아이템 영역에 표시되는 것이다.

ListView 는 Adapter 를 사용하여 데이터를 표시하는 View 로 아래 설명은 Activity에 ListView를 추가할 때 사용하는 방법이다.

Fragment 에 ListView 를 사용하기 위해서는 LayoutInflater를 사용하여 Resource Layout을 View로 변환한 다음, 해당 View를 사용하여 findViewById()를 호출하는 방법으로 해야 한다.



2. list_item.xml 생성

이제 ListView 의 한 아이템에 표시될 Layout 을 정의해야 한다.


main.xml 파일에서 마우스 우클릭을 하여 Copy(Ctrl + C)를 한 다음에

layout 폴더에서 마우스 우클릭하여 붙여넣기를 눌러서 이름을 list_item.xml 로 수정한다.

layout.zip


초보자라면 기존 코드 내용을 전부 지우고 아래 코드를 복사하여 붙여넣기 한다. (연습이니까)

LinearLayout 기반 xml 파일 구성을 할 줄 안다면 본인이 원하는 형식으로 작성한다.



다른 이미지를 drawable-hdpi 폴더에 복사하고 해당 파일명을 적어주면 된다.

이 부분은 나중에 사진 보여주기 부분으로 연동해볼 목적으로 표시한 영역이다.


3. main.xml 수정

ListView 가 표시될 위치를 결정한다.

안드로이드는 사용자 인터페이스를 XML를 사용하여 정의한다.

main Layout 에는 ListView만 넣어주면 된다.

<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" >

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

</LinearLayout>

4. ListView 아이템에 표시될 사용자 데이터 정의


public class Main extends Activity {

    // 서버에서 가져올 정보를 담을 변수 선언
    String myJSON;
    private static final String TAG_RESULTS="result";
    private static final String TAG_UID = "uid";
    private static final String TAG_NAME = "name";
    private static final String TAG_Mobile ="mobile";  



5. Apdater 생성후 ListView에 지정

사용자 데이터가 준비되었으니 해당 데이터를 입력받아 View로 만들어줄 Adapter를 생성해야 한다.


public class Main extends Activity {

     // 서버 정보를 담을 배열(ArrayList)
    ArrayList<HashMap<String, String>> personList;
 
    ImageView imageView1;
    ListView list;  

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
      
        imageView1 = (ImageView) findViewById(R.id.imageView1);
        list = (ListView) findViewById(R.id.listView);
        personList = new ArrayList<HashMap<String,String>>();

    // 어댑터 생성, R.layout.list_item : Layout ID
    ListAdapter adapter = new SimpleAdapter(
        Main.this, personList, R.layout.list_item,
        new String[]{TAG_UID,TAG_NAME,TAG_Mobile},
        new int[]{R.id.uid, R.id.name, R.id.mobile}
    );

    list.setAdapter(adapter); // ListView 에 어댑터 설정(연결)

    }



6. AndroidManifest.xml 파일에 퍼미션 추가

안드로이드가 어떤 컴포넌트를 시작하려면 먼저 애플리케이션 안에 그 컴포넌트가 존재하는지를 알아야 한다. 애플리케이션안의 모든 컴포넌트들은 AndroidManifest.xml 안에 선언되어야 한다.

AndroidManifest.xml 파일에 선언되지 않은 Activity, Service, Content Provider 는 안드로이드 시스템에서 전혀 알 수가 없다. 결과적으로 실행할 수가 없다.


<uses-permission android:name="android.permission.INTERNET"/>





5. Main.java 코드 수정

※ 프로젝트 생성할 때 이름이 다르기 때문에 코드는 필요한 부분만 발췌하여 추가해야 한다.

   첨부된 파일을 다운로드 받아서 필요한 부분을 복사하여 붙여넣기 해보면 된다.

   

Main.java


URL은 특정 URL 주소를 다루기 위해 자바에서 제공되는 클래스다.

URL 객체가 생성되면, URL 클래스의 openStream() 메소드를 이용하여 해당 URL의 자원을 얻어오는 InputStream 을 리턴 받을 수 있으며, getConnection 메소드를 사용하여 URLConnection 객체도 얻어올 수 있다.
기본적으로 네트워크 작업을 기본 UI Thread에서 처리하는 것을 금지하고 별도의 Thread를 생성해서 처리하도록 하고 있다.

package com.example.phpmysql;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;

public class Main extends Activity {

    // 서버에서 가져올 정보를 담을 변수 선언

    String myJSON; 
    private static final String TAG_RESULTS="result"; 
    private static final String TAG_UID = "uid"; 
    private static final String TAG_NAME = "name"; 
    private static final String TAG_Mobile ="mobile"; 
 
    JSONArray peoples = null; 
 

     // 서버 정보를 담을 배열(ArrayList)

    ArrayList<HashMap<String, String>> personList; 
 
    ImageView imageView1;
    ListView list;   

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        imageView1 = (ImageView) findViewById(R.id.imageView1);
        list = (ListView) findViewById(R.id.listView); 
        personList = new ArrayList<HashMap<String,String>>(); 
        getDbData("http://IP주소/mobile/get_json.php"); 
    }
   
    public void setImage(int resId) {
        imageView1.setImageResource(resId);
    }
   
    private void getDbData(String string) {
        class GetDataJSON extends AsyncTask<String, Void, String>{ 
           
            @Override 
            protected String doInBackground(String... params) { 
 
                String uri = params[0];   
                BufferedReader bufferedReader = null;


                try { 
                    URL url = new URL(uri); 
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 연결 객체 생성
                    StringBuilder sb = new StringBuilder();
                   
                    if(conn != null){ // 연결되었으면
                        conn.setConnectTimeout(10000);
                        conn.setUseCaches(false);
                        if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){ // 연결 코드가 리턴되면
                            bufferedReader = new BufferedReader(new InputStreamReader(conn.getInputStream())); 
                            String json; 
                            while((json = bufferedReader.readLine())!= null){ 
                                sb.append(json + "\n"); 
                            }      
                        }
                    }
                    return sb.toString().trim();   
                } catch(Exception e){ 
                    return new String("Exception: " + e.getMessage());
                }    
            } 

 

            protected void onPostExecute(String result){ 
                myJSON=result; 
                showList(); 
            } 
        } 
       
        GetDataJSON g = new GetDataJSON(); 
        g.execute(string);
       
    }
   
    protected void showList(){ 
        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 = c.getString(TAG_Mobile); 
 
                HashMap<String,String> persons = new HashMap<String,String>(); 
 
                persons.put(TAG_UID,uid); 
                persons.put(TAG_NAME,name); 
                persons.put(TAG_Mobile,mobile); 
 
                personList.add(persons); 
            } 
 
            // 어댑터 생성, R.layout.list_item : Layout ID
            ListAdapter adapter = new SimpleAdapter( 
                    Main.this, personList, R.layout.list_item, 
                    new String[]{TAG_UID,TAG_NAME,TAG_Mobile}, 
                    new int[]{R.id.uid, R.id.name, R.id.mobile
            ); 
 
            list.setAdapter(adapter); // ListView 에 어댑터 설정(연결) 
 
        } catch (JSONException e) { 
            e.printStackTrace(); 
        }
    }   
}



AsyncTask : http://link2me.tistory.com/1031

JsonArray 기본 개념 설명 : http://link2me.tistory.com/1247 참조


StringBuilder 부분은 자바 자료는 아직 못봤는데 C# 과 거의 같은거 같다.

http://link2me.tistory.com/824


HashMap 클래스는 키와 데이터 값의 한쌍으로 묶어서 관리하며 키의 중복을 허용하지 않는다.


JSON(JavaScript Object Notation) 파서가 라이브러리 형태로 제공되므로 직접 문자열을 파싱할 필요가 없다. 안드로이드 역시 JSON 파서를 기본 제공한다.

- JSONArray 클래스는 JSON  파일에서 배열을 읽어들인다.

- JSONObject 클래스는 JSON 파일에서 객체를 읽어들인다.

- JSONArray 클래스의 메소드와 JSONObject 클래스의 메소드의 목록은 동일하나 () 안에 멤버의 이름을 인수로 전달받는다는 점이 다르다.



6. 결과화면



MainActivity.java 파일 Update

배우면서 갱신된 내용을 기록해 둔다.


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Vibrator;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.CookieManager;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

    private ListView mListView = null;
    private ListViewAdapter mAdapter = null;

    // 서버 정보를 파싱하기 위한 변수 선언
    String myJSON;
    private static final String TAG_RESULTS="result";
    private static final String TAG_UID = "uid";
    private static final String TAG_NAME = "name";
    private static final String TAG_Mobile ="mobile";

    JSONArray peoples = null;

    Context context;

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

        // ActionBar 제거하기
        ActionBar actionbar = getActionBar();
        actionbar.hide();

        mListView = (ListView) findViewById(R.id.listView);
        mAdapter = new ListViewAdapter(this);

        // 서버에 있는 정보를 읽어다가 mAdapter.addItem 에 추가하는 과정
        getDbData(Value.IPADDRESS + "/mobile/get_json.php");

        mListView.setAdapter(mAdapter);

        TextView searchView = (TextView) findViewById(R.id.SearchView);
        TextView phonebookView = (TextView) findViewById(R.id.PhonebookView);

        searchView.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(), "검색화면으로 이동합니다", Toast.LENGTH_LONG).show();
                Intent intent = new Intent(MainActivity.this, Search_Item.class);
                startActivity(intent);
            }
        });

        phonebookView.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(), "내 폰의 전화번호부를 가져옵니다", Toast.LENGTH_LONG).show();
                Intent intent = new Intent(MainActivity.this, PhonebookActivity.class);
                startActivity(intent);
            }

        });

    }


    private void getDbData(String string) {
        class GetDataJSON extends AsyncTask<String, Void, String>{

            @Override
            protected String doInBackground(String... params) {

                String uri = params[0];
                BufferedReader bufferedReader = null;
                try {
                    URL url = new URL(uri);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    // 세션 쿠키 전달
                    String cookieString = CookieManager.getInstance().getCookie(Value.IPADDRESS);

                    StringBuilder sb = new StringBuilder();

                    if(conn != null){ // 연결되었으면
                        //add request header
                        conn.setRequestMethod("POST");
                        conn.setRequestProperty("USER-AGENT", "Mozilla/5.0");
                        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                        conn.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
                        if (cookieString != null) {
                             conn.setRequestProperty("Cookie", cookieString);
                             Log.e("PHP_getCookie", cookieString);
                         }
                        conn.setConnectTimeout(10000);
                        conn.setReadTimeout(10000);
                        conn.setUseCaches(false);
                        conn.setDefaultUseCaches(false);
                        conn.setDoOutput(true); // POST 로 데이터를 넘겨주겠다는 옵션
                        //conn.setDoInput(true);

                        int responseCode = conn.getResponseCode();
                        System.out.println("GET Response Code : " + responseCode);
                        if(responseCode == HttpURLConnection.HTTP_OK){ // 연결 코드가 리턴되면
                            bufferedReader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
                            String json;
                            while((json = bufferedReader.readLine())!= null){
                                sb.append(json + "\n");
                            }
                        }
                        bufferedReader.close();
                    }
                    return sb.toString().trim();

                } catch(Exception e){
                    return new String("Exception: " + e.getMessage());
                }

            }

            protected void onPostExecute(String result){
                myJSON=result;
                showList();
            }
        }

        GetDataJSON g = new GetDataJSON();
        g.execute(string);

    }

    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 = 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();
        }

    }

    class ViewHolder {
         public LinearLayout child_layout;
         public ImageView mImage;
         public Button childListBtn;
         public TextView name;
         public TextView mobile;
    }

    private class ListViewAdapter extends BaseAdapter {

        private Context mContext = null;
        private ArrayList<ListData> mListData = new ArrayList<ListData>();

        public ListViewAdapter(Context mContext) {
            super();
            this.mContext = mContext;
        }

        @Override
        public int getCount() {
            return mListData.size();
        }

        @Override
        public Object getItem(int position) {
            return mListData.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder viewHolder;
            View view = convertView;
            if (view == null) {
                viewHolder = new ViewHolder();

                LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                view = inflater.inflate(R.layout.list_item, parent, false);

                view.setBackgroundColor(0x00FFFFFF);
                view.invalidate();

                viewHolder.child_layout = (LinearLayout) view.findViewById(R.id.child_layout);
                viewHolder.mImage = (ImageView) view.findViewById(R.id.mImage);
                viewHolder.childListBtn = (Button ) view.findViewById(R.id.childListBtn);
                viewHolder.name = (TextView) view.findViewById(R.id.name);
                viewHolder.mobile = (TextView) view.findViewById(R.id.mobile);

                view.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) view.getTag();
            }

            final ListData mData = mListData.get(position);

            if (mData.mImage != null) {
                viewHolder.mImage.setVisibility(View.VISIBLE);
                viewHolder.mImage.setImageDrawable(mData.mImage);
            } else {
                viewHolder.mImage.setVisibility(View.GONE);
            }

            viewHolder.childListBtn.setText(mData.uid);
            viewHolder.name.setText(mData.name);
            viewHolder.mobile.setText(mData.mobile);

            viewHolder.mImage.setOnClickListener(new ImageView.OnClickListener(){

                @Override
                public void onClick(View v) {
                    // 연락처 저장 함수 호출
                    AlertDialog.Builder SaveContact = new AlertDialog.Builder(MainActivity.this);
                    SaveContact.setMessage("전화번호를 저장하시겠습니까?");
                    DialogInterface.OnClickListener mail = new DialogInterface.OnClickListener() {

                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            int rawContactId = 0;
                            Contacts phonebook = new Contacts(); // 전화번호부 객체 생성
                            ContentResolver cr = getContentResolver();
                            String strContactName = mData.name;
                            String strMobileNO = mData.mobile;
                            String strofficeNO ="";
                            String strEmail ="";
                            String strPhoto ="";

                            rawContactId = phonebook.ContactsIDExistCheck(cr, strContactName);
                            if(rawContactId > 0){
                                // 기존 전화번호가 존재하면 삭제하고 새로 입력
                                phonebook.ContactsIDdelete(cr, context, rawContactId);
                            }

                            phonebook.ContactsIDinsert(cr, context, strContactName, strMobileNO, strofficeNO, strEmail, strPhoto);
                        }
                    };

                    DialogInterface.OnClickListener cancel = new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {

                        }
                    };
                    SaveContact.setPositiveButton("저장", mail);
                    SaveContact.setNegativeButton("취소", cancel);
                    SaveContact.show();
                }

            });

            viewHolder.childListBtn.setOnClickListener(new Button.OnClickListener(){

                @Override
                public void onClick(View v) {

                    Vibrator vibe = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                    vibe.vibrate(50);

                    AlertDialog showdialog = new AlertDialog.Builder(MainActivity.this)
                            .setTitle(mData.name)
                            .setMessage(mData.mobile + " 통화하시겠습니까?")
                            .setPositiveButton("예",
                                    new DialogInterface.OnClickListener() {

                                        public void onClick(DialogInterface dialog,int which) {

                                            Intent i = new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+ mData.mobile));
                                            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                            startActivity(i);
                                        }

                                    })
                            .setNegativeButton(
                                    "아니오",
                                    new DialogInterface.OnClickListener() {

                                        public void onClick(DialogInterface dialog,int which) {
                                            dialog.dismiss();
                                        }
                                    }).create();
                    showdialog.show();
                }

            });

            return view;
        }

        public void addItem(Drawable icon, String uid, String name, String mobile){
            ListData addInfo = null;
            addInfo = new ListData();
            addInfo.mImage = icon;
            addInfo.uid = uid;
            addInfo.name = name;
            addInfo.mobile = mobile;

            mListData.add(addInfo);
        }

        public void remove(int position){
            mListData.remove(position);
            mAdapter.notifyDataSetChanged();
        }


    }

    // Back 버튼을 누르면 어플 종료여부 확인 처리
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if( keyCode == KeyEvent.KEYCODE_BACK ) {
            new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert).setTitle("Quit").setMessage("어플을 종료하시겠습니까?").setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                @Override
                public void onClick( DialogInterface dialog, int which) {
                    moveTaskToBack(true); // 본 Activity finish후 다른 Activity가 뜨는 걸 방지.
                    finish();
                    //application 프로세스를 강제 종료
                    android.os.Process.killProcess(android.os.Process.myPid() );
                }
        }).setNegativeButton( "No", null ).show();

        return true;
      }

      return super.onKeyDown(keyCode, event);
     }

}



Back 버튼 누르면 어플 종료 되는 제대로 된 코드는 http://link2me.tistory.com/1466 활용하라.


블로그 이미지

Link2Me

,