반응형

 안드로이드는 다른 플랫폼의 디스크 기반 파일시스템과 유사한 파일시스템을 사용합니다. 이번시간에는 File 클래스의 API를 사용하여 파일을 읽고 쓰기위한 안드로이드의 파일 시스템 작업방법을 소개하겠습니다.


 File 객체는 건너띄는 것 없이 처음부터 끝까지 순서대로 많은 양의 데이터를 읽고 쓰는데 적합합니다. 예를 들어, 이미지 파일이나 네트워크를 통해 변경되어지는 것들을 저장하는데 좋습니다.


 이번 시간에는 여러분의 앱에 기본 파일 관련 작업을 수행하기 위한 방법을 보여드리겠습니다. 이 포스트는 여러분이 기본적인 리눅스의 파일시스템과 java.io 패키지의 표준 파일 입/출력 API 알고 있는 것으로 가정하고 설명할 것입니다.


 

내부 또는 외부 저장장치 선택 (Choose Internal or External Storage)

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

 모든 안드로이드 단말기들은 두개의 파일 저장 영역을 가지고 있습니다. : "Internal" 과  "External" 저장장치

이 저장소의 이름들은 안드로이드 이전부터 만들어져 있던 것들입니다. 대부분의 단말기들은 내장되어 있는 비휘발성 메모리(내부 메모리Internal Storage)가 제공되어 있으며, 추가적으로 SD card(External Storage)와 같은 제거할 수있는(removable) 저장장치를 가지고 있습니다. 일부 단말기들은 "internal"과 "external" 파티션(partition)으로 영구 저장장치의 공간을 나누기도 합니다. 그래서 제거할수 있는 외부 저장소가 없더라도, 항상 두개의 공간을 가지게 됩니다. 그리고 API의 동작은 외부 저장소가 제거될 수 있든 아니든 상관없이 똑같이 동작합니다. 아래의 목록은 각각의 저장공간에 대한 특징을 요약한 것입니다.



내부 저장장치(Internal Storage)

° 이 장치는 항상 사용할 수 있습니다.

° 이곳에 저장된 파일을 기본적으로는 오직 여러분의 앱에 의해서만 접속할 수 있습니다.

°사용자가 여러분의 앱을 언인스톨(uninstall) 할 때, 시스템은 내부저장소로부터 앱의 파일들을 모두 제거합니다.


 내부 저장소는 사용자든 다른 앱들이든 여러분의 파일에 접속할 수 없도록 하고 싶을 때 사용하기 좋은 곳입니다.



외부 저장장치(External Storage)

° 이장치는 항상 사용할 수 는 없습니다. 왜냐하면 사용자가 USB 저장장치처럼 외부저장소를 마운트(mount)할 수도 잇고 어떤 경우에는 단말기에서 제거할 수도 있기 때문입니다.

° 이 장치는 기본적으로 world-readable 입니다. 그래서 이곳에 저장된 파일은 여러분의 제어 밖에서(동의없이) 읽어질 수도 있습니다.

° 사용자가 여러분의 앱을 언인스톨(uninstall)할 때, 시스템은 여러분이 getExternalFilesDir()로 만든 디렉토리에 파일을 저장했을 때만 자동으로 제거됩니다.


 외부 저장소는 파일의 접속 제한이 필요하지 않으며 다른 앱들이나 사용자가 컴퓨터를 사용하여 접속하도록 공유하고 싶을 때 사용하기 좋은 곳입니다.


Tip : 기본적으로 앱들은 내부 저장소(Internal Storage)에 인스톨(install)되지만, 메니페스트 안에 android:installLocation 속성을 통해 저장위치를 지정할 수 있습니다. 그래서 여러분의 앱이 외부 저장장치(External Storage)에 인스톨(install)되도록 할 수 있습니다. 사용자는 내부 저장소(Internal Storage) 보다 큰 외부 저장소(External Storage)를 가지고 있으며 APK(Android Package)의 용량이 매우 클 때 이 옵션의 진가를 느끼게 됩니다.




외부 저장장치에 대한 퍼미션 취득( Obtain Permissions for External Storage)

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

 외부 저장장치에 저장하기 위해서는 반드시 메니페스트 파일안에 WRITE_EXTERNAL_STORAGE 퍼미션을 요청해야만 합니다.

 <manifest ...>

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

    ...

</manifest>


Caution : 요즘은, 모든 앱들이 특별한 퍼미션없이도 읽을 수 있도록 되어 있습니다. 어쨋든, 이것은 나중에 새로운 버전이 나올 때 변경될 수도 있습니다. 만약 여러분의 앱이 외부 저장소를 읽을 필요가 있다면(저장은 하지 않고), 여러분은 READ_EXTERNAL_STORAGE퍼미션을 선언할 필요가 있을 겁니다. 여러분의 앱이 사용자가 기대한 작업을 지속적으로 하도록 하기 위해서는 나중에 변경되기 전에 이 퍼미션을 지금 선언하는 것이 좋습니다.

 <manifest ...>

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

    ...

</manifest>

  어쨋든, 만약 여러분의 앱이 WRITE_EXTERNAL_STORAGE 퍼미션을 사용한다면, 그것을 묵시적으로 외부 저장소에서 읽을 수도 있는 퍼미션을 받은 것으로 봅니다.


여러분이 내부 저장소에 파일을 저장할 때는 어떤 퍼미션도 필요하지 않습니다. 여러분의 어플은 항상 내부 저장소의 디렉토리를 읽고 쓸수 있는 퍼미션을 가지고 있습니다.

