Directory 생성, file list 가져오기 예제입니다.

여기 예제는 외부 메모리를 엑세스 하기때문에 

os 7.0 이상에서는 system permission 관련 로직을 추가하셔야 가능합니다.


참고 url 

https://developer.android.com/reference/android/os/Environment.html


public static String DIRECTORY_ALARMS = "alarms";

public static String DIRECTORY_DCIM = "DICM";

public static String DIRECTORY_DOCUMENTS = "documents" ;

public static String DIRECTORY_DOWNLOADS = "downloads" ;

public static String DIRECTORY_MOVIES = "movies";

public static String DIRECTORY_MUSIC = "music" ;

public static String DIRECTORY_NOTIFICATIONS = "notifications" ;

public static String DIRECTORY_PICTURES = "pictures" ;

public static String DIRECTORY_PODCASTS = "podcasts" ;

public static String DIRECTORY_RINGTONES = "ringtones" ;


public void getFolderFileList() {
	//internal 
	//File dir = new File(getFilesDir().getAbsolutePath(), "test");
	File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "test");
	if (! dir.isDirectory()){
		if (! dir.mkdirs()){
		}
	}

	String[] str = dir.list();
	for(String st : str) {
		Log.d("test"," st : "+st +" , "+st.endsWith(".gif"));
	}

	File[] files = dir.listFiles();
	for(File f : files) {
		Log.w("test"," f : "+f.getPath() +" , "+f.getPath().endsWith(".gif"));
		Log.i("test"," f : "+f.getName() +" , "+f.getName().endsWith(".gif"));
	}
}


결과화면



android activity, service 에서 서로 데이터를 주고 받는 예제 입니다.

참고 url

https://bitbucket.org/alexfu/androidserviceexample/src


간단하게 서비스를 시작할때

bindService를 통해 내가 만든 Messenger를 서비스로 던져 놓고 데이터를 받는 방식입니다.


작업 내용 - MainActivity.java

public class MainActivity extends AppCompatActivity {

	private Messenger mServiceMessenger = null;
	private boolean mIsBound;

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

		Button send = (Button) findViewById(R.id.send);
		send.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View view) {
				// 메시지를 서비스로 전달
				sendMessageToService("from main");
			}
		});
		
		// 서비스 시작
		setStartService();
	}
	
	/** 서비스 시작 및 Messenger 전달 */
	private void setStartService() {
        startService(new Intent(MainActivity.this, ControlService.class));
        bindService(new Intent(this, ControlService.class), mConnection, Context.BIND_AUTO_CREATE);
        mIsBound = true;
    }
    
    /** 서비스 정지 */
    private void setStopService() {
	    if (mIsBound) {
            unbindService(mConnection);
            mIsBound = false;
        }
        stopService(new Intent(MainActivity.this, ControlService.class));
    }
    
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.d("test","onServiceConnected");
            mServiceMessenger = new Messenger(iBinder);
            try {
                Message msg = Message.obtain(null, ControlService.MSG_REGISTER_CLIENT);
                msg.replyTo = mMessenger;
                mServiceMessenger.send(msg);
            }
            catch (RemoteException e) {
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
        }
    };
    
    /** Service 로 부터 message를 받음 */
    private final Messenger mMessenger = new Messenger(new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            Log.i("test","act : what "+msg.what);
            switch (msg.what) {
                case ControlService.MSG_SEND_TO_ACTIVITY:
                    int value1 = msg.getData().getInt("fromService");
                    String value2 = msg.getData().getString("test");
                    Log.i("test","act : value1 "+value1);
                    Log.i("test","act : value2 "+value2);
                    break;
            }
            return false;
        }
    }));
    
    /** Service 로 메시지를 보냄 */
    private void sendMessageToService(String str) {
        if (mIsBound) {
            if (mServiceMessenger != null) {
                try {
                    Message msg = Message.obtain(null, ControlService.MSG_SEND_TO_SERVICE, str);
                    msg.replyTo = mMessenger;
                    mServiceMessenger.send(msg);
                } catch (RemoteException e) {
                }
            }
        }
    }
}


ControlService.java

public class ControlService extends Service {

	public static final int MSG_REGISTER_CLIENT = 1;
	//public static final int MSG_UNREGISTER_CLIENT = 2;
	public static final int MSG_SEND_TO_SERVICE = 3;
	public static final int MSG_SEND_TO_ACTIVITY = 4;
	
