728x90

안드로이드와 PHP 연동하여 MySQL DB에서 결과를 회신받아 안드로이드에서 보는 방법이다.

안드로이드 폰에서 검색어를 입력하면 서버에서 해당 검색어에 대한 결과를 돌려주는 방식이다.

인터넷에 올라온 자료들은 참조하여 테스트를 하다보니 결과가 나오질 않는다.
뭐가 잘못된 것인지 찾기 위해 각종 게시글을 참조하면서 하나 하나 잘못된 점을 찾아나갔다.
틀린 점이 하나 발견되었다.
conn.setDoInput(true); // 서버로부터 응답 헤더와 메시지를 읽어들이겠다는 옵션
이 코드가 추가되면 결과값이 없는지 화면에 아무것도 없다. 이 한줄의 쓰임새는 아직 파악을 못한 상태다.


==== get_json.php ======

<?php
    include_once $_SERVER['DOCUMENT_ROOT'].'/db.info.php';
    require_once $_SERVER['DOCUMENT_ROOT'].'/phpclass/dbClass.php';
    require_once $_SERVER['DOCUMENT_ROOT'].'/phpclass/xmlClass.php';

    $conn = new MySQLDbClass(); // DB 함수
    $DB_CONNECT = $conn->isConnectDb($DB);

    // 화면에 출력할 칼럼 발췌
    $sql = "select uid,name,mobile from Person ";
    $result = mysql_query($sql);

    // 1. JSON 데이터 생성방법
    $c = new jsonClass();
    echo $c->JSONEncode($result,'result');
?>


참고

class jsonClass {
    function JSONEncode($result,$varname){
        $R = array(); // 결과 담을 변수 생성
        while($row = mysql_fetch_object($result)) { 
            array_push($R, $row);
        }
       
        return json_encode(array($varname=>$R)); //배열-문자열등을 json형식의 '문자열'로 변환
    }
// end of Class


이제 검색 기능을 추가했다.

안드로이드에서 검색 명령어를 입력하면 PHP에서 검색명령어를 인식해야 한다.

GET 방식과 POST 방식 모두 입력값을 인식하도록 $_REQUEST['search'] 를 적어줬다.

Where 조건절에 쿼리문은 인덱스를 타지 않는 LIKE 를 적용했다.

값이 제대로 넘어오는지만 확인하기 위한 목적이기 때문에....


<?php

if(!isset($_REQUEST['search']) || empty($_REQUEST['search'])){

echo '비정상접속';

exit;

}


$query = $_REQUEST['search'];

include_once $_SERVER['DOCUMENT_ROOT'].'/db.info.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/phpclass/dbClass.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/phpclass/xmlClass.php';

$conn = new MySQLDbClass(); // DB 함수
$DB_CONNECT = $conn->isConnectDb($DB);

// 화면에 출력할 칼럼 발췌
$sql = "select uid,name,mobile from Person ";
if(!empty($query)) {
    $sql .= "where name LIKE '%".$query."%' or mobile LIKE '%".$query."%'";
}
$result = mysql_query($sql);

// 1. JSON 데이터 생성방법
$c = new jsonClass();
echo $c->JSONEncode($result,'result');
?>


안드로이드 코드 부문

===== MainActivity.java 추가 사항 =====

TextView searchView = (TextView) findViewById(R.id.SearchView);
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);
    }           
});


===== Search_Item.java =====

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

public class Search_Item extends Activity {
   
    static String getEdit;
    EditText inputSearch;
    Button btnSearch;
   
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.list_search);
       
        final Button btn = (Button) findViewById(R.id.back_btn);
        btn.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                finish();
            }
        });

        Button homeBtn = (Button) findViewById(R.id.home_btn);
        homeBtn.setOnClickListener(new Button.OnClickListener() {

            public void onClick(View v) {
                Intent mn = new Intent(Search_Item.this, MainActivity.class);
                mn.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(mn);
            }
        });

        // title set
        TextView title = (TextView) this.findViewById(R.id.navibar_text); // title
        title.setText("연락처 검색");

        inputSearch = (EditText) findViewById(R.id.list_search_edit);       
        btnSearch = (Button) findViewById(R.id.list_search_btn);
        btnSearch.setOnClickListener(new Button.OnClickListener(){

            @Override
            public void onClick(View v) {
                searchData();               
            }           
           
        });
    }
   
    private void searchData() {
        getEdit = inputSearch.getText().toString().trim();
        if(getEdit.equals("") ){
            Toast.makeText(Search_Item.this, "검색어를 입력하세요!", Toast.LENGTH_SHORT).show();
        } else {
            // 검색어 값을 전달
            Intent intent = new Intent(Search_Item.this, SearchActivity.class);
            intent.putExtra("search", getEdit);
            startActivity(intent);
            finish();
        }
       
    }
}


===== SearchActivity.java =====

import java.io.BufferedReader;
import java.io.DataOutputStream;
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.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.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

public class SearchActivity extends Activity {
   
    private ListView sListView = null;
    private ListViewAdapter sAdapter = null;

