요즘 Android NDK를 사용해서 JNI를 사용한 개발을 하고 있는중인데, eclipse가 Java만 지원하는 줄 알고.. 정말 불편하게 java코드는 eclipse에서 개발하고, cpp JNI코드는 vi 에디터로 개발하는 정말 힘들고 불편한 시간을 보내고 있었다.


그래서 무슨 좋은 방법이 있을것 같은데 하고 찾아봤더니...

훌륭하신 선구자님들이... CDT를 만들어두셨다.. eclipse에서 C개발환경을 제공..한다.. 크흑... 


1. Help -> Install New Software 에서 CDT를 설치하기 위해 site 추가




2. 플러그인들 선택하기~~ 다해버리자... 뭔지 모르지만 언제 쓰일지 모른다.!!!




3. 설치하고나면 eclipse를 restart할래요?? 라고 물어본다. 그러고 재시작해보면...



이제 JNI를 제대로 만드는 일만 남았다...!!!!


블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,

안드로이드가 처음 나왔을때, 개발환경을 설치하는것에 대한 설명을 하는 책이 나왔었다.

그때 대부분의 개발자들이 안드로이드 개발환경을 어떻게 설치하는지 developer사이트를 읽고, 책을 읽고 .. 심지어는 개발환경을 설치해주는 DVD를 만들어서 관리하고 있는 곳도 있었다..


그런데 오랜만에 컴퓨터에 eclipse가 계속 죽고, NDK를 이용해서  프로젝트를 개발하려다가 SDK업데이트나 할까 하고 들어가본 사이트에서.. 두둥!!!

http://developer.android.com/sdk/index.html#download




이거 설치하고나니 한방에 다 된다....헐쓰..

다 필요 없이 저거 하나 설치하고 나면 됨!!!!


이제 개발하기가 마우스 클릭 몇번으로 되는 세상이 곧 올것 같다.. 

나같은 개발자는 더이상 먹고 살기 힘들어지는 걸까....

블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,

안드로이드 어플을 개발하다보면, DataBase를 사용해야 하는 경우가 간혹있다. 우리가 많이 사용하는 전화번호부, 일정관리 어플, 메시지 프로그램들이 모두가 DB를 자체적으로 사용하고 있는 것들이다.


안드로이드는 프레임웍에서 SQLite를 사용하기 쉽게 제공하고 있다. 그래서 오늘은 정말 정말 정말, 간단한 진짜 아무런 기능이 아직 준비되어 있지 않은 기본적인 Provider의 기본중의 기본 클래스만 만들어서 공유하고자 한다. 이후 DB를 사용하거나, openFile(API 9 GingerBread 부터 지원)과 같은 API를 사용해서 기능을 붙여나가고 진짜 DB를 써야 할 이유가 있을때 적절한 설명과 예제를 공유하도록 하겠지만, 오늘은 정말 기 기초적인 Provider의 껍데기만을 만들어뒀다.


나중에 필요할일이 생기면 그대로 복사해서 필요한 것들 추가하고 바로 사용할수 있게함이 목적이다.


Provider를 만들기 위해서는 AndroidManifest.xml에 provider를 선언해줘야 한다, ContentProvider는 내부적으로 Binder Interface를 통해서 IPC를 지원하고 있다.그래서 Manifest File에 내가 제공하는 provider정보를 명세해주어야지 다른 어플에서도 내가 제공하는 Provider의 Authority로 DB를 접근할수 있게 할수있다.


1. AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hoepisagoodthing.simpleprovider"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="15" />

    <application android:label="@string/app_name"
        android:icon="@drawable/ic_launcher"
        android:theme="@style/AppTheme">
        
        <provider
            android:authorities="com.hopeisagoodthing.simpleprovider"
            android:enabled="true"
            android:exported="true"            
            android:label="Coolkim"
            android:name="com.hopeisagoodthing.simpleprovider.Provider"
            android:syncable="false" >
        </provider>

    </application>

</manifest>




2. Provider와 DataBaseHelper Class

package com.hopeisagoodthing.simpleprovider;

import java.io.File;
import java.io.FileNotFoundException;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.util.SparseArray;

public class Provider extends ContentProvider{
	private static final String TAG="Provider";
	private static final String authority = "com.hopeisagoodthing.simpleprovider";
	private SQLiteOpenHelper dbHelper;
	private SQLiteDatabase db;
	private UriMatcher uriMatcher;
	
	private interface Scheme{
		interface Table{
			static final String NAME="name";
			static final String ADDR="address";
			static final String INTEREST="interest";
		}
		interface Match{
			static final int NAME=1;
			static final int ADDR=2;
			static final int INTEREST=3;
		}		
	}	
	