	private Messenger mClient = null;	// Activity 에서 가져온 Messenger

	@Override
	public void onCreate() {
		super.onCreate();
		
		Button send_service = (Button) mView.findViewById(R.id.send_service);
		send_service.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View view) {
				sendMsgToActivity(1234);
			}
		});
	}

	@Override
	public IBinder onBind(Intent intent) {
		return mMessenger.getBinder();
	}
	
	/** activity로부터 binding 된 Messenger */
	private final Messenger mMessenger = new Messenger(new Handler(new Handler.Callback() {
		@Override
		public boolean handleMessage(Message msg) {
			Log.w("test","ControlService - message what : "+msg.what +" , msg.obj "+ msg.obj);
			switch (msg.what) {
				case MSG_REGISTER_CLIENT:
					mClient = msg.replyTo;	// activity로부터 가져온 
					break;
			}
			return false;
		}
	}));
	
	private void sendMsgToActivity(int sendValue) {
		try {
			Bundle bundle = new Bundle();
			bundle.putInt("fromService", sendValue);
			bundle.putString("test","abcdefg");
			Message msg = Message.obtain(null, MSG_SEND_TO_ACTIVITY);
			msg.setData(bundle);
			mClient.send(msg);		// msg 보내기
		} catch (RemoteException e) {
		}
	}
}

결과화면

각각 버튼을 눌러 messenger를 통해 메시지를 주고 받았습니다.


오늘은 최상단 위치에  Services를 통해 View를 실행하는 예제를 작성하겠습니다.

먼저 Service에서 WindowManager를 통해 View를 만들 수 있습니다.


코드 작성

AndroidManifest.xml (permission 과 application 영역내의 service를 등록 해 줍니다.)

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

<application>

	...
	
	<service
		android:name=".MyService"
		android:enabled="true"
		android:permission="android.permission.SYSTEM_ALERT_WINDOW" >
	</service>
</application>


view_in_service.xml (서비스를 통해 보여질 view xml을 작성합니다.)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:background="#0000ff">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:textColor="#ffffff"
        android:id="@+id/textView" />

    <ImageButton
        android:layout_width="368dp"
        android:layout_height="wrap_content"
        android:id="@+id/bt"
        android:text="click"
        android:textColor="#ffffff"
        android:src="@mipmap/ic_launcher"
        android:layout_below="@+id/textView"
        android:layout_alignParentLeft="true"
        android:layout_marginTop="12dp" />

</RelativeLayout>


MyService.java

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.TextView;

public class MyService extends Service {

	WindowManager wm;
	View mView;

	@Override
	public IBinder onBind(Intent intent) { return null; }
	
	@Override
	public void onCreate() {
		super.onCreate();
		LayoutInflater inflate = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		wm = (WindowManager) getSystemService(WINDOW_SERVICE);

		WindowManager.LayoutParams params = new WindowManager.LayoutParams(
				/*ViewGroup.LayoutParams.MATCH_PARENT*/300,
				ViewGroup.LayoutParams.WRAP_CONTENT,
				WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
				WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
						|WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
						|WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
				PixelFormat.TRANSLUCENT);

		params.gravity = Gravity.LEFT | Gravity.TOP;
		mView = inflate.inflate(R.layout.view_in_service, null);
		final TextView textView = (TextView) mView.findViewById(R.id.textView);
		final ImageButton bt =  (ImageButton) mView.findViewById(R.id.bt);
		bt.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				bt.setImageResource(R.mipmap.ic_launcher_round);
				textView.setText("on click!!");
			}
		});
		wm.addView(mView, params);
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		if(wm != null) {
			if(mView != null) {
				wm.removeView(mView);
				mView = null;
			}
			wm = null;
		}
	}
}


MainActivity.java

(마시멜로우 버전 이상부터는 보안이 강화가 되어서 아래 사용자의 동의를 얻어야지만 사용할 수 있습니다.

그래서 checkpermission이라는 부분에서 상세히 작성되어 있습니다.)

public class MainActivity extends AppCompatActivity {

    private static final int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE = 1;

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