반응형
반응형

 만약 여러분이 저장하고자 하는 key-values 의 컬렉션(collection)이 비교적 작다면 여러분은 SharedPreference API 를 사용하시면 됩니다. SharedPreference 객체는 key-value 쌍을 포함하고 있는 파일을 나타내며 그것들을 읽고 쓰는 단수한 메소드를 제공합니다. 각 각의 SharedPreference 파일은 프레임워크(framework)에 의해 관리되며 프라이빗(private) 이거가 공유(Shared) 될 수 도 있습니다.


 이번 시간에는 여러분에게 단순한 값들을 저장하고 읽어오기 위해 SharedPreferences 를 사용하는 방법에 대해 보여드리고자 합니다.


 Note : SharedPreference API들은 오직 key-value 쌍을 읽고 쓰는 용도입니다. 여러분의 앱 설정(App Settings)에 대한 사용자 인터페이스를 만들때 사용하는 Preferences와 혼동하지 마세요(심지어 SharedPreference를 사용해서 앱 설정을 했다 하더라도).Preference API들에 대한 추가 정보를 원하시면 개발자사이트의 Settings 가이드를 참고하시기 바랍니다.


 

SharedPreference 핸들(Handle) 얻어오기 (Get a Handle to a SharedPreferences)

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

 여러분은 아래 두개의 메소드를 호출하여 새로운 Shared Preference를 만들거나 이미 존재하는 것에 연결할 수 있습니다.


° getSharedPreferences() - 만약 여러분이 첫번째 파라미터로 지정한 이름에 의해 식별이 되는 다중(여러개의 MultipleSharedPreference 파일을 만들 필요가 있다면 이것을 사용합니다. 여러분은 앱안의 어떤 Context에서든 이것을 호출할 수 있습니다.


° getPreferences() - 만약 액티비티에 대해 오직 한개의 Shared Preference 파일을 만들거라면 액티비티에서 이것을 사용합니다. 왜냐하면 이것은 액티비티에 소속되어 있는 기본 Shared Preference 파일을 주기때문입니다.  그래서 여러분은 이름은 제공할 필요가 없습니다.



 예를 들어보죠, 아래 코드는 Fragment 안에서 실행되어 집니다. 문자열 리소스 R.string.preference_file_key에 의해 식별되어진Shared Preferences 파일에 접속합니다. 그리고 private 모드로 열기 때문에 이 파일은 오직 여러분의 앱에서만 접속할 수 있습니다.

 Context context = getActivity();

 SharedPreferences sharedPref = context.getSharedPreferences(

        getString(R.string.preference_file_key), Context.MODE_PRIVATE);


 SharedPreference 파일의 이름을 지을 때, 여러붕은 "com.example.myapp.PREFERENCE_FILE_KEY" 와 같이 앱안에서 유일하게 식별되는 이름을 사용해야만 합니다.


 만약 여러분이 액티비티에 대해 오직 하나의 SharedPreference 파일만 필요하다면 위를 대신하여 getPreferences() 메소드를 사용할 수도 있습니다.

  SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);


 Caution : 만약 MODE_WORLD_READABLE 이나 MODE_WORLD_WRITEABLE 로 SharedPreferences 파일을 만들었다면, 식별자를 알고 있는 어떤 앱에서도 여러분의 데이터에 접속할 수 있게 됩니다.



Shared Preferences에 쓰기(Write to Shared Preferences)

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

 Shared Preferences 파일에 쓰기 위해서는, SharedPreferences 객체의 edit() 메소드를 호출함으로서SharedPreferences.Editor 객체를 만들어 내야 합니다.


 putInt()와 putString() 같은 메소드를 통해 여러분이 쓰고자 하는 키(key)와 값(value)들을 전달합니다. 그런다음, 변경 사항들을 저장하기 위해 commit() 메소드를 호출합니다. 예:


 SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);

 SharedPreferences.Editor editor = sharedPref.edit();

 editor.putInt(getString(R.string.saved_high_score), newHighScore);

 editor.commit();



SharedPreferences로부터 읽기(Read from Shard Preferences)

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

 Shared Preferences 파일에서 값을 가져오기 위해서는, getInt() getString()같은 메소드에 여러분의 원하는 값(value)의 키(key)를 제공하면 되고 선택적으로 혹시 제공한 key 값이 없다면 리턴될 기본 값을 부여합니다. 예:

 SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);

 int defaultValue = getResources().getInteger(R.string.saved_high_score_default);

 long highScore = sharedPref.getInt(getString(R.string.saved_high_score), defaultValue);


반응형
반응형

이전 Notification 에서 사운드와 진동을 추가하고 알림창을 클릭했을 때 새로운 액티비티로 전환되록 하여 알림의 세부내용을 확인하도록 하는 소스코드입니다.



버튼을 클릭하면 상태표시줄에 알림(Notification)이 발생하고 사운드와 진동(3초)이 발생합니다. 알림창을 확인(클릭)하면 새로운 액티비티로 전환하며 알림은 자동 삭제됩니다.

 


메인화면                                      알림 발생(상태표시줄)                  상태표시줄에 남아있는 알림 아이콘

    

  

 



상태바를 드래그하면 보이는 알림창      상태바를 클릭(알림 확인)               새로운 액티비티(ByNotificationActivity)

    





