2013.05.05 13:27

ViewPager 관련으로 프로그램을 짜고 있다가 


갤노트2에서는 잘되던게 옵티머스G 프로에만 가면 


Fatal signal 11 (SIGSEGV) at 0x00000008 (code=1) thread xxxxx~


이런 에러를 뱉으며 죽더군요. 충격과 공포에 빠지면 헬지를 욕했지만 


해결책은 꽤나 간단한 곳에 있었습니다.


해당 Activity가 정의된 AndroidManifest.xml에


android:hardwareAccelerated="false" 속성을 넣어주기만 하면 됩니다.


하드웨어가속 이놈 이거 한두가지로 속썩이는게 아닙니다. 이것뿐만 아니라 동영상 관련쪽에서도 문제였고..


아무튼~ 고생하시지 말고 android:hardwareAccelerated="false" 이걸로 간단하게 해결보세요~



신고
Posted by 그린블로그 DEV그린
2012.12.20 08:56


DEL_SVN.BAT


첨부한 DEL_SVN.BAT를 다운받고 


.svn이 존재하는 프로젝트 폴더 안에 집어넣습니다.


그리고 실행.


그러면 알아서 .svn을 제거해줍니다. 


참 쉽죠?



신고
Posted by 그린블로그 DEV그린
2012.11.19 17:27

res 폴더 안에 color 폴더를 만들고 clickable_words.xml 을 만듭니다.

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

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

    <item android:color="@color/white" android:state_pressed="true"/>

    <item android:color="@color/gray" />

</selector> 


그 후 selector를 적용할 폴더에 다음과 같이 선언합니다.

<Button

        android:id="@+id/btn"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:textColor="@color/clickable_words"

        android:textColorHighlight="@color/clickable_words"

        android:textColorLink="@color/clickable_words"

        android:text="테스트"

        android:textSize="16dip" /> 


세팅이 끝나고 버튼을 클릭해 보면 누르고 있을 때 텍스트가 흰색으로 변하고 떼었을 때는 회색으로 변하는 것을 볼 수 있습니다.



신고
Posted by 그린블로그 DEV그린
2012.11.15 20:56

String str = "aa:aa";


에서 : 만 잘라내고 싶은 경우


str.replaceAll(":", ""); 가 아니라


str = str.replaceAll(":", ""); 을 쳐야 제대로 적용됩니다. ^^


오즈모바일로 출발!

신고
Posted by 그린블로그 DEV그린
2012.11.07 17:01

핵심은 이곳을 참조하시고..~

http://blog.svpino.com/2011/08/disabling-pagingswiping-on-android.html


일단 ViewPager를 상속받은 유틸 클래스를 만들어줍니다.

import java.io.PrintWriter;

import java.io.StringWriter;


import android.content.Context;

import android.support.v4.view.ViewPager;

import android.util.AttributeSet;

import android.util.Log;

import android.view.MotionEvent;



//스크롤 막는 ViewPager

public class CustomViewPager extends ViewPager {


private boolean enabled; //이 것이 스크롤을 막아주는 중요 변수!


public CustomViewPager(Context context, AttributeSet attrs) {

super(context, attrs);

this.enabled = true;

}


@Override

public boolean onTouchEvent(MotionEvent event) {

try {

if (this.enabled) {

// Log.i("INFO", "스크롤 중..");

return super.onTouchEvent(event);

}

catch (Exception e) {

StringWriter sw = new StringWriter();

        e.printStackTrace(new PrintWriter(sw));

        String exceptionAsStrting = sw.toString();

        Log.e("INFO", exceptionAsStrting);

}



return false;

}


@Override

public boolean onInterceptTouchEvent(MotionEvent event) {

if (this.enabled) {

return super.onInterceptTouchEvent(event);

}


return false;

}


public void setPagingEnabled() { //이 메소드를 이용해서 스크롤을 풀어주고

this.enabled = true;

}


public void setPagingDisabled() { //이 메소드를 이용해서 스크롤을 막아줍니다.

this.enabled = false;

}


} 


선언이 끝났으면 실제 소스에 반영합니다.

예를 들어 다음 페이지로 스크롤 할 때 스크롤이 다 끝날 때 까지는 스크롤을 막아주기 위해 유틸 클래스에서 정의한 메소드를 이용해서 처리해줍니다.

