안드로이드 서치뷰 searchView 확대하기 expand

출처 : https://stackoverflow.com/questions/27556623/creating-a-searchview-that-looks-like-the-material-design-guidelines/31765199

It is actually quite easy to do this, if you are using android.support.v7 library.

Step – 1

Declare a menu item

<item android:id="@+id/action_search"
    android:title="Search"
    android:icon="@drawable/abc_ic_search_api_mtrl_alpha"
    app:showAsAction="ifRoom|collapseActionView"
    app:actionViewClass="android.support.v7.widget.SearchView" />

Step – 2

Extend AppCompatActivity and in the onCreateOptionsMenu setup the SearchView.

import android.support.v7.widget.SearchView;

...

public class YourActivity extends AppCompatActivity {

    ...

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_home, menu);
        // Retrieve the SearchView and plug it into SearchManager
        final SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));
        SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        return true;
    }

    ... 

}

Result

enter image description here

 

enter image description here

Advertisements

안드로이드 갤러리 gallery 갱신

안드로이드에서 갤러리새로고침이 기기 재부팅을 해도 안되는 경우가 있다.

갤러리 새로고침은 미디어 스캐닝을 해야 해결이 가능하다.

킷캣부터 이렇게 바꼈다(테스트 해보니 아샌(4.0.3에서도 아래 소스가 통한다.)

private void galleryAddPic(String currentPhotoPath) {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(currentPhotoPath); //새로고침할 사진경로
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);
}

Intent.ACTION_MEDIA_SCANNER_SCAN_FILE는 단일파일 하나를 새로고침할 때 사용하고,

Intent.ACTION_MEDIA_MOUNTED는 하나의 폴더를 새로고침할 때 사용한다고 보면 되겠다.

여러개의 파일들을 새로고침하는데,

같은 폴더에 있다면 ACTION_MEDIA_MOUNTED 옵션을 활용하는 것이 좋을 것이다.

참고 :

http://yonoo88.tistory.com/21

http://www.codeproject.com/Questions/689342/Refresh-gallery-in-android-kitkat
http://dd00oo.tistory.com/entry/갤러리-새로고침Refresh [순수의공간]

안드로이드 surfaceView screenShot 찍기

서피스뷰는 카메라의 프리뷰를 보여줄 때 많이쓰는데요.

 

카메라 프리뷰를 서피스뷰로 보여주는 이유는 카메라의 실시간 영상을 다른뷰로 보여주려면 부하가 많이 걸리지만,

서피스뷰를 이용하면, 그 뒷단에서 작업한 후 서피스뷰를 통해 카메라 프리뷰를 띄워주기 때문에 부하를 줄일 수 있어

많이 쓰입니다.

어플을 만들다 보면 카메라 프리뷰를 스크린샷으로 찍어야 할 때가 있는데요.

저같은 경우에는 카메라 위에 오버레이(이미지및 텍스트)를 띄워서 함께 스크린샷을 찍을려고 이 방법을 사용했습니다.

예를 들면 위와같이 Frame Layout안에 Surface View와 각종 Overlay를 넣은 화면을 생각할 수 있습니다.

그리고 Surface View에는 카메라를 그 위에는 정보에 해당하는 Overlay를 띄어 줄 생각입니다.

우선 Surface View입니다.

 

  1. public class SurfacePreview extends SurfaceView implements SurfaceHolder.Callback{
  2.     SurfaceHolder holder;   //서피스홀더
  3.     Camera cam=null;        //카메라
  4.     public SurfacePreview(Context context, AttributeSet attrs) {
  5.         super(context, attrs);
  6.         init(context);
  7.     }
  8.     public SurfacePreview(Context context) {
  9.         super(context);
  10.         init(context);
  11.     }
  12.     public void init(Context context){
  13.         holder=getHolder();
  14.         holder.addCallback(this);
  15.         if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
  16.             getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  17.     }
  18.     @Override
  19.     public void surfaceChanged(SurfaceHolder holder, int format, int width,
  20.             int height) {
  21.         cam.setDisplayOrientation(90);      //카메라 각도를 포트레이트로(90도)
  22.         cam.startPreview();                 //프리뷰 시작
  23.     }
  24.     @Override
  25.     public void surfaceCreated(SurfaceHolder holder) {
  26.         cam=Camera.open();                  //카메라 객체를 오픈(퍼미션 되어있어야 됨)
  27.         try{
  28.             cam.setPreviewDisplay(holder);  //프리뷰를 홀더로
  29.         }catch(Exception e){
  30.             e.printStackTrace();
  31.         }
  32.     }
  33.     @Override
  34.     public void surfaceDestroyed(SurfaceHolder holder) {
  35.         cam.stopPreview();
  36.         cam.release();                      //카메라 죽이기
  37.         cam=null;
  38.     }
  39. }