Layout 파일

 activity_main.xml

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    tools:context="${relativePackage}.${activityClass}" >


    <Button android:id="@+id/button"

        android:layout_width="match_parent"

        android:layout_height="50dp"

        android:text="generate Notification"

        android:onClick="mOnClick"/>


</RelativeLayout>


 



소스파일

 

 MainActivity.java

public class MainActivity extends Activity {


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

//Button을 클릭했을 때 자동으로 호출되는 callback method....

public void mOnClick(View v){

switch( v.getId() ){

case R.id.button:

//알림(Notification)을 관리하는 NotificationManager 얻어오기

NotificationManager manager= (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

//알림(Notification)을 만들어내는 Builder 객체 생성

//만약 minimum SDK가 API 11 이상이면 Notification 클래스 사용 가능

//한번에 여러개의 속성 설정 가능

NotificationCompat.Builder builder= new NotificationCompat.Builder(this)

.setSmallIcon(android.R.drawable.ic_dialog_alert)  //상태표시줄에 보이는 아이콘 모양

.setTicker("Notify")                                     //알림이 발생될 때 잠시 보이는 글씨

.setContentText("Title")                                //알림창에서의 제목

.setContentText("Contents");                          //알림창에서의 글씨

//상태바를 드래그하여 아래로 내리면 보이는 알림창(확장 상태바)의 아이콘 모양 지정

builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), android.R.drawable.ic_dialog_info));

//알림에 사운드 기능 추가

Uri soundUri= RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_NOTIFICATION);

builder.setSound(soundUri);

//알림에 진동 기능 추가 

//진동 추가시에는 AndroidManifest 파일에 uses-permission 을 통해 사용권한 받아야함  "android.permission.VIBRATE"

builder.setVibrate(new long[]{0,3000}); // pattern의 첫번째 파라미터는 wait시간, 두번째는 진동시간(단위 ms)

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

//알림을 확인했을 때(알림창 클릭) 다른 액티비티(ByNitificationActivity) 실행

//클릭했을 때 시작할 액티비티에게 전달하는 Intent 객체 생성

Intent intent= new Intent(this, ByNotificationActivity.class);

//클릭할 때까지 액티비티 실행을 보류하고 있는 PendingIntent 객체 생성

PendingIntent pending= PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);

builder.setContentIntent(pending);   //PendingIntent 설정 

builder.setAutoCancel(true);         //클릭하면 자동으로 알림 삭제

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

Notification notification= builder.build();    //Notification 객체 생성

manager.notify(0, notification);    //NotificationManager가 알림(Notification)을 표시, id는 알림구분용           

break;

}

}

}

   




두번째 액티비티의 소스파일과 레이아웃파일


 ByNotificationActivity.java

 activity_by_notification.xml

 public class ByNotificationActivity extends Activity {


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_by_notification);

}

}




 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    tools:context="${relativePackage}.${activityClass}" >


    <TextView

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="The Activity by Notification" />


</RelativeLayout>



네트워크 사용하기 위해서는 사용 권한(uses-permission)이 필요합니다.

여러분 프로젝트의 메니페스트 파일에 퍼미션을 추가합니다.


 AndroidManifest.xml

 <manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.kitesoft.notification"

    android:versionCode="1"

    android:versionName="1.0" >


    <uses-sdk

        android:minSdkVersion="11"

        android:targetSdkVersion="19" />


    <!-- 진동사용 허가 -->

    <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=".MainActivity"

            android:label="@string/app_name" >

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />


                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

        <activity

            android:name=".ByNotificationActivity"

            android:label="@string/title_activity_by_notification" >

        </activity>

    </application>


</manifest>

 

반응형
반응형

 버튼을 클릭하면 상태표시줄에 알림(Notification)이 발생하는 소스코드입니다.


메인화면                                     알림 발생(상태표시줄)                  상태표시줄에 남아있는 알림 아이콘

    


상태바를 드래그하면 보이는 알림창(확장상태바)             상태바의 지우기 버튼을 누르면 알림이 삭제됨

             




Layout 파일

 activity_main.xml

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    tools:context="${relativePackage}.${activityClass}" >


    <Button android:id="@+id/button"

        android:layout_width="match_parent"

        android:layout_height="50dp"

        android:text="generate Notification"

        android:onClick="mOnClick"/>


</RelativeLayout>


 



소스파일

 

 MainActivity.java

public class MainActivity extends Activity {


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

//Button을 클릭했을 때 자동으로 호출되는 callback method....

public void mOnClick(View v){

switch( v.getId() ){

case R.id.button:

//알림(Notification)을 관리하는 NotificationManager 얻어오기

NotificationManager manager= (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

//알림(Notification)을 만들어내는 Builder 객체 생성

//API 11 버전 이하도 지원하기 위해 NotificationCampat 클래스 사용

//만약 minimum SDK가 API 11 이상이면 Notification 클래스 사용 가능 

NotificationCompat.Builder builder= new NotificationCompat.Builder(this);

//Notification.Builder에게 Notification 제목, 내용, 이미지 등을 설정//////////////////////////////////////


 builder.setSmallIcon(android.R.drawable.ic_dialog_email);//상태표시줄에 보이는 아이콘 모양

builder.setTicker("Notification"); //알림이 발생될 때 잠시 보이는 글씨


//상태바를 드래그하여 아래로 내리면 보이는 알림창(확장 상태바)의 아이콘 모양 지정

builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), android.R.drawable.ic_input_add));

builder.setContentTitle("Contents Title");    //알림창에서의 제목

builder.setContentText("Contents TEXT");   //알림창에서의 글씨


///////////////////////////////////////////////////////////////////////////////////////////////////////

Notification notification= builder.build();   //Notification 객체 생성

manager.notify(1, notification);             //NotificationManager가 알림(Notification)을 표시

break;

}

}

}

   