        Button bt_start = (Button) findViewById(R.id.bt_start);
        bt_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                checkPermission();
                //startService(new Intent(MainActivity.this, AlwaysOnTopService.class));
            }
        });

        Button bt_stop = (Button) findViewById(R.id.bt_stop);
        bt_stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                stopService(new Intent(MainActivity.this, MyService.class));
            }
        });
    }

    public void checkPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {   // 마시멜로우 이상일 경우
            if (!Settings.canDrawOverlays(this)) {              // 체크
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                        Uri.parse("package:" + getPackageName()));
                startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
            } else {
                startService(new Intent(MainActivity.this, MyService.class));
            }
        } else {
            startService(new Intent(MainActivity.this, MyService.class));
        }
    }

    @TargetApi(Build.VERSION_CODES.M)
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE) {
            if (!Settings.canDrawOverlays(this)) {
                // TODO 동의를 얻지 못했을 경우의 처리
                
            } else {
                startService(new Intent(MainActivity.this, MyService.class));
            }
        }
    }
}


완료 및 실행 화면!


   


 



AppCompatSeekBar 를 사용하면 Max값이랑 Progress만 설정 할 수 있게 되어있습니다.

Min이랑 Step 도 되게 해주면 편하게 개발할텐데요.

없으니깐 만들어서 쓰셔야 합니다.


작업 내용

xml 은 아래와 같이 작성하였습니다.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="20dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="15sp"
            android:id="@+id/tv_"
            android:text="SeekBar : "/>

        <android.support.v7.widget.AppCompatSeekBar
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/tv_"
            android:layout_marginTop="20dp"
            android:id="@+id/sb_"/>

    </RelativeLayout>
</android.support.constraint.ConstraintLayout>


.Java code는 아래와 같이 작성하였습니다.

import android.animation.ObjectAnimator;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.AppCompatSeekBar;
import android.view.animation.LinearInterpolator;
import android.widget.SeekBar;
import android.widget.TextView;

import java.text.DecimalFormat;

public class MainActivity extends AppCompatActivity {

    final int max = 5;
    final float min = (float) 0.1;
    final float step = (float) 0.1;
    final String str_title = "SeekBar : ";

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

        final TextView tv_ = (TextView) findViewById(R.id.tv_);
        final AppCompatSeekBar sb_ = (AppCompatSeekBar) findViewById(R.id.sb_);

        setSeekBarMax(sb_, max);
        sb_.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {
                setSeekBarChange(progress, tv_);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
            }
        });
        setSeekBarAnimation(sb_);
    }

    private void setSeekBarMax(AppCompatSeekBar sb, int max_value) {
        sb.setMax((int)((max_value-min) / step));
    }

    private void setSeekBarChange(int progress, TextView tv) {
        float value = min + (progress * step);
        DecimalFormat format = new DecimalFormat(".#");
        String str = format.format(value);
        tv.setText(str_title +" ( "+Float.valueOf(str)+" )");
    }

    // 최초 중간 위치 설정
    private void setSeekBarAnimation(AppCompatSeekBar sb) {

        int progress_half = (int)(((max / min) / 2)-1);

        ObjectAnimator animation = ObjectAnimator.ofInt(sb, "progress", progress_half);
        animation.setDuration(100); // 0.5 second
        animation.setInterpolator(new /*DecelerateInterpolator()*/LinearInterpolator());
        animation.start();
    }
}


결과화면

최소 value 0.1 ~ 5.0 사이에 step 은 0.1 만큼씩 움직이게 됩니다.





개발을 하다보니 이것저것 외부 라이브러리를 참조하게 되었는데,

프로가드를 적용하다보니 

org.apache.log4j.chainsaw.ControlPanel: can't find superclass or interface javax.swing.JPanel 

천개가 넘는 warning 메시지가 나오면서 빌드가 되지 않았습니다.



그래서 해결책은 간단하게

proguard-rules.pro 파일 내에서 관련 lib에 관한 예외처리를 해주었습니다.

-dontwarn org.apache.log4j.**



안드로이드에서 SQLite like 검색 방법입니다.


SQL Like 검색시 사용 방법

protected Cursor select(String tableName, String col1, String Like) throws SQLiteException{
	return getReadableDatabase().query(tableName, null, col1+ " LIKE ?", new String[] {"%"+ Like+ "%" }, null, null, null, null);
}


SQL Like 검색시 (OR, AND) 사용 방법 (두개 이상의 컬럼시) 

- 당연한 얘기이겠지만, 이렇게 사용하면 성능이 현저히 떨어지기 때문에 권장하지 않습니다.