     private void nextPage(){

  

      vp_main.setPagingDisabled();

      

      Handler handler = new Handler(){

  public void handleMessage(Message msg){

  vp_main.setPagingEnabled();

vp_main.getAdapter().notifyDataSetChanged();

  }

  };

  handler.sendEmptyMessageDelayed(0, 400);   

     } 




신고
Posted by 그린블로그 DEV그린
2012.11.07 16:56

스마트폰의 뒤로가기 키를 눌렀을 때 웹뷰에서 goBack() 할 수 있을 때 까진 goBack()을 해주고

아니라면 finish(); 시켜주면 됩니다.

ifwebview.canGoBack() ) {

webview.goBack();

}

else {

finish();

}  


신고
Posted by 그린블로그 DEV그린
2012.11.01 15:24

예를들어 A, B, C Activity가 있다고 칩시다.


A에서 B로 갈 때 finish()를 하지 않고 갑니다. 


즉, 


Intent intent = new Intent(A.this, B.class);

startActivity(intent); 


startActivity(intent); 만 이용해서 이동한 것이지요.


그렇게 B로 이동한 후 또 C로 이동합니다. 

Intent intent = new Intent(B.this, C.class);

startActivity(intent); 


이렇게 C로 이동한 후 이동 한 후 C를 종료하면서 A로 바로 이동하고 싶습니다. 그런데 A로 이동하면서 B도 끄고 싶습니다.


이런경우 보통 FLAG_ACTIVITY_CLEAR_TOP 플래그를 이용해서 이동합니다.

Intent intent = new Intent(C.this, A.class);

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

startActivity(intent); 
finish();


하지만 Activity가 많아질 경우 FLAG_ACTIVITY_CLEAR_TOP 은 더이상 통하지 않습니다.


간단하게 처리하기 위해서는 Activity를 상속받은 BaseActivity 클래스를 따로 만들어준 후 ArrayList<Activity>를 이용해서 


추가된  Activity 들을 한번에 종료시켜주는 것이 가장 확실한 방법인 것입니다. 그럼 구현 하는 방법을 알아볼까요?


BaseActivity에 ArrayList<Activity>을 선언해줍니다.

 public static ArrayList<Activity> actList = new ArrayList<Activity>();


그리고 A이동할 메소드에 해당 소스를 넣어줍니다.

actList 에 쌓인 Activity들을 for문을 돌려 모두 finish() 시켜버리는 것입니다.

for(int i = 0; i < actList.size(); i++)

actList.get(i).finish();

intent = new Intent(C.this, A.class);

startActivity(intent);

finish(); 


이렇게만 해주면 제대로 동작하지 않습니다.

목적은 C와 A 사이에 있는 B를 제거하기 위함이므로 B를 actList 에 추가해줍니다.

onCreate()에서 추가해주면 됩니다.

//일단 B를 상속받고... 
public class B extends BaseActivity{


@Override

protected void onCreate(Bundle savedInstanceState) {

actList.add(this); // actList에 B를 추가해줍니다.

super.onCreate(savedInstanceState);

setContentView(R.layout.b);


}


}


이렇게 만들어 놓고 필요시 for문을 돌려 Activity들을 언제든지 삭제할 수 있는 것입니다. ^^



신고
Posted by 그린블로그 DEV그린
2012.10.22 13:54

키보드에서 특정 키를 꾹 누르고 있으면 그 키에 해당하는 문자가 계속 타이핑 되듯이 

안드로이드에서도 특정 버튼을 누르면 어떠한 액션이 반복적으로 실행되는 리스너를 찾아보았습니다. 