반응형
반응형

 네이버에서 제공하는 오픈 API 를 파싱해서 단순하게 텍스트뷰(TextView)에 출력하는 소스 코드입니다.


XmlPullParser 를 이용한 파싱 입니다. 


네이버 검색 오픈 API중에 '지역' 검색을 하는 예제 소스입니다. 

네이버 개발자센터에서 검색키를 발급받으셔야 합니다. 검색키 발급방법은 다른 포스트를 참고하시기 바랍니다.

 



메인화면                                                                   검색값 입력(스타벅스)  

                




네이버 XML data 문자열로 출력 ( Scrolling 가능 )

               





Layout 파일

 activity_main.xml

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:orientation="vertical"

    android:padding="10dp">

    

    <LinearLayout 

        android:layout_width="match_parent"

        android:layout_height="50dp"

        android:orientation="horizontal"

        android:weightSum="10">

        

        <EditText android:id="@+id/edit"

        android:layout_width="0dp"

        android:layout_height="match_parent"

        android:layout_weight="8"

        android:textSize="12sp"

        android:hint="enter text to search"/>

    

    <Button android:id="@+id/button"

        android:layout_width="0dp"

        android:layout_height="match_parent"

        android:layout_weight="2"

        android:text="search"

        android:textSize="12sp"

        android:onClick="mOnClick"/>

        

    </LinearLayout>    

    

    <ScrollView 

        android:layout_width="match_parent"

        android:layout_height="match_parent">

    

        <TextView android:id="@+id/text"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:textSize="8sp"        

        android:textStyle="bold"/>

        

    </ScrollView>     


</LinearLayout>






소스파일

 

 MainActivity.java

public class MainActivity extends Activity {

EditText edit;

TextView text;

XmlPullParser xpp;

String key=" 본인의 개발자 검색 키 "//Naver 개발자센터 검색 키

String data;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

edit= (EditText)findViewById(R.id.edit);

text= (TextView)findViewById(R.id.text);

}

//Button을 클릭했을 때 자동으로 호출되는 callback method....

public void mOnClick(View v){

switch( v.getId() ){

case R.id.button:

//Android 4.0 이상 부터는 네트워크를 이용할 때 반드시 Thread 사용해야 함

new Thread(new Runnable() {

@Override

public void run() {

// TODO Auto-generated method stub

data= getXmlData(); //아래 메소드를 호출하여 XML data를 파싱해서 String 객체로 얻어오기

//UI Thread(Main Thread)를 제외한 어떤 Thread도 화면을 변경할 수 없기때문에

//runOnUiThread()를 이용하여 UI Thread가 TextView 글씨 변경하도록 함

runOnUiThread(new Runnable() {

@Override

public void run() {

// TODO Auto-generated method stub

text.setText(data);  //TextView에 문자열  data 출력

}

});

}

}).start();

break;

}

}//mOnClick method..

//XmlPullParser를 이용하여 Naver 에서 제공하는 OpenAPI XML 파일 파싱하기(parsing)

String getXmlData(){

StringBuffer buffer=new StringBuffer();

String str= edit.getText().toString(); //EditText에 작성된 Text얻어오기

String location = URLEncoder.encode(str); //한글의 경우 인식이 안되기에 utf-8 방식으로 encoding..

String queryUrl="http://openapi.naver.com/search"   //요청 URL

   +"?key="+key                        //key 값

   +"&target=local"                     //검색서비스 api명세

   +"&query="+location                 //지역검색 요청값

   +"&display=10"                      //검색 출력 건수  10~100

   +"&start=1";                         //검색 시작 위치  1~1000

try {

URL url= new URL(queryUrl); //문자열로 된 요청 url을 URL 객체로 생성.

InputStream is= url.openStream();  //url위치로 입력스트림 연결

XmlPullParserFactory factory= XmlPullParserFactory.newInstance();

XmlPullParser xpp= factory.newPullParser();

xpp.setInput( new InputStreamReader(is, "UTF-8") );  //inputstream 으로부터 xml 입력받기

String tag;

xpp.next();

int eventType= xpp.getEventType();

while( eventType != XmlPullParser.END_DOCUMENT ){

switch( eventType ){

case XmlPullParser.START_DOCUMENT:

buffer.append("start NAVER XML parsing...\n\n");

break;

case XmlPullParser.START_TAG:

tag= xpp.getName();    //테그 이름 얻어오기

if(tag.equals("item")) ;// 첫번째 검색결과

else if(tag.equals("title")){

buffer.append("업소명 : ");

xpp.next();

buffer.append(xpp.getText()); //title 요소의 TEXT 읽어와서 문자열버퍼에 추가 

buffer.append("\n");          //줄바꿈 문자 추가

}

else if(tag.equals("category")){

buffer.append("업종 : ");

xpp.next();

buffer.append(xpp.getText()); //category 요소의 TEXT 읽어와서 문자열버퍼에 추가 

buffer.append("\n");          //줄바꿈 문자 추가

}

else if(tag.equals("description")){

buffer.append("세부설명 :");

xpp.next();

buffer.append(xpp.getText()); //description 요소의 TEXT 읽어와서 문자열버퍼에 추가 

buffer.append("\n");          //줄바꿈 문자 추가

}

else if(tag.equals("telephone")){

buffer.append("연락처 :");

xpp.next();

buffer.append(xpp.getText()); //telephone 요소의 TEXT 읽어와서 문자열버퍼에 추가 

buffer.append("\n");          //줄바꿈 문자 추가

}

else if(tag.equals("address")){

buffer.append("주소 :");

xpp.next();

buffer.append(xpp.getText()); //address 요소의 TEXT 읽어와서 문자열버퍼에 추가 

buffer.append("\n");          //줄바꿈 문자 추가

}

else if(tag.equals("mapx")){

buffer.append("지도 위치 X :");

xpp.next();

buffer.append(xpp.getText()); //mapx 요소의 TEXT 읽어와서 문자열버퍼에 추가 

buffer.append("  ,  ");          //줄바꿈 문자 추가

}

else if(tag.equals("mapy")){

buffer.append("지도 위치 Y :");

xpp.next();

buffer.append(xpp.getText()); //mapy 요소의 TEXT 읽어와서 문자열버퍼에 추가 

buffer.append("\n");          //줄바꿈 문자 추가

}

break;

case XmlPullParser.TEXT:

break;

case XmlPullParser.END_TAG:

tag= xpp.getName();    //테그 이름 얻어오기

if(tag.equals("item")) buffer.append("\n"); // 첫번째 검색결과종료..줄바꿈

break;

}

eventType= xpp.next();

}

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

buffer.append("end NAVER XML parsing...\n");

return buffer.toString(); //StringBuffer 문자열 객체 반환

}//getXmlData method....

}//MainActivity class..

  



 네트워크 사용하기 위해서는 사용 권한(uses-permission)이 필요합니다.