protected Cursor select(String tableName, String col1, String col2, String Like) throws SQLiteException{
	return getReadableDatabase().query(true, tableName, null, col1+" LIKE '%"+Like+"%' or "+col2+" LIKE '%"+Like+"%'", null, null, null, null, null);
}


TTS 예제 프로그램입니다.

setLanguage() // 지역 선택

setPitch() // 낮거나 높은음을 일정하게 맞춰 주는 옵션

setSpeechRate() // 재생 속도

speak()                // 재생


실행 화면



코드 사용 (xml)

<RelativeLayout
	android:layout_width="match_parent"
	android:layout_height="match_parent">

	<EditText
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:layout_marginTop="20dp"
		android:id="@+id/et"
		android:text="There is something I want to talk to you about."/>

	<Button
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:layout_marginTop="20dp"
		android:layout_below="@+id/et"
		android:text="play"
		android:id="@+id/play"/>

	<RadioGroup
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:id="@+id/rg_local"
		android:layout_marginTop="20dp"
		android:orientation="horizontal"
		android:layout_below="@id/play">

		<RadioButton
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:checked="true"
			android:id="@+id/rb_local1"
			android:text="us"/>

		<RadioButton
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:id="@+id/rb_local2"
			android:text="korea"/>

	</RadioGroup>

	<RadioGroup
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:id="@+id/rg_pitch"
		android:layout_marginTop="20dp"
		android:orientation="horizontal"
		android:layout_below="@id/rg_local">

		<RadioButton
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:checked="true"
			android:id="@+id/rb_pitch1"
			android:text="pitch row"/>

		<RadioButton
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:id="@+id/rb_pitch2"
			android:checked="true"
			android:text="pitch normal"/>

		<RadioButton
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:id="@+id/rb_pitch3"
			android:text="pitch high"/>
	</RadioGroup>

	<RadioGroup
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:id="@+id/rg_rate"
		android:layout_marginTop="20dp"
		android:orientation="horizontal"
		android:layout_below="@id/rg_pitch">

		<RadioButton
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:id="@+id/rb_rate1"
			android:text="x0.1"/>

		<RadioButton
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:id="@+id/rb_rate2"
			android:checked="true"
			android:text="x1"/>

		<RadioButton
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:id="@+id/rb_rate3"
			android:text="x2"/>

		<RadioButton
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:id="@+id/rb_rate4"
			android:text="x3"/>

		<RadioButton
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:id="@+id/rb_rate5"
			android:text="x4"/>
	</RadioGroup>

	<RadioGroup
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:id="@+id/rg_queue"
		android:layout_marginTop="20dp"
		android:orientation="horizontal"
		android:layout_below="@id/rg_rate">

		<RadioButton
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:checked="true"
			android:id="@+id/rb_queue_add"
			android:text="QUEUE_ADD"/>

		<RadioButton
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:id="@+id/rb_queue_flush"
			android:text="QUEUE_FLUSH"/>
	</RadioGroup>
</RelativeLayout>



코드 사용

import android.content.ComponentName;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.support.annotation.IdRes;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioGroup;