보시는 봐와 같이 custom surfaceview입니다.

위와같이 작성하셔서 스크린샷을 찍으시면 검은 화면으로 나올겁니다.

이게 카메라를 바로 서피스뷰로 뿌리는게 아니라 뒤쪽에서 작업후 뿌리는 거라 다르다고 하네요.

그래서 이 카메라의 서피스뷰를 카메라 프리뷰콜백 함수로 bitmap을 가져올 수 있습니다.

서피스뷰에서 impleament로 카메라 프리뷰 콜백을 추가시켜 주시면 됩니다.

위 서피스뷰 클래스에 아래 코드처럼 impleament를 추가해 주세요.

  1. public class SurfacePreview extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback

그럼 onPreviewFrame 메소드가 추가됩니다.

onPreviewFrame메소드는 아래처럼 입력해줍니다.

  1.     @Override
  2.     public void onPreviewFrame(byte[] data, Camera camera) {
  3.         Camera.Parameters params = camera.getParameters();
  4.         int w = params.getPreviewSize().width;
  5.             int h = params.getPreviewSize().height;
  6.             int format = params.getPreviewFormat();
  7.             YuvImage image = new YuvImage(data, format, w, h, null);
  8.             ByteArrayOutputStream out = new ByteArrayOutputStream();
  9.             Rect area = new Rect(0, 0, w, h);
  10.             image.compressToJpeg(area, 100, out);
  11.             Bitmap bm = BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.size());
  12.             Matrix matrix = new Matrix();
  13.         matrix.postRotate(90);
  14.         Bitmap rotatedBitmap = Bitmap.createBitmap(bm, 0, 0,w, h, matrix, true);
  15.             camWeather.shareBitmap=rotatedBitmap;
  16.     }

onPreviewFrame은 매 순간 자동으로 호출이 됩니다.

코드에서 보시면 13번째 줄까지는 카메라의 프리뷰를 bitmap으로 바꿔주는 코드이고요.

15~17까지는 처음 서피스로 뿌릴때 90도 돌려서 뿌렸기 때문에 프리뷰에서도 각도를 맞춰줘야 해서 90도 돌리는

코드입니다.

18번째줄은 오버레이와 합쳐주기위해 메인쪽에 bitmap값을 전달해주기 위해 넣어놓은 코드입니다.

그리고 onPreviewFrame callback함수를 실행하기 위해서는 surfaceCreated 메소드안에 

 

  1. cam.setPreviewCallback(this);

를 추가해 줘야합니다.

그리고 method called after release() exception이 나는걸 방지하기 위해

surfaceDestroyed안에 

  1. cam.setPreviewCallback(null);

를 추가해 주셔야 합니다.