여러분 프로젝트의 메니페스트 파일에 퍼미션을 추가합니다.


 AndroidManifest.xml

 <manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.kitesoft.xmlpullparsernaver"

    android:versionCode="1"

    android:versionName="1.0" >


    <uses-sdk

        android:minSdkVersion="8"

        android:targetSdkVersion="19"/>


    <!-- 네트워크 사용허가 요청  -->

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


    <application

        android:allowBackup="true"

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"

        android:theme="@style/AppTheme" >

        <activity

            android:name=".MainActivity"

            android:label="@string/app_name" >

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />


                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

    </application>


</manifest>


 

반응형
반응형

res 폴더에 있는 XML 파일을 파싱(parsing)하는 소스코드 입니다.


XmlResourceParser 를 이용한 파싱 입니다.



  

메인화면                                                           res폴더의 XML data 읽기

            




XML data 파일 ( res/xml/movies.xml )

 movies.xml

 저장 위치
 

 <?xml version="1.0" encoding="UTF-8"?>

<Movie>

    <Title>

        Alien

        <Genre>

            SF, action, advanture

        </Genre>        

    </Title>

    

    <Title>

        avatar

        <Genre>

            SF, action, advanture

        </Genre>        

    </Title>

    

    <Title>

        Notting Hill

        <Genre>

            romance, melo

        </Genre>        

    </Title>

    

    <Title>

        Nightmare

        <Genre>

            horror, thriller

        </Genre>        

    </Title>    

    

</Movie>


 





Layout 파일

 activity_main.xml

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

    

    <EditText android:id="@+id/edit"

        android:layout_width="match_parent"

        android:layout_height="50dp"

        android:padding="5dp"

        android:inputType="text"

        android:hint="input text"/>

    

    <Button android:id="@+id/btn_save"

        android:layout_width="match_parent"

        android:layout_height="50dp"

        android:text="save file into External(SDcard)"

        android:onClick="mOnClick"/>

    

    <Button android:id="@+id/btn_load"

        android:layout_width="match_parent"

        android:layout_height="50dp"

        android:text="load file from External(SDcard)"

        android:onClick="mOnClick"/>

    

    <TextView android:id="@+id/text"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:padding="5dp"

        android:text="Show data from file"/>


</LinearLayout>





소스파일

 

 MainActivity.java

 public class MainActivity extends Activity {

XmlResourceParser xrp;

TextView text;


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

text= (TextView)findViewById(R.id.text);

}

//Button을 클릭했을 때 자동으로 호출되는 callback method....

public void mOnClick(View v){

switch( v.getId() ){

case R.id.button:

Resources res= getResources(); //res 폴더 관리자(Resources 객체) 얻어오기

xrp= res.getXml(R.xml.movies); //XmlResourcesParser 얻어오기

String data= getXmlData(); //아래 메소드를 호출하여 XML data를 파싱해서 String 객체로 얻어오기

text.setText(data);    //TextView에 문자열  data 출력

break;

}

}//mOnClick method..

//XmlResourceParser를 이용하여 res/xml 폴더에 있는 movies.xml 파일 파싱하기(parsing)