import java.util.HashMap;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {

    private TextToSpeech mTts = null;
    private Locale mLocale = Locale.US;
    private float mPitch = (float) 0;
    private float mRate = (float) 0;
    private int mQueue = TextToSpeech.QUEUE_ADD;

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

        final EditText et = (EditText) findViewById(R.id.et);
        Button play = (Button) findViewById(R.id.play);
        play.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(mTts != null) {
                    if(et != null) {
                        String text = et.getText().toString();
                        if(text.length() > 0) {
                            setLanguage(mLocale);
                            setPitch(mPitch);
                            setSpeechRate(mRate);
                            speak(text, 0);
                        }
                    }
                }
            }
        });
        RadioGroup lay_local = (RadioGroup) findViewById(R.id.rg_local);
        RadioGroup lay_pitch = (RadioGroup) findViewById(R.id.rg_pitch);
        RadioGroup lay_rate = (RadioGroup) findViewById(R.id.rg_rate);
        RadioGroup lay_queue = (RadioGroup) findViewById(R.id.rg_queue);
        lay_local.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup radioGroup, @IdRes int id) {
                if(id == R.id.rb_local1) {
                    mLocale = Locale.US;
                } else {
                    mLocale = Locale.KOREA;
                }
            }
        });
        lay_pitch.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup radioGroup, @IdRes int id) {
                if(id == R.id.rb_pitch1) {
                    mPitch = (float) 0.1;
                } else if(id == R.id.rb_pitch2) {
                    mPitch = 1;
                } else if(id == R.id.rb_pitch3) {
                    mPitch = 2;
                }
            }
        });
        lay_rate.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup radioGroup, @IdRes int id) {
                if(id == R.id.rb_rate1) {
                    mRate = (float) 0.1;
                } else if(id == R.id.rb_rate2) {
                    mRate = 1;
                } else if(id == R.id.rb_rate3) {
                    mRate = 2;
                } else if(id == R.id.rb_rate4) {
                    mRate = 3;
                } else if(id == R.id.rb_rate5) {
                    mRate = 4;
                }
            }
        });
        lay_queue.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup radioGroup, @IdRes int id) {
                if(id == R.id.rb_queue_add) {
                    mQueue = TextToSpeech.QUEUE_ADD;
                } else {
                    mQueue = TextToSpeech.QUEUE_FLUSH;
                }
            }
        });
        init();
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mTts != null) {
            if(mTts.isSpeaking()) {
                mTts.stop();
            }
        }
    }

    @Override
    public void onDestroy() {
        if (mTts != null) {
            if(mTts.isSpeaking()) {
                mTts.stop();
            }
            mTts.shutdown();
        }
        super.onDestroy();
    }

    private void init() {
        mTts = new TextToSpeech(getBaseContext(), new TextToSpeech.OnInitListener() {
            @Override
            public void onInit(int status) {
                if(status == TextToSpeech.SUCCESS) {
                } else{
                    // todo: fail 시 처리
                    startActivity(getSettingActIntent());
                }
            }
        });
    }

    /** 언어 선택 */
    public void setLanguage(Locale locale){
        if(mTts!=null)
            mTts.setLanguage(locale);
    }

    public void setPitch(float value){
        if(mTts!=null)
            mTts.setPitch(value);
    }

    /** 속도 선택 */
    public void setSpeechRate(float value){
        if(mTts!=null)
            mTts.setSpeechRate(value);
    }

    /** TTS 설정 으로 이동 */
    public Intent getSettingActIntent(){
        Intent intent = new Intent();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH){
            intent.setAction("com.android.settings.TTS_SETTINGS");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }else {
            intent.addCategory(Intent.CATEGORY_LAUNCHER);
            intent.setComponent(new ComponentName("com.android.settings", "com.android.settings.TextToSpeechSettings"));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        return intent;
    }

    /** 재생 */
    public void speak(String text, int resId){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
            if(mTts != null)
                mTts.speak(text, mQueue, null, ""+resId);
        }else {
            HashMap<String, String> map = new HashMap<>();
            map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, ""+resId);
            if(mTts != null)
                mTts.speak(text, mQueue, map);
        }
    }
}


안드로이드 구글맵 v2 클러스터 예제를 만들어 보았습니다.

zoomlevel을 내렸을 경우에는 해당 인근의 데이터는 모아서 숫자로 보여주며

올렸을 경우에는 원래 데이터가 있던 위치에 표시되는 지도를 확인 할수 있습니다.


실행 화면

  (Zoom level down)


Java 코드 작업

1. 클러스터 라이브러리를 사용하기 위한 작업을 Gradle에서 추가합니다.

dependencies {
    /* 중략 */
    compile 'com.google.android.gms:play-services-maps:10.2.1'
    compile 'com.google.android.gms:play-services-location:10.2.1'
    compile 'com.google.maps.android:android-maps-utils:0.5'
}


2. ClusterItem 인터페이스 클래스를 작성해줍니다.

import com.google.android.gms.maps.model.LatLng;
import com.google.maps.android.clustering.ClusterItem;

public class PositionItem implements ClusterItem {

    private final LatLng mPosition;
    public int bg;

    public PositionItem(double lat, double lng, int bg) {
        mPosition = new LatLng(lat, lng);
        this.bg = bg;
    }

    @Override
    public LatLng getPosition() {
        return mPosition;
    }

    @Override
    public String getTitle() {
        return null;
    }

    @Override
    public String getSnippet() {
        return null;
    }
}<


3. 맵 호출 부분 작성.