    // 서버 정보를 파싱하기 위한 변수 선언
    String searchJSON; 
    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; 
    String squery = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search_result);
       
        // ActionBar 제거하기  --> AnroidManifest.xml 파일을 수정했음. 화면이 까맣게 나오는 현상 때문에
        ActionBar actionbar = getActionBar();
        actionbar.hide();

        final Button btn = (Button) findViewById(R.id.back_btn);
        btn.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                finish();
            }
        });

        Button homeBtn = (Button) findViewById(R.id.home_btn);
        homeBtn.setOnClickListener(new Button.OnClickListener() {

            public void onClick(View v) {
                Intent mn = new Intent(SearchActivity.this, MainActivity.class);
                mn.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(mn);
            }
        });

        // title set
        TextView title = (TextView) this.findViewById(R.id.navibar_text); // title
        title.setText("검색 결과");
       
        sListView = (ListView) findViewById(R.id.list_search); 
        sAdapter = new ListViewAdapter(this);       

        // 이전 Activity에서 전달한 값 받기
        Intent intent = getIntent();
        squery = intent.getExtras().getString("search");

        // 서버에 있는 정보를 읽어다가 mAdapter.addItem 에 추가하는 과정
        String url ="http://IP주소/mobile/get_json.php";
        getDbData(url);
       
        sListView.setAdapter(sAdapter);

    }
   
    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 post_data = "search=" + Uri.encode(squery);

                    StringBuilder sb = new StringBuilder(); 
 
                    if(conn != null){ // 연결되었으면
                        conn.setConnectTimeout(10000); // milliseconds 연결 타임아웃시간

                        //add request header
                        conn.setUseCaches(false);
                        conn.setDefaultUseCaches(false);
                        //conn.setDoInput(true); // 서버로부터 응답 헤더와 메시지를 읽어들이겠다는 옵션
                        // 이 코드를 활성화하면 응답된 내용이 전혀 없다. 비활성화하면 정상이다.
                        conn.setDoOutput(true); // POST 로 데이터를 넘겨주겠다는 옵션

                        conn.setRequestMethod("POST");

                        // 서버에게 웹에서 <Form>으로 값이 넘어온 것과 같은 방식으로 처리하라고 알려준다

                        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");
 
                        // Send POST request (서버로 값 전송)
                        DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
                        wr.writeBytes(
post_data);
                        wr.flush();
                        wr.close();
                       
                        int responseCode = conn.getResponseCode();
                        System.out.println("GET Response Code : " + responseCode); //
200 : 정상연결                      
                        if(responseCode == HttpURLConnection.HTTP_OK){ // 연결 코드가 리턴되면
                            bufferedReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                            String json;
                            while((json = bufferedReader.readLine())!= null){ 
// 라인단위로 읽는다

                               sb.append(json + "\n"); // View에 표시하기 위해 라인 구분자 추가

                            }     
                        }
                        bufferedReader.close();
                    }
                    return sb.toString().trim(); 
 
                } catch(Exception e){ 
                    return new String("Exception: " + e.getMessage());
                }  
 
            } 
 
            protected void onPostExecute(String result){ 
                searchJSON=result; 
                showList(); 
            }           
        } 
       
        GetDataJSON g = new GetDataJSON(); 
        g.execute(string);                
       
    }
   
    protected void showList() {
        // 서버에서 읽어온 정보를 sAdapter 에 저장하고 화면에 출력
        try { 
            JSONObject jsonObj = new JSONObject(searchJSON); 
            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 );
               
                sAdapter.addItem(myIcon,uid,name,mobile);
            }         


            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    sAdapter.notifyDataSetChanged();
                }
            });
           
        } catch (JSONException e) { 
            e.printStackTrace(); 
        }

    } 

    class ViewHolder {
         public LinearLayout child_slayout;
         public ImageView mImage;     
         public Button ListBtn;     
         public TextView name;
         public TextView mobile;
    }

    private class ListViewAdapter extends BaseAdapter {

        private Context sContext = null;
        private ArrayList<ListData> sListData = new ArrayList<ListData>();
       
        public ListViewAdapter(Context mContext) {
            super();
            this.sContext = mContext;
        }
       
        @Override
        public int getCount() {       
            return sListData.size();
        }

        @Override
        public Object getItem(int position) {       
            return sListData.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) sContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                view = inflater.inflate(R.layout.search_item, parent, false);
               
                view.setBackgroundColor(0x00FFFFFF);
                view.invalidate();
         
                viewHolder.child_slayout = (LinearLayout) view.findViewById(R.id.child_searchlayout);
                viewHolder.mImage = (ImageView) view.findViewById(R.id.mImage);
                viewHolder.ListBtn = (Button ) view.findViewById(R.id.search_ListBtn);
                viewHolder.name = (TextView) view.findViewById(R.id.search_name);
                viewHolder.mobile = (TextView) view.findViewById(R.id.search_mobile);
         
                view.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) view.getTag();
            }
           
            final ListData sData = sListData.get(position);
           
            if (sData.mImage != null) {
                viewHolder.mImage.setVisibility(View.VISIBLE);
                viewHolder.mImage.setImageDrawable(sData.mImage);
            } else {
                viewHolder.mImage.setVisibility(View.GONE);
            }
           
            viewHolder.ListBtn.setText(sData.uid);
            viewHolder.name.setText(sData.name);
            viewHolder.mobile.setText(sData.mobile);
           
            viewHolder.ListBtn.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(SearchActivity.this)
                            .setTitle(sData.name)
                            .setMessage(sData.mobile + " 통화하시겠습니까?")
                            .setPositiveButton("예",
                                    new DialogInterface.OnClickListener() {

                                        public void onClick(DialogInterface dialog,int which) {

                                            Intent i = new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+ sData.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;
                    
            sListData.add(addInfo);
        }
   
    }

}


===== AndroidManifest.xml =====

아래 순서는 Login.java --> MainActivity.java --> Search_Item.java  --> SearchActivity.java 파일 순으로 실행된다.


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.phpmysqljson"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="23" />
   
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
 
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.MODIFY_PHONE_READ"/>
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.VIBRATE" />
       
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".Login"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:launchMode="singleTop"
            android:windowSoftInputMode="adjustPan" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
       
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:launchMode="singleTop" />
       
        <activity
            android:name=".Search_Item"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@android:style/Theme.NoTitleBar" />

        <activity
            android:name=".SearchActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:launchMode="singleTop" />
       
    </application>

</manifest>

블로그 이미지

Link2Me

,
728x90

안드로이드와 PHP 연동하여 MySQL DB에서 결과를 회신받아 안드로이드에서 보는 방법에 대해 포스팅을 했었다.

검색어를 입력하고 전달한 검색어를 통해 결과를 회신받는 방법중 하나인 GET 방식부터 테스트를 해봤다.

인터넷에 있는 자료들은 참조하여 일일이 테스트를 하면서 부족한 부분은 보강하고 완벽하게 동작되는 걸 확인하고 적어둔다.


==== get_json.php ======

<?php
    include_once $_SERVER['DOCUMENT_ROOT'].'/db.info.php';
    require_once $_SERVER['DOCUMENT_ROOT'].'/phpclass/dbClass.php';
    require_once $_SERVER['DOCUMENT_ROOT'].'/phpclass/xmlClass.php';

    $conn = new MySQLDbClass(); // DB 함수
    $DB_CONNECT = $conn->isConnectDb($DB);

    // 화면에 출력할 칼럼 발췌
    $sql = "select uid,name,mobile from Person ";
    $result = mysql_query($sql);

    // 1. JSON 데이터 생성방법
    $c = new jsonClass();
    echo $c->JSONEncode($result,'result');
?>

이제 검색 기능을 추가했다.

안드로이드에서 검색 명령어를 입력하면 PHP에서 검색명령어를 인식해야 한다.

GET 방식과 POST 방식 모두 입력값을 인식하도록 $_REQUEST['search'] 를 적어줬다.

Where 조건절에 쿼리문은 인덱스를 타지 않는 LIKE 를 적용했다.

값이 제대로 넘어오는지만 확인하기 위한 목적이기 때문에....


<?php
$query = $_REQUEST['search'];

include_once $_SERVER['DOCUMENT_ROOT'].'/db.info.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/phpclass/dbClass.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/phpclass/xmlClass.php';

$conn = new MySQLDbClass(); // DB 함수
$DB_CONNECT = $conn->isConnectDb($DB);

// 화면에 출력할 칼럼 발췌
$sql = "select uid,name,mobile from Person ";
if(!empty($query)) {
    $sql .= "where name LIKE '%".$query."%' or mobile LIKE '%".$query."%'";
}
$result = mysql_query($sql);