String getXmlData(){

StringBuffer buffer=new StringBuffer();

String name;

String text;

try {

xrp.next();

int eventType= xrp.getEventType(); //XML의 이벤트 타입 얻어오기..

while( eventType != XmlResourceParser.END_DOCUMENT ){

// XmlResourceParser의 5가지 이벤트 타입

switch( eventType){

case XmlResourceParser.START_DOCUMENT:

buffer.append("Start XML Parsing ......\n\n");

break;

case XmlResourceParser.START_TAG:

name= xrp.getName();

if(name.equals("Movie")) buffer.append("--Movie List Start--\n\n");

else if(name.equals("Title")) buffer.append("Title : ");

else if(name.equals("Genre")) buffer.append("Genre : ");

break;

case XmlResourceParser.TEXT:

buffer.append(xrp.getText());

break;

case XmlResourceParser.END_TAG:

name= xrp.getName();

if(name.equals("Movie")) buffer.append("--Movie List End--\n");

else if(name.equals("Title")) buffer.append("\n");

break;

case XmlResourceParser.END_DOCUMENT:

break;

}

eventType= xrp.next(); //다음 이벤트타입 얻어오기

}//while

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

buffer.append("\n End XML Parsing ......");

return buffer.toString(); //StringBuffer 문자열 객체 반환

}//getXmlData method....

}//MainActivity class..

 









반응형
반응형

EditText 에 입력한 글씨를 외부 메모리(Internal Storage) 즉, SDcard에 저장하고 다시 읽어오는 소스입니다.


먼저, 여러분의 테스터 단말기(실제 스마트폰 또는 에뮬레이터)에 SDcard가 있는지 확인하시기 바랍니다.




메인화면                                        SDcard에 저장                               SDcard에서 읽어오기

          


Layout 파일

 activity_main.xml

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

    

    <EditText android:id="@+id/edit"

        android:layout_width="match_parent"

        android:layout_height="50dp"

        android:padding="5dp"

        android:inputType="text"

        android:hint="input text"/>

    

    <Button android:id="@+id/btn_save"

        android:layout_width="match_parent"

        android:layout_height="50dp"

        android:text="save file into External(SDcard)"

        android:onClick="mOnClick"/>

    

    <Button android:id="@+id/btn_load"

        android:layout_width="match_parent"

        android:layout_height="50dp"

        android:text="load file from External(SDcard)"

        android:onClick="mOnClick"/>

    

    <TextView android:id="@+id/text"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:padding="5dp"

        android:text="Show data from file"/>


</LinearLayout>



소스파일

 

 MainActivity.java

 public class MainActivity extends Activity {

EditText edit;

TextView text;


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

edit= (EditText)findViewById(R.id.edit);

text= (TextView)findViewById(R.id.text); 

}

//Button을 클릭했을 때 자동으로 호출되는 callback method....

public void mOnClick(View v){

String state= Environment.getExternalStorageState(); //외부저장소(SDcard)의 상태 얻어오기

File path;    //저장 데이터가 존재하는 디렉토리경로

File file;     //파일명까지 포함한 경로

switch(v.getId()){

case R.id.btn_save:  //External Storage(SDcard)에 file 저장하기

if(!state.equals(Environment.MEDIA_MOUNTED)){ // SDcard 의 상태가 쓰기 가능한 상태로 마운트되었는지 확인

Toast.makeText(this, "SDcard Not Mounted", Toast.LENGTH_SHORT).show();

return;

}

String data= edit.getText().toString();  //EditText의 Text 얻어오기

//SDcard에 데이터 종류(Type)에 따라 자동으로 분류된 저장 폴더 경로선택

//Environment.DIRECTORY_DOWNLOADS : 사용자에의해 다운로드가 된 파일들이 놓여지는 표준 저장소

path= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);

file= new File(path, "Data.txt"); //파일명까지 포함함 경로의 File 객체 생성

try {

//데이터 추가가 가능한 파일 작성자(FileWriter 객체생성)

FileWriter wr= new FileWriter(file,true); //두번째 파라미터 true: 기존파일에 추가할지 여부를 나타냅니다.

PrintWriter writer= new PrintWriter(wr); 

writer.println(data);

writer.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

//소프트 키보드 없애기

InputMethodManager imm= (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);

imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);

break;

case R.id.btn_load:  //External Storage(SDcard)에서 file 읽어오기

// SDcard 의 상태가 읽기/쓰기가 가능하거나 또는 읽기만 가능한 상태로 마운트되었는지 확인

if( !(state.equals(Environment.MEDIA_MOUNTED) || state.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) ){

Toast.makeText(this, "SDcard Not Mounted", Toast.LENGTH_SHORT).show();

return;

}

StringBuffer buffer= new StringBuffer();

path= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);

file= new File(path, "Data.txt");

try {

FileReader in= new FileReader(file);

BufferedReader reader= new BufferedReader(in);

String str= reader.readLine();

while( str!=null ){

buffer.append(str+"\n");

str= reader.readLine();//한 줄씩 읽어오기

}

text.setText(buffer.toString());

reader.close();

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

break;

}

}

}

 



 외부 저장소를 사용하기 위해서는 사용 권한(uses-permission)이 필요합니다.

여러분 프로젝트의 메니페스트 파일에 퍼미션을 추가합니다.


 AndroidManifest.xml

 <manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.kitesoft.externalstorage"

    android:versionCode="1"

    android:versionName="1.0" >


    <uses-sdk

        android:minSdkVersion="8"

        android:targetSdkVersion="19" />

    

    <!-- 외부저장소(SDcard) 사용허가 요청  -->

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


    <application

        android:allowBackup="true"

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"

        android:theme="@style/AppTheme" >

        <activity

            android:name=".MainActivity"

            android:label="@string/app_name" >

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />


                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

    </application>


</manifest>






저장된 위치 확인