mMap.getMapAsync(new OnMapReadyCallback() {
	@Override
	public void onMapReady(final GoogleMap googleMap) {
		if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
			boolean permission = mParentsAct.hasAllPermissionsGranted();
			if (!permission) {
				return;
			}
		}
		try {
			MapsInitializer.initialize(getActivity());
		} catch (Exception e) {
		}

		googleMap.getUiSettings().setMyLocationButtonEnabled(true);
		googleMap.getUiSettings().setZoomControlsEnabled(true);
		googleMap.setMyLocationEnabled(true);

		setCluster(googleMap);
	}
});


4. setCluster() 메소드 작성.

private void setCluster(final GoogleMap googleMap) {
	final List<PositionItem> mPosi = /* 좌표정보 데이터 리스트 */;
	if(mPosi != null) {
		if (mPosi.size() > 0) {
			mClusterManager = new ClusterManager<PositionItem>(getActivity(), googleMap);
			googleMap.setOnCameraIdleListener(mClusterManager);
			googleMap.setOnMarkerClickListener(mClusterManager);
			
			LatLngBounds.Builder builder = LatLngBounds.builder();	// Bounds 모든 데이터를 맵 안으로 보여주게 하기 위한
			LatLngBounds bounds = addItems(builder, mPosi);         // 클러스터 Marker 추가
			googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, ZoomLevel));
			float zoom = googleMap.getCameraPosition().zoom - 0.5f;
			googleMap.animateCamera(CameraUpdateFactory.zoomTo(zoom));

			mClusterManager.setRenderer(new OwnIconRendered(mAppData, googleMap, mClusterManager));

			// 내용 클릭시
			googleMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
				@Override
				public void onInfoWindowClick(Marker marker) {
				}
			});

			// 클러스터 클릭시 펼치기
			mClusterManager.setOnClusterClickListener(new ClusterManager.OnClusterClickListener<PositionItem>() {
				@Override
				public boolean onClusterClick(Cluster<PositionItem> cluster) {
					LatLngBounds.Builder builder_c = LatLngBounds.builder();
					for (ClusterItem item : cluster.getItems()) {
						builder_c.include(item.getPosition());
					}
					LatLngBounds bounds_c = builder_c.build();
					googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds_c, ZoomLevel));
					float zoom = googleMap.getCameraPosition().zoom - 0.5f;
					googleMap.animateCamera(CameraUpdateFactory.zoomTo(zoom));
					return true;
				}
			});
		}
	}
}

// 마커 추가
private void addItems(List<PositionItem> mPosi) {
	for (PositionItem item : mPosi) {
		mClusterManager.addItem(item);
	}
}

// 마커 커스텀 class
class CustomIconRenderer extends DefaultClusterRenderer<PositionItem> {
	public CustomIconRenderer(Context context, GoogleMap map, ClusterManager<PositionItem> clusterManager) {
		super(context, map, clusterManager);
	}

	@Override
	protected void onBeforeClusterItemRendered(PositionItem item, MarkerOptions markerOptions) {
		int id = R.drawable.rect_memo1;
		if(item.bg == 1) {					// drawable 변경
		} else if (item.bg == 2) {
		} else if (item.bg == 3) {
		} else if (item.bg == 4) {
		}
		Drawable d = ContextCompat.getDrawable(getActivity(), id);
		BitmapDescriptor markerIcon = getMarkerIconFromDrawable(d);

		markerOptions.icon(markerIcon);
		markerOptions.snippet(item.getSnippet());
		markerOptions.title(item.getTitle());
		super.onBeforeClusterItemRendered(item, markerOptions);
	}
}


Bundle 로 Object, ArrayList 넘기기 예제 입니다.


Intent를 사용하실 경우에는 아래와 같이 사용하며

// 줄때
Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putSerializable("Obj", item);   // Object 넘기기
bundle.putParcelableArrayList("list", (ArrayList<? extends Parcelable>) list); // list 넘기기
intent.putExtras(bundle);

// 받을때
Bundle bundle = getIntent().getExtras();
bundle.getSerializable("Obj");
bundle.getParcelableArrayList("list");

Fragment를 통한 사용은 아래와 같이 사용하시면 됩니다.

// 줄때
Fragment f = new Fragment();
Bundle bundle = new Bundle();
bundle.putSerializable("Obj", item);   // Object 넘기기
bundle.putParcelableArrayList("list", (ArrayList<? extends Parcelable>) list); // list 넘기기
f.setArguments(bundle);