// 1. JSON 데이터 생성방법
$c = new jsonClass();
echo $c->JSONEncode($result,'result');
?>



안드로이드 코드 부문

===== MainActivity.java 추가 사항 =====

TextView searchView = (TextView) findViewById(R.id.SearchView);
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);
    }           
});


===== Search_Item.java =====

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

public class Search_Item extends Activity {
   
    static String getEdit;
    EditText inputSearch;
    Button btnSearch;
   
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.list_search);
       
        final Button btn = (Button) findViewById(R.id.back_btn);
        btn.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                finish();
            }
        });

        Button homeBtn = (Button) findViewById(R.id.home_btn);
        homeBtn.setOnClickListener(new Button.OnClickListener() {

            public void onClick(View v) {
                Intent mn = new Intent(Search_Item.this, MainActivity.class);
                mn.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(mn);
            }
        });

        // title set
        TextView title = (TextView) this.findViewById(R.id.navibar_text); // title
        title.setText("연락처 검색");

        inputSearch = (EditText) findViewById(R.id.list_search_edit);       
        btnSearch = (Button) findViewById(R.id.list_search_btn);
        btnSearch.setOnClickListener(new Button.OnClickListener(){

            @Override
            public void onClick(View v) {
                searchData();               
            }           
           
        });
    }
   
    private void searchData() {
        getEdit = inputSearch.getText().toString().trim();
        if(getEdit.equals("") ){
            Toast.makeText(Search_Item.this, "검색어를 입력하세요!", Toast.LENGTH_SHORT).show();
        } else {
            // 검색어 값을 전달
            Intent intent = new Intent(Search_Item.this, SearchActivity.class);
            intent.putExtra("search", getEdit);
            startActivity(intent);
            finish();
        }
       
    }
}


===== SearchActivity.java =====

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.Activity;
import android.app.AlertDialog;
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.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

public class SearchActivity extends Activity {
   
    private ListView sListView = null;
    private ListViewAdapter sAdapter = null;

    // 서버 정보를 파싱하기 위한 변수 선언
    String searchJSON; 
    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; 
    String squery;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search_result);
       
        // ActionBar 제거하기 

        // android:theme="@android:style/Theme.NoTitleBar" 에 추가했기 때문에 반드시 비활성화해야 함
        //ActionBar actionbar = getActionBar();
        //actionbar.hide();

        final Button btn = (Button) findViewById(R.id.back_btn);
        btn.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                finish();
            }
        });

        Button homeBtn = (Button) findViewById(R.id.home_btn);
        homeBtn.setOnClickListener(new Button.OnClickListener() {

            public void onClick(View v) {
                Intent mn = new Intent(SearchActivity.this, MainActivity.class);
                mn.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(mn);
            }
        });

        // title set
        TextView title = (TextView) this.findViewById(R.id.navibar_text); // title
        title.setText("검색 결과");
       
        sListView = (ListView) findViewById(R.id.list_search); 
        sAdapter = new ListViewAdapter(this);       

        // 이전 Activity에서 전달한 값 받기
        Intent intent = getIntent();
        squery = intent.getExtras().getString("search");

        // 서버에 있는 정보를 읽어다가 mAdapter.addItem 에 추가하는 과정
        String url ="http://IP주소/mobile/get_json.php?search=" + Uri.encode(squery); // 한글검색도 처리
        getDbData(url);
       
        sListView.setAdapter(sAdapter);

    }
   
    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); // milliseconds 연결 타임아웃시간
                        conn.setUseCaches(false);
                        conn.setDefaultUseCaches(false);

                        int responseCode = conn.getResponseCode();
                        System.out.println("GET Response Code : " + responseCode);                       
                        if(responseCode == HttpURLConnection.HTTP_OK){ // 연결 코드가 리턴되면
                            bufferedReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                            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){ 
                searchJSON=result; 
                showList(); 
            }           
        } 
       
        GetDataJSON g = new GetDataJSON(); 
        g.execute(string);                
       
    }
   
    protected void showList() {
        // 서버에서 읽어온 정보를 sAdapter 에 저장하고 화면에 출력
        try { 
            JSONObject jsonObj = new JSONObject(searchJSON); 
            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 );
               
                sAdapter.addItem(myIcon,uid,name,mobile);
            }         


            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    sAdapter.notifyDataSetChanged();
                }
            });
           
        } catch (JSONException e) { 
            e.printStackTrace(); 
        }

    } 

    class ViewHolder {
         public LinearLayout child_slayout;
         public ImageView mImage;     
         public Button ListBtn;     
         public TextView name;
         public TextView mobile;
    }

    private class ListViewAdapter extends BaseAdapter {

        private Context sContext = null;
        private ArrayList<ListData> sListData = new ArrayList<ListData>();
       
        public ListViewAdapter(Context mContext) {
            super();
            this.sContext = mContext;
        }
       
        @Override
        public int getCount() {       
            return sListData.size();
        }

        @Override
        public Object getItem(int position) {       
            return sListData.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) sContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                view = inflater.inflate(R.layout.search_item, parent, false);
               
                view.setBackgroundColor(0x00FFFFFF);
                view.invalidate();
         
                viewHolder.child_slayout = (LinearLayout) view.findViewById(R.id.child_searchlayout);
                viewHolder.mImage = (ImageView) view.findViewById(R.id.mImage);
                viewHolder.ListBtn = (Button ) view.findViewById(R.id.search_ListBtn);
                viewHolder.name = (TextView) view.findViewById(R.id.search_name);
                viewHolder.mobile = (TextView) view.findViewById(R.id.search_mobile);
         
                view.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) view.getTag();
            }
           
            final ListData sData = sListData.get(position);
           
            if (sData.mImage != null) {
                viewHolder.mImage.setVisibility(View.VISIBLE);
                viewHolder.mImage.setImageDrawable(sData.mImage);
            } else {
                viewHolder.mImage.setVisibility(View.GONE);
            }
           
            viewHolder.ListBtn.setText(sData.uid);
            viewHolder.name.setText(sData.name);
            viewHolder.mobile.setText(sData.mobile);
           
            viewHolder.ListBtn.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(SearchActivity.this)
                            .setTitle(sData.name)
                            .setMessage(sData.mobile + " 통화하시겠습니까?")
                            .setPositiveButton("예",
                                    new DialogInterface.OnClickListener() {

                                        public void onClick(DialogInterface dialog,int which) {

                                            Intent i = new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+ sData.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;
                    
            sListData.add(addInfo);
        }
   
    }
}