	private static final SparseArray<Stringgt; tableMap = new SparseArraylt;Stringgt;();
	static{
		tableMap.put(Scheme.Match.NAME, Scheme.Table.NAME);
		tableMap.put(Scheme.Match.ADDR, Scheme.Table.ADDR);
		tableMap.put(Scheme.Match.INTEREST, Scheme.Table.INTEREST);		
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		int 	match 	= uriMatcher.match(uri);
		switch(match){
		case Scheme.Match.NAME:
			break;
		
		case Scheme.Match.ADDR:
			break;
			
		case Scheme.Match.INTEREST:
			break;
			
		default:
			throw new UnsupportedOperationException();			
		}
		
		return db.delete(tableMap.get(match), selection, selectionArgs);		
	}

	@Override
	public String getType(Uri uri) {
		int 	match 	= uriMatcher.match(uri);
		switch(match){
		case Scheme.Match.NAME:
			break;
		
		case Scheme.Match.ADDR:
			break;
			
		case Scheme.Match.INTEREST:
			break;
			
		default:
			throw new UnsupportedOperationException();	
		}
		return null;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		int 	match 	= uriMatcher.match(uri);
		switch(match){
		case Scheme.Match.NAME:
			break;
		
		case Scheme.Match.ADDR:
			break;
			
		case Scheme.Match.INTEREST:
			break;
			
		default:
			throw new UnsupportedOperationException();	
		}
		
		long rowId =  db.insert(tableMap.get(match), null, values);
		uri = ContentUris.withAppendedId(uri, rowId);
		getContext().getContentResolver().notifyChange(uri, null);
		return uri;
	}

	@Override
	public boolean onCreate() {
		dbHelper 	= new SimpleDatabaseHelper(getContext());
        db 		= dbHelper.getWritableDatabase();
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

        uriMatcher.addURI(authority, Scheme.Table.NAME, Scheme.Match.NAME);       
        uriMatcher.addURI(authority, Scheme.Table.ADDR,Scheme.Match.ADDR); 
        uriMatcher.addURI(authority, Scheme.Table.INTEREST, Scheme.Match.INTEREST);
       
		return true;		
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
		int 	match 	= uriMatcher.match(uri);
		switch(match){
		case Scheme.Match.NAME:
			break;
		case Scheme.Match.ADDR:
			break;
		case Scheme.Match.INTEREST:
			break;
			
		default:
			throw new UnsupportedOperationException();	
		}
		
		return db.query(tableMap.get(match), projection, selection, selectionArgs, null, null, sortOrder);
		
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		int 	match 	= uriMatcher.match(uri);
		switch(match){
		
		case Scheme.Match.NAME:
			break;
		
		case Scheme.Match.ADDR:
			break;
		
		case Scheme.Match.INTEREST:
			break;
			
		default:
			throw new UnsupportedOperationException();	
		}
		
		
		return db.update(tableMap.get(match), values, selection,selectionArgs);
	}
	
	@Override
	public ParcelFileDescriptor openFile (Uri uri,String mode){
		ParcelFileDescriptor fd = null;
		
		String filename = uri.getQueryParameter("filename");
		if(filename == null || filename.isEmpty()){
			throw new UnsupportedOperationException();
		}
		File dir = getContext().getFilesDir();
		if(dir.exists() == false){
			dir.mkdir();
		}
		String filepath = dir.getAbsolutePath()+ "/" +filename;
	    try {
			fd = ParcelFileDescriptor.open(new File(filepath), ParcelFileDescriptor.MODE_CREATE|ParcelFileDescriptor.MODE_READ_WRITE);
		} catch (FileNotFoundException e) {
			Log.e(TAG,"Unable to open file "+ filepath);
		}		
		return fd;		
	}
	
	@Override
	public int bulkInsert(Uri uri, ContentValues[] values) {
		long 	rowId 		= -1;
		int 	count = 0;
		int 	match 	= uriMatcher.match(uri);
			
		db.beginTransaction();
					
		switch(match){
		
		case Scheme.Match.NAME:
			break;
		
		case Scheme.Match.ADDR:
			break;
		
		case Scheme.Match.INTEREST:
			break;
		
		default:
			throw new UnsupportedOperationException();	
		}
		
		for(ContentValues value:values){
			rowId = db.insert(tableMap.get(match), null, value);
			if(rowId > 0 ){
				count++;
			}
		}
		
		db.setTransactionSuccessful();			
		
		db.endTransaction();
		uri = ContentUris.withAppendedId(uri, rowId);
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}
	