(Eclipse 에서 DDMS의 mnt/sdcard/Download/)

- 외부 메모리(SDcard)에 위치해 있기 때문에 앱을 제거해도 파일은 여전히 남아있게 됩니다.





Tip. 사용자가 원하는 디렉토리에 저장하기

 기본 SDcard의 디렉토리가 아닌 사용자가 원하는 디렉토리를 사용하고 싶다면 아래 코드로 디렉토리 pah를 만드시면 됩니다.

 //SDcard의 절대 경로 얻어오기( /mnt/sdcard )

 String absolutePath= Environment.getExternalStorageDirectory().getAbsolutePath();

 // 커스텀 디렉토리로서 "/custDir" 디렉토리 추가  ( /mnt/sdcard/custDir/ )

 String newPath= absolutePath+"/custDir";

 File path= new File(newPath); //새로운 디렉토리로 File 객체 생성

 if( !path.exists() ) path.mkdir(); //만약 처음 디렉토리를 만들면 존재하지 않기때문에 디렉토리를 생성( make Directory )

  .......



사용자 정의 디렉토리 사용시 저장 위치( /mnt/sdcard/custDir/ )




























반응형
반응형

 EditText 에 입력한 글씨를 내부 메모리(Internal Storage)에 저장하고 다시 읽어오는 소스입니다.



메인화면                                       내부메모리에 저장                            내부메모리에서 읽어오기

         



Layout 파일

 activity_main.xml

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

    

    <EditText android:id="@+id/edit"

        android:layout_width="match_parent"

        android:layout_height="50dp"

        android:padding="5dp"

        android:inputType="text"

        android:hint="input text"/>

    

    <Button android:id="@+id/btn_save"

        android:layout_width="match_parent"

        android:layout_height="50dp"

        android:text="save file into Internal"

        android:onClick="mOnClick"/>

    

    <Button android:id="@+id/btn_load"

        android:layout_width="match_parent"

        android:layout_height="50dp"

        android:text="load file from Internal"

        android:onClick="mOnClick"/>

    

    <TextView android:id="@+id/text"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:padding="5dp"

        android:text="Show data from file"/>


</LinearLayout>



소스파일

 

 MainActivity.java

 public class MainActivity extends Activity {

EditText edit;

TextView text;


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

edit= (EditText)findViewById(R.id.edit);

text= (TextView)findViewById(R.id.text); 

}

//Button을 클릭했을 때 자동으로 호출되는 callback method....

public void mOnClick(View v){

switch(v.getId()){

case R.id.btn_save: //Internal Storage에 file 저장하기

String data= edit.getText().toString(); //EditText에서 Text 얻어오기

edit.setText("");

try {

//FileOutputStream 객체생성, 파일명 "data.txt", 새로운 텍스트 추가하기 모드

FileOutputStream fos=openFileOutput("data.txt", Context.MODE_APPEND); 

PrintWriter writer= new PrintWriter(fos);

writer.println(data);

writer.close();

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

//소프트 키보드 없애기

InputMethodManager imm= (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);

imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);

break;

case R.id.btn_load: //file 에서 읽어오기

StringBuffer buffer= new StringBuffer();

try {

//FileInputStream 객체생성, 파일명 "data.txt"

FileInputStream fis=openFileInput("data.txt");

BufferedReader reader= new BufferedReader(new InputStreamReader(fis));

String str=reader.readLine();//한 줄씩 읽어오기

while(str!=null){

buffer.append(str+"\n");

str=reader.readLine();

}

text.setText(buffer.toString());

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

break;

}

}

}



 

저장된 위치 확인 (Eclipse 에서 DDMS의 본인 앱위치)

- 본인의 앱 폴더 안에 있으므로 앱을 제거하면 파일도 같이  제거됩니다.











반응형
반응형

 오직 onPause()가 되는 동안 앱의 상태에 대한 정보만을 저장하더라도 대부분의 안드로이드 앱들은 데이터를 저장할 필요가 있습니다. 그렇기에 사용자의 프로세스를 잃어버리지 않습니다. 대부분의 적지않은 앱들 역시 사용자의 설정을 저장할 필요가 있으며 일부 앱들은 파일(file)과 데이터베이스(Database)안에 많은 양의 정보를 관리해야만 합니다. 이번 시간에는 여러분에게 안드로이드 안에 있는 주요한 데이터 저장 옵션에 대해 소개하고자 합니다.


 ° Shared Preferences 파일(file)안에 key-value 쌍으로 간단한 데이터 타입들 저장하기

 ° Android의 파일(file) 시스템안에 임의의 파일들 저장하기

 ° SQLite의 의한 관리되는 데이터베이스 사용하기




Lessons

--------

Key - Value 세트로 저장하기

 key- value 쌍안에 작은양의 정보를 저장하도록 하는 Shared Preferences 파일(file)을 사용하는 방법을 학습합니다. 


File 저장하기

 일반적으로 순서대로 읽어지는 긴 데이터를 순차적으로 저장하는 것과 같이, 기본적인 파일 저장에 대해 학습합니다.


SQL Database 저장하기

 구조화된 데이터를 읽고 쓰기 위한 SQLite database의 사용에 대해 학습합니다.