// 받을때
Bundle bundle = getArguments();
bundle.getSerializable("Obj");
bundle.getParcelableArrayList("list");


Java 사용 예제

(Serializable)Item 클래스의 코드입니다.

import java.io.Serializable;

public class Item implements Serializable {

    public int index;
    public String address; // 주소
    public String title;   // 제목

    public Item(int index, String address, String title) {
        this.index = index;
        this.address = address;
        this.title = title;
    }
}

(Parcelable)Item2 클래스의 코드입니다.

import android.os.Parcel;
import android.os.Parcelable;

public class Item2 implements Parcelable {

    public int index;
    public String address; // 주소
    public String title;   // 제목

    public Item2(int index, String address, String title) {
        this.index = index;
        this.address = address;
        this.title = title;
    }

    public Item2(Parcel in) {
        index = in.readInt();
        address = in.readString();
        title = in.readString();
    }

    public static final Creator<Item2> CREATOR = new Creator<Item2>() {
        @Override
        public Item2 createFromParcel(Parcel in) {
            return new Item2(in);
        }

        @Override
        public Item2[] newArray(int size) {
            return new Item2[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(index);
        dest.writeString(address);
        dest.writeString(title);
    }
}

보내는 부분의 Java 코드입니다.

Fragment f = new Fragment();
Bundle bundle = new Bundle();
bundle.putInt("id", 1122);

Item item = new Item(123, "abc", "가나다");
// Object 넘기기
bundle.putSerializable("item", item);   

List<Item2> list = new ArrayList<>();
list.add(new Item2(222, "ddd", "다다다"));
list.add(new Item2(223, "eee", "다다다"));
list.add(new Item2(224, "ddd", "다다다"));
// 리스트 넘기기
bundle.putParcelableArrayList("list", (ArrayList<? extends Parcelable>) list);

f.setArguments(bundle);

받는 부분의 Java 코드입니다.

Bundle bundle = getArguments();
int id = bundle.getInt("id");
Item item = (Item) bundle.getSerializable("item");
List<Item2> item2 = bundle.getParcelableArrayList("list");

Log.v("test","id : "+id);
Log.w("test","item : "+item.index+" , "+item.address+" , "+item.title);
Log.d("test","item2 : "+item2.size());
for(Item2 it : item2)
	Log.i("test","it : "+it.index+" , "+it.address+" , "+it.title);

결과 화면





sqlite 에서 Like 검색 예제입니다.

실행 화면은 아래와 같습니다.


 


코드 작성

UI 처리 부분

public void setChangeListData(String searchKeyword) {
	if(searchKeyword != null) {
		if (searchKeyword.length() != 0) {
			List<ItemMemo> temp = setLikeSearch(searchKeyword);
			if(temp != null) {
				setSearchData(temp);
				return;
			}
		}
	}
	setLoadListData(oriList);
}

private void setSearchData(List<ItemMemo> list) {
	lay_noData.setVisibility(View.GONE);
	tv_noSearch.setVisibility(View.GONE);
	if(list.size() == 0) {
		rv.setVisibility(View.INVISIBLE);
		tv_noSearch.setVisibility(View.VISIBLE);
	} else {
		rv.setVisibility(View.VISIBLE);
		mAdapter.swap(list);
	}
}


SQLite 쿼리 날리는 부분

/**
 * Like 검색
 */
public List<ItemMemo> setLikeSearch(String keyword) {
	List<ItemMemo> list = new ArrayList<>();
	try {
		beginTransaction();
		Cursor c = select(TABLE_NAME, /**COLUMNS_NAME*/"contents", keyword);
		if (c != null) {
			Log.i("test","c : " + c + " , " + c.getCount());
			int total = c.getCount();
			if (total > 0) {
				c.moveToFirst();
				while (!c.isAfterLast()) {
					
					/* 중략 */

					list.add(new ItemMemo());
					c.moveToNext();
				}
			}
			c.close();
		}
	} catch (SQLiteException e) {
		Log.e("test", e.toString());
	} finally {
		endTransaction();
	}
	return list;
}

public Cursor select(String tableName, String name, String Like) throws SQLiteException{
	return getReadableDatabase().query(
			tableName, 
			null,
			name+ " LIKE ?",
			new String[] {"%"+ Like+ "%" },
			null,
			null,
			null,
			null);
}


+ Recent posts