원본 링크 : http://stackoverflow.com/questions/4284224/android-hold-button-to-repeat-action


이곳에 보면 버튼 반복 방법이 두가지 나오는데요, 첫번째 보다 두번째 방식이 더 간결하고 쓰기 좋습니다.

(첫번째 방법은 버튼 셀렉터 먹이기가 힘들더군요 ㅇㅁㅇ;)


일단 RepeatListener.java 를 생성합니다.

import android.os.Handler;

import android.view.MotionEvent;

import android.view.View;

import android.view.View.OnClickListener;

import android.view.View.OnTouchListener;


/**

 * A class, that can be used as a TouchListener on any view (e.g. a Button).

 * It cyclically runs a clickListener, emulating keyboard-like behaviour. First

 * click is fired immediately, next after initialInterval, and subsequent after

 * normalInterval.

 *

 * <p>Interval is scheduled after the onClick completes, so it has to run fast.

 * If it runs slow, it does not generate skipped onClicks.

 */

public class RepeatListener implements OnTouchListener {


    private Handler handler = new Handler();


    private int initialInterval;

    private final int normalInterval;

    private final OnClickListener clickListener;


    private Runnable handlerRunnable = new Runnable() {

        @Override

        public void run() {

            handler.postDelayed(thisnormalInterval);

            clickListener.onClick(downView);

        }

    };


    private View downView;


    /**

     @param initialInterval The interval after first click event

     @param normalInterval The interval after second and subsequent click 

     *       events

     @param clickListener The OnClickListener, that will be called

     *       periodically

     */

    public RepeatListener(int initialInterval, int normalInterval, 

            OnClickListener clickListener) {

        if (clickListener == null)

            throw new IllegalArgumentException("null runnable");

        if (initialInterval < 0 || normalInterval < 0)

            throw new IllegalArgumentException("negative interval");


        this.initialInterval = initialInterval;

        this.normalInterval = normalInterval;

        this.clickListener = clickListener;

    }


    public boolean onTouch(View view, MotionEvent motionEvent) {

        switch (motionEvent.getAction()) {

        case MotionEvent.ACTION_DOWN:

            handler.removeCallbacks(handlerRunnable);

            handler.postDelayed(handlerRunnableinitialInterval);

            downView = view;

            clickListener.onClick(view);

            break;

        case MotionEvent.ACTION_UP:

            handler.removeCallbacks(handlerRunnable);

            downView = null;

            break;

        case MotionEvent.ACTION_CANCEL:

            handler.removeCallbacks(handlerRunnable);

            downView = null;

            break;

        }

        return false;

    }


} 


그후 onCreate()에 Button 리스너를 줍니다.

 ((Button)findViewById(R.id.btn)).setOnTouchListener(new RepeatListener(400, 50, new OnClickListener() {

  @Override

  public void onClick(View view) {

  //할 것!!

  }

}));

여기서 400은 처음 터치한 후 반복이 실행되기 까지의 대기시간, 50은 반복속도입니다. 자유롭게 주셔도 됩니다.



신고
Posted by 그린블로그 DEV그린
2012.10.22 12:27

다이얼로그를 띄워 전화번호에 autoLink를 걸었는데 


Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?


라는 에러가 뜬다면 다이얼로그 부분에서 


getApplicationContext()로 선언하지 않았는지 확인합니다.


만약 그렇게 되어있다면 클래스이름.this 로 바꿔주고 테스트하면 정상적으로 작동합니다.



신고
Posted by 그린블로그 DEV그린
2012.10.15 23:24

젤리빈을 업데이트 하면서 갑작스럽게 웹뷰에서 openFileChooser가 먹지 않는 현상이 발생하였습니다.



아이스크림 버전까지는 이렇게 해서 잘 썼지만

 public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType) {

openFileChooser(uploadFile);

}

 