반응형
반응형

 프레그먼트 UI 컴포넌트들(components)을 재사용하기 위해서는, 프레그먼트 자신의 레이아웃과 동작을 정의한 완전히 독립적인 모듈로서 구성요소를 만들어야 합니다. 이렇게 프레그먼트를 재사용하도록 정의하면, 액티비티와 프레그먼트들을 조합할 수 있으며 전체적으로 복합 UI를 실현하기 위한 어플리케이션 로직을 가지고 프레그먼트들을 연결할 수 있습니다.


 종종 여러분은 다른 것들과 커뮤니케이션을 하는 프레그먼트를 원할 수도 있습니다. 사용자의 이벤트를 기반으로 내용을 변경하는 경우가 있을 수 있게죠. 모든 프레그먼트 대 프레그먼트(fragment-to-fragment) 간의 통신(communication)은 액티비티와의 조합을 통해서 이루어 집니다. 두개의 프레그먼트들은 절대로 다이렉트로 통신을 할 수 없습니다.



인터페이스 정의 (Define an Interface)

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

 프레그먼트가 액티비티와 통신을 하도록 하기 위해, 여러분은 프레그먼트 안에 인터페이스를 정의할 수 있으며 액티비티안에도 그것을 구현할 수 있습니다. 프레그먼트는 본인의 라이프사이클(lifecycle) 메소드인 onAttach() 에서 인터페이스(interface)을 붙잡도록 구현합니다. 그리고 액티비티와 통신하기 위해 인터페이스 메소드를 호출할 수 있습니다.


 아래는 액티비티에게 통신을 하는 프레그먼트의 예제입니다.

 public class HeadlinesFragment extends ListFragment {

    OnHeadlineSelectedListener mCallback;


    // Container Activity must implement this interface

    public interface OnHeadlineSelectedListener {

        public void onArticleSelected(int position);

    }


    @Override

    public void onAttach(Activity activity) {

        super.onAttach(activity);

        

        // This makes sure that the container activity has implemented

        // the callback interface. If not, it throws an exception

        try {

            mCallback = (OnHeadlineSelectedListener) activity;

        } catch (ClassCastException e) {

            throw new ClassCastException(activity.toString()

                    + " must implement OnHeadlineSelectedListener");

        }

    }

    

    ...

}

 

 이제 프레그먼트는 OnHeadlineselectedListener 인터페이스인 mCallback 인스턴스(instance)를 사용하여onAriticleSelected() 메소드를( 또은 인터페이스안에 있는 다른 메소드들) 호출함으로서 액티비티에게 메세지를 전달할 수 있습니다.


 예들들어, 프레그먼트안에 있는 아래의 메소드는 사용자가 list 아이템을 클릭했을 때 호출됩니다. 프레그먼트는 부모 액티비티에게 이벤트를 전달하기 위해 callback 인터페이스를 사용합니다.

  @Override

    public void onListItemClick(ListView l, View v, int position, long id) {

        // Send the event to the host activity

        mCallback.onArticleSelected(position);

    }




인터페이스 구현 ( implement the Interface )

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

프레그먼트로 부터 콜백(callback) 이벤트를 받기 위해서, 호스트 액티비티는 반드시 프레그먼트 클래스 안에 정의되어 있는 인터페이스를 구현해야만 합니다.


 예를 들어, 아래 액티비티는 위의 예제에 있는 인터페이스를 구현한 것입니다.

 public static class MainActivity extends Activity

        implements HeadlinesFragment.OnHeadlineSelectedListener{

    ...

    

    public void onArticleSelected(int position) {

        // The user selected the headline of an article from the HeadlinesFragment

        // Do something here to display that article

    }

}




프레그먼트에게 메세지 전달하기

( Deliver a Message to a Fragment )

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

 호스트(host) 액티비티는 findFragmentById()를 통해 프레그먼트(Fragment) 인스턴스(instance)를 참조함으로서 프레그먼트에게 메세지를 전달할 수 있습니다. 그런다음, 직접적으로 프레그먼트의 public 메소드들을 호출합니다.


 액티비티가 위의 콜백(callback) 메소드안에 리턴된(returned) 데이터에 의해 쓰여진 아이템을 보여주기 위해 사용되어지는 또 다른 프레그먼트가 포함되어 있다고 생각해 보겠습니다. 이런 경우, 액티비티는 아이템을 보여주기 위한 다른 액티비티에게 콜백메소드안에 받았던 정보를 전달할 수 있습니다.


 public static class MainActivity extends Activity

        implements HeadlinesFragment.OnHeadlineSelectedListener{

    ...


    public void onArticleSelected(int position) {

        // The user selected the headline of an article from the HeadlinesFragment

        // Do something here to display that article


        ArticleFragment articleFrag = (ArticleFragment)

                getSupportFragmentManager().findFragmentById(R.id.article_fragment);


        if (articleFrag != null) {

            // If article frag is available, we're in two-pane layout...


            // Call a method in the ArticleFragment to update its content

            articleFrag.updateArticleView(position);

        } else {

            // Otherwise, we're in the one-pane layout and must swap frags...


            // Create fragment and give it an argument for the selected article

            ArticleFragment newFragment = new ArticleFragment();

            Bundle args = new Bundle();

            args.putInt(ArticleFragment.ARG_POSITION, position);

            newFragment.setArguments(args);

        

            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();


            // Replace whatever is in the fragment_container view with this fragment,

            // and add the transaction to the back stack so the user can navigate back

            transaction.replace(R.id.fragment_container, newFragment);

            transaction.addToBackStack(null);


            // Commit the transaction

            transaction.commit();

        }

    }

}


반응형

+ Recent posts