===== AndroidManifest.xml ====

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.phpmysqljson"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="23" />
   
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
 
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.MODIFY_PHONE_READ"/>
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.VIBRATE" />
       
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".Login"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:launchMode="singleTop"
            android:windowSoftInputMode="adjustPan" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
       
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:launchMode="singleTop" />
       
        <activity
            android:name=".Search_Item"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@android:style/Theme.NoTitleBar" />

        <activity
            android:name=".SearchActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@android:style/Theme.NoTitleBar" />
       
    </application>

</manifest>


다음에는 POST 로 값을 넘기는 방법에 대해 테스트를 해보련다.

블로그 이미지

Link2Me

,
728x90

안드로이드에서 PHP 서버에 등록한 단말이 없으면 등록하고, 등록한 단말이 있으면 맞는 단말인지 체크하여 로그인하는 기능을 추가했다.


1. 안드로이드 Login.java

import java.util.ArrayList;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;

import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

public class Login extends Activity {

    String getDeviceID; // 스마트기기의 장치 고유값
    ProgressDialog dialog = null;
    EditText etId;
    EditText etPw;
   
    String loginID;
    String loginPW;
    CheckBox autologin;
    Boolean loginChecked;
    List<NameValuePair> params;
    public SharedPreferences settings;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.login);
       
        // ActionBar 제거하기
        ActionBar actionbar = getActionBar();
        actionbar.hide();

        // 네트워크 연결상태 체크
        if(NetworkConnection() == false){
            NotConnected_showAlert();
        }
       
        etId = (EditText) findViewById(R.id.login_id_edit);
        etPw = (EditText) findViewById(R.id.login_pw_edit);   
        autologin = (CheckBox) findViewById(R.id.autologinchk);
       
        settings = getSharedPreferences("settings",    Activity.MODE_PRIVATE);
        loginChecked = settings.getBoolean("LoginChecked", false);
        if (loginChecked) {
            etId.setText(settings.getString("loginID", ""));
            etPw.setText(settings.getString("loginPW", ""));
            autologin.setChecked(true);
        }
       
        if(!settings.getString("loginID", "").equals("")) etPw.requestFocus();
       
        Button submit = (Button) findViewById(R.id.login_btn);
        submit.setOnClickListener(new Button.OnClickListener(){

            @Override
            public void onClick(View v) {
                dialog = ProgressDialog.show(Login.this, "", "Validating user...", true);
                 new Thread(new Runnable() {
                        public void run() {
                            login();                         
                        }
                       
                      }).start();                
            }
           
        });
       
    }

    void login() {
        try {
            loginID = etId.getText().toString().trim();
            loginPW = etPw.getText().toString().trim();
           
            // 단말기의 ID 정보를 얻기 위해서는 READ_PHONE_STATE 권한이 필요
            TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
            if (mTelephony.getDeviceId() != null){
                getDeviceID = mTelephony.getDeviceId();  // 스마트폰 기기 정보
            } else {
                getDeviceID = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID);
            }       
       
            String postURL = "http://IP주소/loginChk.php";
            HttpPost httppost = new HttpPost(postURL);
           
            // 전달할 인자들
            params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("loginID", loginID));
            params.add(new BasicNameValuePair("loginPW", loginPW));
            params.add(new BasicNameValuePair("deviceID", getDeviceID));
           
            UrlEncodedFormEntity ent = new UrlEncodedFormEntity(params,HTTP.UTF_8);
            httppost.setEntity(ent);

            HttpClient httpclient = new DefaultHttpClient();
            ResponseHandler<String> responseHandler = new BasicResponseHandler();
            final String responsePost = httpclient.execute(httppost, responseHandler);

            System.out.println("DeviceID : " + getDeviceID);
            System.out.println("Response : " + responsePost);
            runOnUiThread(new Runnable() {
                public void run() {
                    dialog.dismiss();
                }
            });
           
            if(responsePost.equalsIgnoreCase("Login Success")){ // 로그인 정보 불일치
                runOnUiThread(new Runnable() {
                    public void run() {
                        Toast.makeText(Login.this,"Login Success", Toast.LENGTH_SHORT).show();
                    }
                });
               
                startActivity(new Intent(Login.this, MainActivity.class));
                finish(); // finish()를 호출해서 Activity를 없애줌

            } else if(responsePost.equalsIgnoreCase("Phone Dismatch")){ // 등록된 단말기와 불일치
                deviceDismatch_showAlert();
            } else {
                showAlert();
            }
        } catch(Exception e) {
            dialog.dismiss();
            System.out.println("Exception : " + e.getMessage());
        }
       
    }
   
    public void onStop(){
        // 어플리케이션이 화면에서 사라질때
        super.onStop();       
        // 자동 로그인이 체크되어 있고, 로그인에 성공했으면 폰에 자동로그인 정보 저장     
        if (autologin.isChecked()) {
             settings = getSharedPreferences("settings",Activity.MODE_PRIVATE);
             SharedPreferences.Editor editor = settings.edit();
            
             editor.putString("loginID", loginID);
             editor.putString("loginPW", loginPW);
             editor.putBoolean("LoginChecked", true);
            
             editor.commit();
         } else {
             // 자동 로그인 체크가 해제되면 폰에 저장된 정보 모두 삭제
             settings = getSharedPreferences("settings",    Activity.MODE_PRIVATE);
             SharedPreferences.Editor editor = settings.edit();
              editor.clear(); // 모든 정보 삭제
             editor.commit();
         }
       
    }

    public void deviceDismatch_showAlert(){
        Login.this.runOnUiThread(new Runnable() {
            public void run() {
                AlertDialog.Builder builder = new AlertDialog.Builder(Login.this);
                builder.setTitle("등록단말 불일치");
                builder.setMessage("최초 등록된 단말기가 아닙니다.\n" + "관리자에게 문의하여 단말기 변경신청을 하시기 바랍니다.") 
                       .setCancelable(false)
                       .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                           public void onClick(DialogInterface dialog, int id) {
                           }
                       });                    
                AlertDialog alert = builder.create();
                alert.show();              
            }
        });
    }

    public void showAlert(){
        Login.this.runOnUiThread(new Runnable() {
            public void run() {
                AlertDialog.Builder builder = new AlertDialog.Builder(Login.this);
                builder.setTitle("로그인 에러");
                builder.setMessage("로그인 정보가 일치하지 않습니다.") 
                       .setCancelable(false)
                       .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                           public void onClick(DialogInterface dialog, int id) {
                           }
                       });                    
                AlertDialog alert = builder.create();
                alert.show();              
            }
        });
    }
   
    private void NotConnected_showAlert() {
        AlertDialog.Builder builder = new AlertDialog.Builder(Login.this);
        builder.setTitle("네트워크 연결 오류");
        builder.setMessage("사용 가능한 무선네트워크가 없습니다.\n" + "먼저 무선네트워크 연결상태를 확인해 주세요.") 
               .setCancelable(false)
               .setPositiveButton("확인", new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       finish(); // exit
                           //application 프로세스를 강제 종료
                           android.os.Process.killProcess(android.os.Process.myPid() );
                   }
               });                    
        AlertDialog alert = builder.create();
        alert.show();        
       
    }
   
    private boolean NetworkConnection() {
        ConnectivityManager manager = (ConnectivityManager) getSystemService (Context.CONNECTIVITY_SERVICE);
        boolean isMobileAvailable = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).isAvailable();
        boolean isMobileConnect = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).isConnectedOrConnecting();
        boolean isWifiAvailable = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isAvailable();
        boolean isWifiConnect = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnectedOrConnecting();
       
        if ((isWifiAvailable && isWifiConnect) || (isMobileAvailable && isMobileConnect)){
            return true;
        }else{
            return false;
        }
    }
   
    // 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);
     }
       
}