public void openFileChooser(ValueCallback<Uri> uploadMsg) {

uploadMessage = uploadMsg;

Intent i = new Intent(Intent.ACTION_GET_CONTENT);

i.addCategory(Intent.CATEGORY_OPENABLE);

i.setType("image/*");

startActivityForResult(Intent.createChooser(i, "이미지 첨부"),FILECHOOSER_RESULTCODE);

}


젤리빈부터는 아래와 같이 붉은 색으로 표기한 메소드를 추가해주어야 제대로 읽어옵니다~

 public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType) {

openFileChooser(uploadFile);

}

 

public void openFileChooser(ValueCallback<Uri> uploadMsg) {

uploadMessage = uploadMsg;

Intent i = new Intent(Intent.ACTION_GET_CONTENT);

i.addCategory(Intent.CATEGORY_OPENABLE);

i.setType("image/*");

startActivityForResult(Intent.createChooser(i, "이미지 첨부"),FILECHOOSER_RESULTCODE);

}


public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {

       openFileChooser( uploadMsg, "" );

   }




신고
Posted by 그린블로그 DEV그린
2012.09.27 11:41

맥에서 갑자기 certificate 관련으로 svn 체크아웃이 안되는 경우가 있습니다.


이럴 때는 터미널로 들어가서 다음과 같이 설정해줍니다.


svn ls svs체크아웃주소


Password for 'neoroid': 맥 비번


Username: svn에 등록한 ID
Password for 'ID': svn ID에 등록한 패스워드


그리고 아무런 로그 없이 다음 커맨드가 출력되면 해결된겁니다.

확인은

svn ls svs체크아웃주소

이걸로 다시 해보세요~ ^^


신고
Posted by 그린블로그 DEV그린
2012.09.26 15:19

저번 시간에 Json의 키값과 밸류값을 Map에 집어넣는 방법을 알아보았는데요~


정작 Map을 쓰려면 for문으로 작업해야 하는데 웬만하면 map.get(i)로 계산 했기 때문에


Map의 key값이 String형인 경우 for문을 돌리기가 쉽지 않습니다.


그럴 경우 Iterator 를 사용해서 돌리면 됩니다. ^^


 

Iterator<String> iterator = map.keySet().iterator();

    while (iterator.hasNext()) {

        String key = (String) iterator.next();      

        Log.i("INFO", "key : "+key);

        Log.i("INFO", "value"+map.get(key));

    }




신고
Posted by 그린블로그 DEV그린
2012.09.26 14:43

Json을 받아 Map으로 집어넣는 방법입니다.


중요 포인트는 Json의 키 값까지 Map에 담는 것인데요, Json의 키 값은 names() 메소드로 구합니다. ^^



TreeMap<String,String> map = new TreeMap<String,String>();

JSONArray json null;

String jsonString "";


.

...

.......


//Json String을 받는 과정은 생략 후 받았다 치고 Map으로 넣는 과정을 설명합니다.

 json = new JSONArray(jsonString);

        

 JSONObject resultObject = json.getJSONObject(0);

 for (int j = 0; j < resultObject.length(); j++) { //Json의 Object 숫자만큼 for문을 돌립니다.

     //Json의 키와 밸류 값을 맵에 집어넣습니다.

     map.put(resultObject.names().getString(j), resultObject.getString(resultObject.names().getString(j)));

}



신고
Posted by 그린블로그 DEV그린
2012.09.13 17:20

float 형태의 변수를 int형으로 명시하면 자연스럽게 소수점이 버려집니다.


 float a = 1.23456


int b = (int) a ;


//결과값 b = 1


끝!




신고
Posted by 그린블로그 DEV그린
2012.08.27 10:29

map을 만들고 add하고 


map.get(i)로 돌리는데 i에 해당하는 키 값을 이미 지웠다면?! 


map.ceilingKey(i)를 이용하면 됩니다. 즉


map에 키와 밸류값을 추가한 뒤 로그를 찍었을 때


{0=1, 1=2, 2=3} 에서 