이제 메인쪽(스크린샷을 호출하는 코드가 있는곳)에서 아래의 코드가 호출 됩니다.

  1.     public void capture(){
  2.         Bitmap overlay=Bitmap.createBitmap(shareBitmap.getWidth(),shareBitmap.getHeight(),shareBitmap.getConfig());
  3.         Canvas canvas=new Canvas(overlay);
  4.         canvas.drawBitmap(shareBitmap, 0,0, null);
  5.         shareLayout.buildDrawingCache();
  6.         Bitmap bm=shareLayout.getDrawingCache();
  7.         canvas.drawBitmap(bm,0,0,null);
  8.         FileOutputStream out;
  9.         String filename=System.currentTimeMillis()+”.jpg”;
  10.         String temp=”/”+filename;
  11.         try{
  12.             out=new FileOutputStream(Environment.getExternalStorageDirectory().toString()+temp);
  13.             overlay.compress(Bitmap.CompressFormat.JPEG,100, out);
  14.             Toast.makeText(getApplicationContext(),temp+”에 저장되었습니다”, Toast.LENGTH_SHORT).show();
  15.         }catch(Exception e){
  16.             Log.d(“screenshot”,String.valueOf(e));
  17.             e.printStackTrace();
  18.         }
  19.     }

2~3라인은 서피스뷰쪽에서 전달해준 비트맵을 가져와서 새로운 비트맵을 그리는 코드입니다.

같은 크기로 그려주기위해 속성을 그대로 줬습니다.

그리고 canvas를 그려주고요.

4번줄에 카메라 프리뷰로 가져온 전달받은 녀석을 그려줬습니다.

5~6은 오버레이에 해당되는 레이아웃입니다. 이건 서피스뷰가 아니라서 원래의 방법대로 스크린샷을~

그리고 7번라인에서 canvas에 오버레이를 그려줍니다.

여기까지하시면 사진위에 오버레이가 그려집니다.

8번부터는 파일로 저장하는 코드입니다.

 

 

 

구현된 코드입니다.

출처: http://answerofgod.tistory.com/entry/surfaceview-에서-screenshot-찍기 [The Answer’s Engineering Blog]

안드로이드 url to Bitmap + 비트맵 리사이즈

 public static Bitmap getImageFromURL(String imageURL){
        Bitmap imgBitmap = null;
        HttpURLConnection conn = null;
        BufferedInputStream bis = null;
        
        try
        {
            URL url = new URL(imageURL);
            conn = (HttpURLConnection)url.openConnection();
            conn.connect();
            
            int nSize = conn.getContentLength();
            bis = new BufferedInputStream(conn.getInputStream(), nSize);
            imgBitmap = BitmapFactory.decodeStream(bis);
        }
        catch (Exception e){
            e.printStackTrace();
        } finally{
            if(bis != null) {
                try {bis.close();} catch (IOException e) {}
            }
            if(conn != null ) {
                conn.disconnect();
            }
        }
        
        return imgBitmap;
    }
추가 : 네트워크를 사용하기 때문에 위 코드는 메인 스레드가 아닌 새로운 스레드를 생성해서 그 안에서 사용해야 함.
ex)

final Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        finalBitmap = getImageFromURL(drawingImage);
        finalBitmapa2 = imgResize(finalBitmap);

    }
});
thread.start();

+ 이미지 리사이즈

public Bitmap imgResize(Bitmap bitmap)
    {
int x=200,y=200; //바꿀 이미지 사이즈
     Bitmap output = Bitmap.createBitmap(x, y, Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
canvas.drawBitmap(bitmap, 0, 0, null);
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Rect src = new Rect(0, 0, w, h);
Rect dst = new Rect(0, 0, x, y);//이 크기로 변경됨
canvas.drawBitmap(bitmap, src, dst, null);
     return output;
    }

출처: http://newkie.tistory.com/34 [뉴키]

안드로이드 setParameters failed 에러

camera의 setPreviewSize 에서 발생하는 java.lang.RuntimeException: setParameters failed

10-23 21:46:38.535: E/AndroidRuntime(7850): java.lang.RuntimeException: setParameters failed


원인

– setParameters() 함수를 호출할 때, Parameter.setPreviewSize() 를 통해서 지정한 사이즈가 해당 단말의 카메라 하드웨어가 지원하지 않는 사이즈일 떄 발생하는 exception 입니다.



해결방법

 Parameters.getSupportedPreviewSizes() 를 호출하면, 단말의 하드웨어(카메라) 가 지원하는 size 들이 List<Size> 형태로 return 됩니다. 여기에 명시된 size 들이 set 되어야만 exception 이 발생하지 않습니다.

출처: http://aroundck.tistory.com/1149 [돼지왕 왕돼지 놀이터]

추가 – 적용 방법 :

Camera.Parameters params = camera.getParameters();
List<Camera.Size> priviewSizes = params.getSupportedPreviewSizes();

Camera.Size priviewsize = priviewSizes.get(1);

params.setPreviewSize(priviewsize.width, priviewsize.height);

 

안드로이드 핸들러 사용법 심화

Android Handler 사용법에 대해 알아 봅시다.

핸들러의 메세지 전송 사용법에 대해 알아보도록 하겠습니다.
적당한 예제가 소켓 통신 -> 쉽게 말해서 채팅 하는거를 적용해서 설명 하겠습니다.
제가 Handler를 쓴 이유는 스레드를 사용하기 때문입니다.
즉 메인스레드(송신)에 있는 변수 값을 다른 스레드(수신)에서 값을 변경 시켜주기 위해 사용하였습니다.
1)handleMessage함수
그림1