2. PHP 서버 loginCheck.php

<?php
session_start();
if(isset($_POST['loginID']) && !empty($_POST['loginID']) && isset($_POST['loginPW']) && !empty($_POST['loginPW'])) {
    $loginID = trim($_POST['loginID']);
    $loginPW = trim($_POST['loginPW']);
    $deviceID = trim($_POST['deviceID']);

    require_once $_SERVER['DOCUMENT_ROOT'].'/dbconnect.php';
    require_once $_SERVER['DOCUMENT_ROOT'].'/phpclass/loginClass.php';

    $c=new LoginClass();
    $deviceID = $deviceID ? $deviceID : '';
    if(empty($deviceID)){
        $row = $c->WebUserAuthCheck($loginID,$loginPW);
        if(is_array($row)) {
            if($row['code'] > 0) {
                $_SESSION['userID'] = $row['id'];
                $_SESSION['userPW'] = md5($loginPW);
                $_SESSION['code'] = $row['code'];
                $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
                $_SESSION['ua'] = $_SERVER['HTTP_USER_AGENT'];

                echo("<meta http-equiv='Refresh' content='0; URL=mobile/list.php'>");
            }
        }

    } else {
        $result = $c->MobileUserAuthCheck($loginID,$loginPW,$deviceID);
        if($result > 0 ) {
            echo 'Login Success';
        } else if($result == 0) {
            echo 'Login Fail';
        } else {
            echo 'Phone Dismatch';
        }
    }
   
} else {
    echo("<meta http-equiv='Refresh' content='0; URL=loginForm.php'>");
}
?>


MobileUserAuthCheck($loginID,$loginPW,$deviceID) 함수 내용은 공개하지 않는다.

그냥 로직만 설명하면 ID, PW, deviceID 검사를 해서 deviceID가 없으면 필드(PhoneID)에 추가하고, 등록되어 있으면 현재 폰의 고유장치값과 서버에 등록된 값이 일치하는지 검사하여 틀리면 불일치 메시지를 화면에 뿌린다.

화면에 뿌린 echo 'Phone Dismatch'; 내용을 안드로이드 소스에서 인식하여 해당되는 메시지를 화면에 출력한다.


http://link2me.tistory.com/1032 게시물 내용과 달라진 사항을 비교해보면 도움이 된다.

로그인 처리 부분은 이 정도면 충분한 거 같으니 PHP JSON 데이터 검색하는 루틴을 추가해볼 것이다.


블로그 이미지

Link2Me

,
728x90

안드로이드와 PHP 간에 로그인 연동처리 방법을 적어둔다.


1. 안드로이드 단말에서 PHP 서버로 정보를 보낼 때

    - 안드로이드 단말에서 보내는 코드

    String postURL = "http://192.168.1.2/Logincheck.php";

    HttpPost httppost= new HttpPost(postURL);


    // 전달할 인자
    nameValuePairs = new ArrayList<NameValuePair>(2);   
    nameValuePairs.add(new BasicNameValuePair("loginID",et.getText().toString().trim()));
    nameValuePairs.add(new BasicNameValuePair("loginPW",pass.getText().toString().trim()));
    httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));


    //Execute HTTP Post Request   
    httpclient=new DefaultHttpClient();
    ResponseHandler<String> responseHandler = new BasicResponseHandler();
    final String response = httpclient.execute(httppost, responseHandler);

    - 안드로이드 단말에서 보낸 정보를 PHP 에서 인식하는 코드 추가

      $userID = $_POST['loginID'];

      $password = $_POST['loginPW'];


2. PHP 서버의 정보를 안드로이드 단말로 가져올 때

    - 허니콤(3.0) 이후로 네트워크 접속시 별도의 스레드로 돌려야 오류가 발생하지 않는다.

      AsyncTask 를 주로 사용한다.



3. Android 소스 코드

import java.util.ArrayList;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

public class Login extends Activity {

    String getDeviceID; // 스마트기기의 장치 고유값
    ProgressDialog dialog = null;
    EditText etId;
    EditText etPw;
   