	private class SimpleDatabaseHelper extends SQLiteOpenHelper {	
		private static final String DATABASE_NAME = "simple.db";
		private static final int DATABASE_VERSION = 1;
		private static final String NAME_TABLE_CREATE = "CREATE TABLE "
				+ "name" + " (" 
				+ "_id" + " INTEGER PRIMARY KEY AUTOINCREMENT," 
				+ "name" + " TEXT "+");";
		
		private static final String ADDRESS_TABLE_CREATE = "CREATE TABLE "
				+ "address" + " (" 
				+ "_id" + " INTEGER PRIMARY KEY AUTOINCREMENT," 
				+ "address" + " TEXT ," 
				+ "name_id" + " INTEGER " + ");";
		
		private static final String INTEREST_TABLE_CREATE = "CREATE TABLE "
				+ "interest" + " (" 
				+ "_id" + " INTEGER PRIMARY KEY AUTOINCREMENT,"				
				+ "interest" + " TEXT ," 
				+ "name_id" + " INTEGER " + ");";
		
		protected SimpleDatabaseHelper(Context context) {
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}

		@Override
		public void onCreate(SQLiteDatabase db) {
			try {				
				db.execSQL(NAME_TABLE_CREATE);	
				db.execSQL(ADDRESS_TABLE_CREATE);
				db.execSQL(INTEREST_TABLE_CREATE);
			} catch (Exception e) {
				Log.e(TAG, "onCreate: Exception - " + e.getMessage());
			}
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		}
	}
}

블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,

Honey Comb(Android 3)부터 Fragment라는 것이 들어왔는데, 그동안 프로바이더나 네트워크 Sync쪽으로만 너무 일이 몰려있던 바람에 Fragment를 이것 저것 많이 다루지 못했던것 같다.


그래서 정말 진짜,, 기초적으로!!! 나중에 참고할일이 있을때 바로 샘플로 사용하기 위해서 간단하 Activity 하나에 Fragment를 두개를 붙이는 예제를 만들었다.

아무런 내용도 없는 진짜 껍데기만 존재하는 코드라서, 나중에 필요한 부분을 붙여넣을 일이 생길때만 사용하면 된다.





너무 휑~~ 하다. 소스도 역시 내용이 없다, 필요할때 채워서 써야 한다. 


1. Main Layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <fragment
        android:id="@+id/fragment1"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        class="com.hopeisagoodthing.fragments.Fragment1" />
    <fragment
        android:id="@+id/fragment2"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        class="com.hopeisagoodthing.fragments.Fragment2" />
</LinearLayout>



2. Fragment1 layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/fragment1"
        tools:context=".MainActivity" />

</RelativeLayout>



3. Fragment2 layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/fragment2"
        tools:context=".MainActivity" />

</RelativeLayout>



4. MainActivity.java

package com.hopeisagoodthing.fragments;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}



5. Fragment1.java

package com.hopeisagoodthing.fragments;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


public class Fragment1 extends Fragment {

	@Override
	public View onCreateView(LayoutInflater inflater,
			ViewGroup container, Bundle savedInstanceState) {
		View v = inflater.inflate(R.layout.fragment1, container, false);	

		return v;
	}

}



6. Fragment2.java

package com.hopeisagoodthing.fragments;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class Fragment2 extends Fragment {

	@Override
	public View onCreateView(LayoutInflater inflater,
			ViewGroup container, Bundle savedInstanceState) {
		View v = inflater.inflate(R.layout.fragment2, container, false);		

		return v;
	}

}

블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,

오늘은 심심해서 Android 4.x에 새로 추가된것들에 대해서 보고 있었는데, 그중에 재미난것이 하나 있어서 코딩해볼까?? 하고 eclipse를 열었다.


그런데, 코딩할필요가 없었다.





이유는 아예 AnalogClock view를 지원하고 있다. 좋다!!!! 아무것도 할것 없이 그냥 아래 view 만 추가해주면 모든게 끝난다.


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


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

    android:id="@+id/analog"

    android:layout_width="match_parent"

    android:layout_height="match_parent" >

    </AnalogClock>


</RelativeLayout>


'코딩하고 > Android' 카테고리의 다른 글

DB관리하기 - Provider 사용하기  (0) 2012.11.21
Fragment 다루기 (아주 심플하게..)  (0) 2012.11.15
HttpClient 사용하기  (0) 2012.10.25
File Observer 사용하기  (0) 2012.10.21
ActionBar로 Tab 만들기  (19) 2012.10.19
블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,