핸들러 구현 함수

public void handleMessage(Message msg)
{
//write your method
}
위 함수는 밑에 사진의 sendMessage 함수에 의해 전달되는 msg를 받아서 처리하는 하는것입니다.
그림1

sendMessage를 이용한 메세지 전송

즉 sendMessage(msg)에서 보낸 msg를    handleMessage(Message msg)의 msg 로 받아 public void handleMessage(Message msg) 함수에서 처리 하는 것입니다.
참고* Message msg  에는 밑에 5개의 변수가 있습니다. 메세지를 전송할때 처리해야 되는 값을 arg1,arg2,obj에 넣어서 sendMessage(msg)함수를 이용해 보내는 것입니다.
저는 receiverstr (String형)를 변수 내용을 Object 인객체 변수인 obj에 넣었습니다.
arg1,arg2는 int형만 쓸 수 있기 때문에 ,다른 자료형은 obj에 넣어 주는것 입니다.
그림3

Message의 매개변수

 
 
2)post함수
 
 
post함수는 간단히 핸들러에서 처리 해야 될때 사용 할 수 있습니다.
이것은 new Runnable()의 run()을 이용하여 사용 됩니다.
그러면 구지 sendMessage()함수를 쓰지않아도 run()함수 내에서 처리 할 수 있습니다.
 
그림에 적혀 있는 mHandler와 tv.setText 는 매인 에서 스레드 생성시 넘겨주는 변수 입니다.
 
매개변수를 넘겨주는 부분만 먼저 보여드리겠습니다.
메인 에서 스레드 생성 및 시작할 때 넘겨주는 부분 입니다.
밑에 그림에 나와있는 mhandler는 메인 클래스 에서 생성된 변수 입니다. 즉
첫 번째 그림에 나와있는 변수 mhandler입니다.
 
밑에 그림은 수신하는 클래스 에서 선언된 부분 입니다.
메인클래스의 mhandler을 this.mhandler = handler 에서 넣어 줍니다.

출처: http://itnhappy.tistory.com/29 [즐거운 IT 연구개발을 위해]

안드로이드 pendingIntent에 대해

출처 : https://www.androidpub.com/262461
PendingIntent 는 특정 Component(Activity / Service 등) 가 Intent 를 생성한 후, 해당 Intent 를 바로 사용하는 대신, 나 대신 다른 Component 가 해당 Intent 를 사용 할 수 있도록 할 때 사용하는 클래스입니다.

PendingIntent.getActivity 는 PendingIntent 를 만드는 팩토리 함수입니다. PendingIntent 가 Send 될 때, startActivtiy API 가 호출되는 PendingIntent 를 만들어 줍니다. 보다 자세한 내용은 안드로이드 개발자 사이트를 참조하셔도 좋고, 제가 개인적으로 블로그에 정리한 내용을 참고 하셔도 약간의 도움은 될 듯 합니다.

한가지 추가로 pendingintent 를 실행해주는 다른 component 가 그 intent 를 실행할때는 최초에 그 pendingintent 를 만든 component 가 갖고있는 권한으로 (각종 permission, 등) 실행됩니다.