    String loginID;
    String loginPW;
    CheckBox autologin;
    Boolean loginChecked;
    List<NameValuePair> params;
    public SharedPreferences settings;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.login);
       
        // 네트워크 연결상태 체크
        if(NetworkConnection() == false){
            NotConnected_showAlert();
        }
       
        etId = (EditText) findViewById(R.id.login_id_edit);
        etPw = (EditText) findViewById(R.id.login_pw_edit);   
        autologin = (CheckBox) findViewById(R.id.autologinchk);
       

       // 폰에 저장된 로그인 정보 가져오기
        settings = getSharedPreferences("settings",    Activity.MODE_PRIVATE);
        loginChecked = settings.getBoolean("LoginChecked", false);
        if (loginChecked) {
            etId.setText(settings.getString("loginID", ""));
            etPw.setText(settings.getString("loginPW", ""));
            autologin.setChecked(true);
        }
       
        if(!settings.getString("loginID", "").equals("")) etPw.requestFocus();
       
        Button submit = (Button) findViewById(R.id.login_btn);
        submit.setOnClickListener(new Button.OnClickListener(){

            @Override
            public void onClick(View v) {
                dialog = ProgressDialog.show(Login.this, "", "Validating user...", true);
                 new Thread(new Runnable() {
                        public void run() {
                            login();                         
                        }
                       
                      }).start();                
            }
           
        });
       
    }

    void login() {
        try {
            loginID = etId.getText().toString().trim();
            loginPW = etPw.getText().toString().trim();
           
            // 단말기의 ID 정보를 얻기 위해서는 READ_PHONE_STATE 권한이 필요
            TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
            if (mTelephony.getDeviceId() != null){
                getDeviceID = mTelephony.getDeviceId();  // 스마트폰 기기정보
            } else {
                getDeviceID = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID);
            }       
       
            String postURL = "http://IP주소/loginChk.php";
            HttpPost httppost = new HttpPost(postURL);
           
            // 전달할 인자들
            params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("loginID", loginID));
            params.add(new BasicNameValuePair("loginPW", loginPW));
            params.add(new BasicNameValuePair("deviceID", getDeviceID));
           
            UrlEncodedFormEntity ent = new UrlEncodedFormEntity(params,HTTP.UTF_8);
            httppost.setEntity(ent);

            HttpClient httpclient = new DefaultHttpClient();
            ResponseHandler<String> responseHandler = new BasicResponseHandler();
            final String responsePost = httpclient.execute(httppost, responseHandler);

            System.out.println("DeviceID : " + getDeviceID);
            System.out.println("Response : " + responsePost);
            runOnUiThread(new Runnable() {
                public void run() {
                    dialog.dismiss();
                }
            });
           
            if(responsePost.equalsIgnoreCase("<meta http-equiv='Refresh' content='0; URL=mobile/list.php'>")){
                runOnUiThread(new Runnable() {
                    public void run() {
                        Toast.makeText(Login.this,"Login Success", Toast.LENGTH_SHORT).show();
                    }
                });
               
                startActivity(new Intent(Login.this, MainActivity.class));
                finish(); // finish()를 호출해서 Activity를 없애줌
            } else {
                showAlert();               
            }
        } catch(Exception e) {
            dialog.dismiss();
            System.out.println("Exception : " + e.getMessage());
        }
       
    }
   
    public void onStop(){
        // 어플리케이션이 화면에서 사라질때
        super.onStop();       
        // 자동 로그인이 체크되어 있고, 로그인에 성공했으면 폰에 자동로그인 정보 저장     
        if (autologin.isChecked()) {
             settings = getSharedPreferences("settings",Activity.MODE_PRIVATE);
             SharedPreferences.Editor editor = settings.edit();
            
             editor.putString("loginID", loginID);
             editor.putString("loginPW", loginPW);
             editor.putBoolean("LoginChecked", true);
            
             editor.commit();
         } else {
             // 자동 로그인 체크가 해제되면 폰에 저장된 정보 모두 삭제
             settings = getSharedPreferences("settings",    Activity.MODE_PRIVATE);
             SharedPreferences.Editor editor = settings.edit();
              editor.clear(); // 모든 정보 해제
             editor.commit();
         }
       
    }
   
    public void showAlert(){
        Login.this.runOnUiThread(new Runnable() {
            public void run() {
                AlertDialog.Builder builder = new AlertDialog.Builder(Login.this);
                builder.setTitle("Login Error.");
                builder.setMessage("로그인 정보가 일치하지 않습니다.") 
                       .setCancelable(false)
                       .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                           public void onClick(DialogInterface dialog, int id) {
                           }
                       });                    
                AlertDialog alert = builder.create();
                alert.show();              
            }
        });
    }

    private void NotConnected_showAlert() {
        AlertDialog.Builder builder = new AlertDialog.Builder(Login.this);
        builder.setTitle("네트워크 연결 오류");
        builder.setMessage("사용 가능한 무선네트워크가 없습니다.\n" + "먼저 무선네트워크 연결상태를 확인해 주세요.") 
               .setCancelable(false)
               .setPositiveButton("확인", new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       finish(); // exit
                           //application 프로세스를 강제 종료
                           android.os.Process.killProcess(android.os.Process.myPid() );
                   }
               });                    
        AlertDialog alert = builder.create();
        alert.show();        
       
    }
   
    private boolean NetworkConnection() {
        ConnectivityManager manager = (ConnectivityManager) getSystemService (Context.CONNECTIVITY_SERVICE);
        boolean isMobileAvailable = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).isAvailable();
        boolean isMobileConnect = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).isConnectedOrConnecting();
        boolean isWifiAvailable = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isAvailable();
        boolean isWifiConnect = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnectedOrConnecting();
       
        if ((isWifiAvailable && isWifiConnect) || (isMobileAvailable && isMobileConnect)){
            return true;
        }else{
            return false;
        }
    }
   
}


4. AndroidManifest.xml 파일 수정사항

   - 로그인(Login.java) 한 후, 메인(MainActivity.java) 가 실행되게 하는 순서에 맞게

     AndroidManifest.xml 파일 내용도 수정을 해줘야만 된다.


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.phpmysqljson"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="23" />
   
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
 
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.VIBRATE" />
       
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".Login"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:launchMode="singleTop"
            android:windowSoftInputMode="adjustPan" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
       
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:launchMode="singleTop" />
       
    </application>

</manifest>


5. PHP 로그인 코드

<?php
session_start();
if(isset($_POST['loginID']) && !empty($_POST['loginID']) && isset($_POST['loginPW']) && !empty($_POST['loginPW'])) {
    $loginID = trim($_POST['loginID']);
    $loginPW = trim($_POST['loginPW']);

    require_once $_SERVER['DOCUMENT_ROOT'].'/dbconnect.php';
    require_once $_SERVER['DOCUMENT_ROOT'].'/phpclass/loginClass.php';

    $c=new LoginClass();
    $row = $c->LoginUserAuthCheck($loginID,$loginPW);
    if(is_array($row)) {
        if($row['code'] > 0) {
            $_SESSION['userID'] = $row['id'];
            $_SESSION['userPW'] = md5($loginPW);
            $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
            $_SESSION['ua'] = $_SERVER['HTTP_USER_AGENT'];

            echo("<meta http-equiv='Refresh' content='0; URL=mobile/list.php'>");
        }
    }
} else {
    echo("<meta http-equiv='Refresh' content='0; URL=loginForm.php'>");
}
?>



이 로그인 연동처리하는 코드는 http://www.coderzheaven.com/2012/04/22/create-simple-login-form-php-android-connect-php-android/ 자료를 참조했으나 부족한 사항들을 상당히 더 추가했다.

http://www.coderzheaven.com/ 사이트에 좋은 예제들이 많이 있다.

블로그 이미지

Link2Me

,
728x90

AsyncTask

- 클래스 하나에 Thread 와 Handler 의 기능이 콜백 메서드로 모두 존재


AsyncTask 클래스는 Thread 나 Looper 등의 작동 원리를 몰라도 하나의 클래스에서 UI 처리 및 Background 작업들을 쉽게 할 수 있도록 안드로이드에서 제공하는 클래스다.

이 클래스를 활용하면 작업을 백그라운드에서 수행할 수 있으며, 핸들러나 Thread 를 건들 필요 없이, 백그라운드에서 수행한 결과를 UI Thread(Main Thread) 로 보낼 수 있게 된다.

이렇게 백그라운드에서 수행되는 비 동기적인 작업은 세 가지 generic 타입 - Params, Progress, Result -

과 네 가지 스텝 - onPreExecute, doInBackground, onProgressUpdate, onPostExecute 으로 구성된다.


AsyncTask<Params, Progress, Result> 와 같이 제네릭 인수로  3가지 타입을 전달받는데 사용하지 않는 타입은 Void 라고 적으면 된다.