키값 1번을 지우면


{0=1, 2=3} 이 됩니다.


여기서 for문으로 map을 돌려버리면 


map.get(i)에서 i가 1일 때 NullPointException이 발생하게 됩니다.


이럴때 


if(map.get(i) == null){

   i = map.ceilingKey(i);

}


를 넣어주면 i는 2로 바뀌어 계산됩니다.



신고
Posted by 그린블로그 DEV그린
2012.08.24 17:45

아래와 같은 메소드를 선언합니다.

public static <K, V extends Comparable<V>> Map<K, V> sortByValues(final Map<K, V> map) {

Comparator<K> valueComparator =  new Comparator<K>() {

    public int compare(K k1, K k2) {

        int compare = map.get(k2).compareTo(map.get(k1));

        if (compare == 0) return 1;

        else return compare;

    }

};

Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);

sortedByValues.putAll(map);

return sortedByValues;

}


클래스에 맵을 선언하고

TreeMap<Integer,Integer> map = new TreeMap<Integer,Integer>(); 


아래와 같이 사용합니다.

Log.i("INFO", "map : "+sortByValues(map)); 



신고
Posted by 그린블로그 DEV그린
2012.08.07 08:57

* DIP 값으로 Pixel 값 얻기

 private static float displayDensity = -1f;

  private static final float DEFAULT_HDIP_DENSITY_SCALE = 1.5f;


  public int getPixelByDIP(int dip)

  {

  if(displayDensity==-1f)

  displayDensity = this.getResources().getDisplayMetrics().density;


  return (int)(dip / displayDensity * DEFAULT_HDIP_DENSITY_SCALE+0.5);

  }



신고
Posted by 그린블로그 DEV그린
2012.08.03 10:09

크롬브라우저나 인터넷 익스플로러에서 당연히 쓰이던 width=100%가 안드로이드 WebView에서는 먹히지 않습니다.


해결책은 의외로 간단합니다.


 <img src="yourImage.png" width='100%25' />


원인은 %를 제대로 인식하지 못해서 에러가 나는거였는데요.


%는 %25로 해야 제대로된 문자열 '%'로 인식합니다.


http://www.hypergurl.com/urlencode.html 


이곳에 가면 자동으로 encode, decode 해주는 프로그램이 있습니다.



아까 언급한 사이트로 접속 후 변환하고자 하는 문자열을 쓰고 밑의 Encode버튼을 누르면 자동으로 인코딩 되어 'URL encoded text에 나타납니다.



신고
Posted by 그린블로그 DEV그린
2012.08.01 17:15

* 폰인지 태블릿인지 판별하는 메소드

 static boolean isTablet (Context context) { 

        // TODO: This hacky stuff goes away when we allow users to target devices 

        int xlargeBit = 4; // Configuration.SCREENLAYOUT_SIZE_XLARGE;  // upgrade to HC SDK to get this 

        Configuration config = context.getResources().getConfiguration(); 

        return (config.screenLayout & xlargeBit) == xlargeBit; 

    } 


* 실제 사용

  if(isTablet(this)){

   //TODO 태블릿일 때 적용할 소스

  }



신고
Posted by 그린블로그 DEV그린
2012.07.26 09:00

AsyncTask의 doInBackground에서 통신중에 try catch의 catch에 Toast를 쓰지 말 것.


에러가 난다.


그러므로 catch에서는 전역으로 선언해둔 boolean 값을 false로 먹여놓고 


catch로 넘어올 때 true로 바꾼 다음 


onPostExecute에서 비로소 띄워주는 것이 좋다.


다이얼로그도 마찬가지.


doInBackground에서 조건에 맞춰 다이얼로그를 뜨게 한다음 return을 먹였으나 작동하지 않았다 


그래서 다이얼로그도 같은 방식으로 onPostExecute로 옮긴 결과 제대로 실행이 되었다.


신고
Posted by 그린블로그 DEV그린