- Params : 실행할 전달한 인수의 타입. 즉 execute(..) 메소드의 파라미터를 통해 넘겨주는 값의 타입을 지정

- Progress : onProgressUpdate()가 호출될 때 넘겨받을 인자를 뜻한다.

- Result : 작업의 결과로 리턴될 타입 (onPostExecute()가 호출될 때넘겨받을 인자)



@Override

protected void onPreExecuted() { ... }

 //  Background 작업 시작전에 호출되며 UI 쓰레드에서 실행된다.

      계산을 위한 초기화나 프로그래스 대화상자 등의 작업을 수행한다

@Override

protected String doInBackground(Params... params)  { ... }  // 필수 메소드

 // background 작업을 수행하며 분리된 작업 쓰레드에서 실행된다.

     execute 메소드로 전달한 작업거리가 params 인수로 전달되는데 여러 개의 인수를 전달 할 수 있으므로 배열 타입으로 되어있다. 하나의 인수만 필요하다면 params[0] 만을 사용하면 된다.  (가변인자는 JDK 5.0 부터 지원)

작업중에 publishProgress 메소드르 호출하여 작업 경과를 UI Thread로 보고 할 수 있다.

그리고 최종 작업된 결과를 Result 타입으로 반환하며, 결과 값은 onPostExcute() 로 전달된다.

이 쓰레드 안에서 UI를 조작하면 에러가 발생한다.


@Override

 protected void onPostExecute(String result) { .... }

//이 메소드는 doInBackground() 메소드가 완료된 후에 호출된다.
// doInBackground() 메소드 작업의 결과가 return 되어 이 메소드에 전달된다.

// 여기에서 UI Thread 로 보낼 UI 조작을 할 수 있다.


AsyncTask를 사용해서 스케줄링 할 수 있는 작업 수의 제한이 있고, 몇 초 정도의 짧은 작업에서만 이상적으로 동작한다는 한계가 있다.
또한, 안드로이드의 버전별로 병렬 처리 동작이 다르므로 허니콤 이후 버전에서 멀티 스레드로 병렬적인 동작을 원한다면 AsyncTask를 실행할 때 AsyncTask.THREAD_POOL_EXECUTOR 스케줄러를 지정해야 한다.




(Example)


private class DownloadFiles extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {

         // Background 작업 진행상태 표시할 때 호출
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }



사용법

DownloadFiles asyncTask = new DownloadFiles();
asyncTask.execute();

한번에 쓰면
new DownloadFiles().execute();


하지만 cancel 처리도 발생하는 걸 고려한다면
new DownloadFiles().execute(); 로 사용하면 안된다.


DownloadFiles asyncTask = new DownloadFiles();

asyncTask.execute();

asyncTask.cancel(true);

로 해야 된다.


Android Studio 실제 코드 구현시에는 try catch 를 해주어야 에러메시지가 나오지 않는다.

try catch는 Alt + Enter 눌러서 해당 항목 선택해주면 자동으로 코드가 추가된다.



블로그 이미지

Link2Me

,
728x90

XML 방식으로 연동하기 위해서 구글링을 하고 테스트를 하고 적어둔다.

아직 ListView 처리 부분을 명확하게 이해하지 못해서 처리내역이 좀 어설퍼 보인다.


PHP 서버 파트는 http://link2me.tistory.com/1022 게시물을 참조하면 된다.

XML 데이터를 생성하는 부분도 추가해서 게시물을 보강했다.



XML 데이터 포멧은 위와 같다.


XML 데이터는 Local 에 있는 경우와 서버에 있는 경우 둘 다 테스트를 해봤다.

그래서 두가지 경우를 모두 하나의 파일로 만든 걸 적어둔다.



XML 파일은 res 폴더 하단에 만들어서 파일을 추가했다.

테스트에 사용한 파일 첨부

xml.zip


1. Activity_main.xml 파일 내용



2. person_item.xml 파일 작성



3. Person_Item.java 파일 생성


Person.java



4. 퍼미션 설정

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

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

AndroidManifest.xml 파일에서 퍼머션 추가


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myxml"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="19" />
   
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

     ...
</manifest>


5. MainActivity.java 파일 코드 추가


MainActivity.java


XmlPullParser 는 문서를 순차적으로 읽으며 이벤트를 발생시킨다.

START_DOCUMENT 이벤트는 문서의 시작을
END_DOCUMENT 은 문서의 끝을
START_TAG는 태그의 시작을 (예 : <uid> )
END_TAG는 태그의 끝을 (예 : </uid> )
TEXT는 태그의 시작과 끝 사이에서 나타난다. (예 : <uid>여기서 TEXT 이벤트 발생</uid> )


서버, Local 둘다 있는 코드


서버파일 접속 코드만 별도 발췌



Local 파일 접속 코드만 별도 발췌


ListView 모양을 처리하는 부분을 아직 제대로 이해하지 못해서 이 부분은 나중에 알게되면 추가 정리를 할 생각이다.

일단은 PHP 를 통해서 MySQL 데이터를 XML 형태로 안드로이드 단말에서 볼 수 있다는 것 자체에 의미를 두련다.

블로그 이미지

Link2Me

,
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

,
728x90

안드로이드에서 MySQL DB 에 직접 접속이 불가능하다.

웹을 통해서 DB 접속을 해야 하므로 PHP 를 통한 MySQL 접속을 한다.


1. MySQL DB 테이블 생성

CREATE TABLE IF NOT EXISTS `Person` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `mobile` varchar(16) NOT NULL,
  PRIMARY KEY (`uid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;


INSERT INTO `Person` (`uid`, `name`, `mobile`) VALUES
(1, '홍길동', '010-6123-0000'),
(2, '장정은', '010-0123-0001'),
(3, '김홍길', '010-0123-0002'),
(4, '최신형', '010-0123-0003'),
(5, '민들레', '010-0123-0004'),
(6, '김아정', '010-0123-0005'),
(7, '이순신', '010-0123-0006'),
(8, '이정민', '010-9999-8887');

위 테이블 구조를 phpMyAdmin 상에서 복사하여 붙여넣기하면 테이블이 만들어진다.

첨부파일 받아서 수정해서 사용해도 된다.


android_mysql_php.sql


MySQL DB 생성 방법을 모르면 http://link2me.tistory.com/431 참조

phpMyAdmin 사용법을 알고 싶다면 http://link2me.tistory.com/797 참조


※ 개인 PC에 설치해서 테스트 하는 경우에는 public IP 주소가 아니므로 스마트폰에서 인식을 못할 수 있음.


2. PHP 코드 작성

코드를 모듈화 해두면 코드가 간결해진다.

==== dbconnect.php ====

<?php
$db['host'] = "localhost";
$db['name'] = "address";
$db['user'] = "root";
$db['pass'] = "autoset";
$db['port'] = "3306";

$dbconn = isConnectDb($db);

function isConnectDb($db) {
    $conn = mysqli_connect($db['host'],$db['user'],$db['pass'],$db['name'],$db['port']);
    mysqli_set_charset($conn, "utf8");  // DB설정이 잘못되어 euc-kr 로 되어 있으면 문제가 됨
    if (mysqli_connect_errno()) {
        echo "Failed to connect to MySQL: " . mysqli_connect_error();
        exit;
    } else {
        return $conn;
    }
}
?>


==== get_json.php =====

<?php
@extract($_POST); // POST 전송으로 전달받은 값 처리
if(!(isset($idx) && !empty($idx))) { // 안드로이드에서 넘어온 변수 체크
    echo 0;
    exit;
}

require_once $_SERVER['DOCUMENT_ROOT'].'/dbconnect.php';
$sql = "select uid, name, mobile from Person ";

$R = array(); // 결과 담을 변수 생성
$result = mysqli_query($dbconn,$sql);
while($row = mysqli_fetch_object($result)) {
    array_push($R, $row); // 이 부분을 풀어서 처리하는 코드는 http://link2me.tistory.com/1275 참조
}
echo json_encode(array("result"=>$R));
?>


실행결과 Web 화면



PHP 초보자는 아래 작성된 내용은 안봐도 된다. 이런 방법도 있다는 걸 알고자 한다면 읽어도 좋다.


좀 더 세분화한 함수를 만들어서 연동 처리하는 방법도 가능하다.

==== get_xml.php =====

<?php
    include_once $_SERVER['DOCUMENT_ROOT'].'/_var/db.info.php';
    require_once $_SERVER['DOCUMENT_ROOT'].'/_app/phpclass/dbClass.php';
    require_once $_SERVER['DOCUMENT_ROOT'].'/_app/phpclass/xmlClass.php';

    $conn = new MySQLDbClass(); // DB 함수
    $dbconn = $conn->isConnectDb($db);

    $result = mysql_query('select uid,name,mobile from Person');

    // 1. XML 데이터 생성방법
    $c = new xmlcreateClass();
    $c->XML2View($result); // 화면출력
?>


class xmlcreateClass {

    // XML 데이터를 모니터 화면으로 출력
    // $c->XML2View($result); // XML 데이터 화면 출력
    function XML2View($result) {
        header('Content-type: text/xml');
        echo $this->exportAsXML($result);
    }


    // MySQL DB 자료를 column 개수, 게시물 총개수 만큼 자동으로 XML로 만들기
    function exportAsXML($result){
        $xml ='<?xml version="1.0" encoding="UTF-8" ?>'."\n";
        $xml.='<ListInfo>'."\n";
        while($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
            $xml.="<items>"."\n";

            // 여기에 테이블에 필요한 칼럼을 적어준다.

            // 능력이 되면 자동으로 칼럼을 생성처리하면 된다.

            $xml.="</items>"."\n";
        }
        $xml.='</ListInfo>';
        return $xml;
    }
}


3. PHP 코드에 사용된 함수 설명

KIMSQ RB의 코드를 Class 화하여 필요한 코드를 추가하거나 수정해서 사용함.


==== db.info.php ======

<?php
$db['host'] = "localhost";
$
db['name'] = "DB명"; // root
$
db['user'] = "db_user"; // DB 접속권한을 가진 User명
$
db['pass'] = "db_password";
$
db['port'] = "3306";
?>


==== dbClass.php =====

<?php
class MySQLDbClass {

    function isConnectDb($db)
    {
        $conn = mysqli_connect($db['host'],$db['user'],$db['pass'],$db['name'],$db['port']);
        mysqli_set_charset($conn, "utf8");  // DB설정이 잘못되어 euc-kr 로 되어 있으면 문제가 됨
        if (mysqli_connect_errno()) {
           echo "Failed to connect to MySQL: " . mysqli_connect_error();
           exit;
        } else {
          return $conn;  
        }
    }


    // DB Query result 함수

    function getDbresult($table,$where,$column) {
        global $db;
        $result = mysqli_query($db,'select '.$column.' from '.$table.($where?' where '.$this->getSqlFilter($where):''));
        return $result;
    }


    //SQL필터링
    function getSqlFilter($sql)
    {
        return $sql;
    }

}//end dbClass
?>


더 많은 코드는 KIMSQ RB 함수를 참조하여 응용해도 되고 Class 화하여 사용해도 된다.

MySQLi 를 사용하는 서버인 경우에는 코드를 수정할 부분이 있다.


$flddata ="uid, name, mobile"; // 화면에 출력할 칼럼 발췌
$where ='';
$result = $db->getDbresult('Person',$where,$flddata);


위 부분은 코드를 직관적으로 이해할 수 있도록 칼럼부분과 조건부분을 별도로 구분하여 처리했다.

테이블에 있는 모든 칼럼을 다 표시하는 * 보다는 출력하고픈 칼럼만 발췌하는 것이 속도면에서도 좋다.


만약 LIMIT 을 걸어서 테스트하고 싶다면 함수를 수정 보완하거나 그냥 간단하게

$result = mysql_query('select uid,name,mobile from Person LIMIT 3');

로 변경해서 테스트 해보면 된다.


함수로 만들어서 사용한다면

    function JSONEncode($result,$varname){
        $R = array(); // 결과 담을 변수 생성
        while($row = mysqli_fetch_object($result)) { 
            $R[] = $row;
        }
       
        return json_encode(array($varname=>$R));
    }



<?php
    include_once $_SERVER['DOCUMENT_ROOT'].'/db.info.php';
    require_once $_SERVER['DOCUMENT_ROOT'].'/phpclass/dbClass.php';
    require_once $_SERVER['DOCUMENT_ROOT'].'/phpclass/jsonClass.php';

    $conn = new MySQLDbClass(); // DB 함수
    $dbconn = $conn->isConnectDb($db);

    // 화면에 출력할 칼럼 발췌
    $result = mysqli_query($db, 'select uid,name,mobile from Person LIMIT 3');

    $c = new jsonClass();
    echo $c->JSONEncode($result,'result');
?>


JSON_Encode 형태로 만들어서 출력(echo)하면 안드로이드에서 PHP 출력화면 데이터를 인식하여 스마트폰 화면에서 볼 수 있다.


https://www.androidhive.info/2012/05/how-to-connect-android-with-php-mysql/ 를 참조해도 도움된다.


eclipse Android Code 부분은  다음 게시글 http://link2me.tistory.com/1020 을 참조하면 된다.

Android Studio Code 부분은 http://link2me.tistory.com/1230 를 추가로 보고 틀려진 부분을 확인하여 코드를 약간 수정하면 된다.

블로그 이미지

Link2Me

,