출처 : http://nlopez.io/how-to-style-the-actionbar-searchview-programmatically/

I stumbled upon a problem with the styling of a view at work. I had almost everything solved with a custom theme, but it all came down to style a SearchView widget of an ActionBar.

The unstyled version

That's where the fun begins.

All of this must happen in your onCreateOptionsMenu method. With a reference to your SearchView object in there, you can start doing things.

For example, if you'd like to get a reference to its EditText, you could do it using reflection like in this snippet.

int searchSrcTextId = getResources().getIdentifier("android:id/search_src_text", null, null);  
EditText searchEditText = (EditText) searchView.findViewById(searchSrcTextId);  
searchEditText.setTextColor(Color.WHITE);  
searchEditText.setHintTextColor(Color.LTGRAY);  

For changing the close icon, this one.

int closeButtonId = getResources().getIdentifier("android:id/search_close_btn", null, null);  
ImageView closeButtonImage = (ImageView) searchView.findViewById(closeButtonId);  
closeButtonImage.setImageResource(R.drawable.ic_action_cancel);  

And so on. You can get all the references in either the Android code for SearchView.java, or in its layout. For the lazy ones, here are some of those references that you can retrieve (and play with).

// This excerpt is from Android source code (SearchView.java)
mSearchButton = findViewById(R.id.search_button);  
mSearchEditFrame = findViewById(R.id.search_edit_frame);  
mSearchPlate = findViewById(R.id.search_plate);  
mSubmitArea = findViewById(R.id.submit_area);  
mSubmitButton = findViewById(R.id.search_go_btn);  
mCloseButton = (ImageView) findViewById(R.id.search_close_btn);  
mVoiceButton = findViewById(R.id.search_voice_btn);  
mSearchHintIcon = (ImageView) findViewById(R.id.search_mag_icon);  

But as you probably can see in Android's code, you have no direct access to the SearchAutoComplete class. The problem with that is that it's difficult to you to be able to style the magnifying glass next to the hint text.

You can set up with searchView.setQueryHint("your hint") its hint and you can hide it with searchView.setIconifiedByDefault(false) - though that's even worse because then the search icon is at the left of the EditText and it looks ugly.

The ugly version

The thing is, that icon at the left of the hint text is done in Android by using an ImageSpan in a SpannableString, and it depends directly on the theme applied to the control. But what happens if you can't change the theme? (like in my case). Then you have to do more dirty and ugly stuff.

// Accessing the SearchAutoComplete
int queryTextViewId = getResources().getIdentifier("android:id/search_src_text", null, null);  
View autoComplete = searchView.findViewById(queryTextViewId);

Class<?> clazz = Class.forName("android.widget.SearchView$SearchAutoComplete");

SpannableStringBuilder stopHint = new SpannableStringBuilder("   ");  
stopHint.append(getString(R.string.your_new_text));

// Add the icon as an spannable
Drawable searchIcon = getResources().getDrawable(R.drawable.ic_action_search);  
Method textSizeMethod = clazz.getMethod("getTextSize");  
Float rawTextSize = (Float)textSizeMethod.invoke(autoComplete);  
int textSize = (int) (rawTextSize * 1.25);  
searchIcon.setBounds(0, 0, textSize, textSize);  
stopHint.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

// Set the new hint text
Method setHintMethod = clazz.getMethod("setHint", CharSequence.class);  
setHintMethod.invoke(autoComplete, stopHint);

And that's it. Ugly and hacky as promised.

Styled, finally!

But works!

앞페이지에서 옵션메뉴를 하였다
옵션메뉴는 전화기의 하단 왼쪽 화면 밖을 크릭하면 나타나는 것
프로그램들 마다 다양한 형식의 메뉴시스템을 제공하듯이
안드로이드에는 이것만 있는 것이 아니고
윈도우시스템의 상단 메뉴줄과 같은 것도 있을 것이다
이것을 Action Bar라고 부른다
이번 페이지에서는 Action Bar에 앞의 페이지에서 만든 것을
옮겨 보자
아주 간단하다

&lt;?xml version="1.0" encoding="utf-8"?&gt; &lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt; &lt;item android:id="@+id/menu_calculator" android:title="Calculator" /&gt; &lt;item android:id="@+id/menu_news" android:title="News" /&gt; &lt;item android:id="@+id/menu_search" android:title="Search" /&gt; &lt;item android:id="@+id/menu_location" android:title="Location" /&gt; &lt;item android:id="@+id/menu_alarm" android:title="Alarm" /&gt; &lt;item android:id="@+id/menu_google_play" android:showAsAction="ifRoom|withText" android:title="GooglePlay" /&gt; &lt;/menu&gt; 위의 메뉴를 구성하는 xml화일을 Activity 크래스의 아래 메소드에서 불러 들여서 옵션메뉴를 설치하였던 것이다 public boolean onCreateOptionsMenu(Menu menu) { MenuInflater menuInflater = getMenuInflater(); menuInflater.inflate(R.menu.activity_main, menu); return true; }

Action Bar로 옵션메뉴의 내용을 옮겨본다면 위에서 마지막 메뉴
GooglePlay라는 곳에 

android:showAsAction="ifRoom|withText"

한줄 삽입하면 해당 메뉴는 Action Bar로 옮겨진다
앞페이지 쏘스에 위와 같이 한줄만 달랑 바꾸고 실행시켜보시면
화면상단 타이틀바에 메뉴가 나타남을 볼수 있을 것이다

그런데 Action Bar에 메뉴아이템 6개 전부에

android:showAsAction="ifRoom|withText"

와 같은 속성(Attribute)을 준다면 
Action Bar의 공간이 좁다..그래서 공간이 되는 만큼만 Action Bar에
메뉴가 나타나고, 나머지는 Option Menu공간에 그대로 남게 된다
말그대로 이다
"ifRoom|withText"라는 속성값은
If 만약에 Room 공간이 있다면 문자로 표현한다 with Text 인것이다
그래서 아래와 같이 menu.xml 화일의 내용을 표현하였다면


그림과 같이 Action Bar와 Option Menu로 분배되어 표현된다
그래서 메뉴공간을 활용하기 위하여 Text로 표현하는 것 보다는
Icon 으로 표현하면 좁은 공간에 많은 메뉴를 표현할수 있을 것이다

조그만 화면에 표현을 하기 위하여서는 그림으로 표현하는 것이 바람직하다
그래픽의 폴더가 몇가지의 성격은 아래와 같다



작은 그림 Icon을 넣고 싶다면 아래와 같이 속성을 넣는다

&lt;item android:id="@+id/menu_calculator" android:showAsAction="ifRoom|withText" android:icon="@drawable/ic_action_calculator" android:title="calculator" /&gt;

아래와 같이 태그내의 속성에 icon속성을 넣는 것이다

android:icon="@drawable/ic_action_calculator"
이때..drawable은 위의 그림의 폴더중에 drawable_ldpi,drawable_mdpi,,,,폴더
내에서 아무것이나 화일이름이 ic_action_calculator.jpg 인것을 찾아서
올리게 되는 것이다
이때...좀더 정교하게 설계를 한다면 위의 각 폴더별 icon해상도에
맞추어 넣어주면 가장적절한 해상도의 것을 알아서 찾아
올리게 되는 것이다
해상도가 맞지 않도라고 같은 화일이 다른 해상도에 있다면
이것을 갖여다 사용하고..

이 아이콘을 죄다 만들어야 하나..
Google에서 다운 받으면 기본적인 것들이 만들어져 있으니 활용하면 된다

다운 받으면 아래와 같이 좋은 자료가 된다



위의 그림을 안드로이드프로젝트의 해상도에 맞는 홀더에
넣어주고..menu.xml에서 속성으로 어떤 그림을 사용하겠다고 지정하고
Activity크래스가 실행되면서 이 menu.xml화일을 읽어서
화면에 아래의 그림과 같이 Action Bar에 배치해주게 되는 것이다



Action Bar바탕색이 검정색이니까..이때 아이콘은 검정색의 외의 것으로
사용하여야 나타날 것이다

어라...그런데 Option Menu의 6개의 메뉴를 모두 아이콘으로
만들어 Action Bar에 올리려고 하는데
반만 올라가고 나머지는 여전히 Option Menu에 남아있다
아래의 그림의 맨마지막과 같이 하고 싶다



public class MainActivity extends Activity { 
   public void onCreate(Bundle savedInstanceState) { 
       super.onCreate(savedInstanceState); 
       setContentView(R.layout.activity_main); 

       	ActionBar actionBar = getActionBar();
   		actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM
   				| ActionBar.NAVIGATION_MODE_STANDARD);
       
       
       
   } 

Activity(화면)개체가 생성되면 OnCrete메소드에서
ActionBar개체를 찾아서
setDisplayOptions에 위와 같이 설정하면 App Icon과
App Title이 사라진다
그러면 Action Bar폭에 여유가 생겨서 많은 사용자정의
메뉴를 삽입하게 되는 것
그리고 menu.xml화일에서 각 menu Item의 속성을
android:showAsAction="ifRoom" 혹은 
adnroid:showAsAction="ifRoom|withText" 을
withText라는 값은 만약 여러분이 옵션메뉴에 만든
메뉴아이템에 Title이 있을 경우 Title도 아이콘과 같이
Action Bar에 나타나게 해주는 것
여기에서는 아이콘만 나타나게 하였으므로 "ifRoom"만 주면 된다
아래와 같이 바꿔준다
android:showAsAction="always"
위의 layout xml 화일에서 속성을 줄때 ="값_A|값_B|값_C"와 같이
|로 나누어서 여러개의 값을 전달하는 문법
Java코드에서도

actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM
     | ActionBar.NAVIGATION_MODE_STANDARD);

와 같이 여러개의 값을 전달 하는 문법을 잘 챙기시고..

***[LOG-IN]***

출처 : http://bugnote.tistory.com/2


안드로이드 프로그래밍을 하던 중 사용자와 사용자간의 거리를 계산해야 할 일이 생겼다.

각 사용자의 위치는 위도와 경도로 알고 있기 때문에 아래 공식을 이용하여 적용했다.

좌표 1(위도,경도)과 좌표 2(위도,경도) 거리 계산 방법

sLat,sLng 는 좌표1(로그인한 사용자)의 위도, 경도 값이다.

double sLat = Double.valueOf(LoginUser.item.lat);
double sLng = Double.valueOf(LoginUser.item.lng);

eLat, eLng는 대상(target)의 위도,경도 값이다.
double eLat = Double.valueOf(item.lat);
double eLng = Double.valueOf(item.lng);

String distance = SocialUtil.calcDistance(sLat, sLng, eLat, eLng);
distanceStr = "● 나와  " + distance +" 거리에 있습니다.";

거리를 구한다음 textview에 표시를 해준다.

socialtxt.setText(distanceStr);

삼각함수를 이용하여 사용자간의 거리를 구하는 핵심 공식은 아래와 같다.

SocialUtil.calcDistance

    public static String calcDistance(double lat1, double lon1, double lat2, double lon2){
     double EARTH_R, Rad, radLat1, radLat2, radDist; 
     double distance, ret;

        EARTH_R = 6371000.0;
        Rad = Math.PI/180;
        radLat1 = Rad * lat1;
        radLat2 = Rad * lat2;
        radDist = Rad * (lon1 - lon2);
        
        distance = Math.sin(radLat1) * Math.sin(radLat2);
        distance = distance + Math.cos(radLat1) * Math.cos(radLat2) * Math.cos(radDist);
        ret = EARTH_R * Math.acos(distance);

        double rslt = Math.round(Math.round(ret) / 1000);
        String result = rslt + " km";
        if(rslt == 0) result = Math.round(ret) +" m";
        
        return result;
    } 

결과 화면은 아래와 같다

출처 :  http://ncube.net/7388

이번에 작업 중인 사이트.. 수시로 정책이 바뀌어서 고생하고 있는.. 사이트에서 반경을 이용한 업체 검색 기능이 필요해서 구글링 좀 하고 잔머리를 좀 굴려서 원하는 기능을 구현했다. 각 지점의 경도와 위도는 네이버 지도API를 이용해 얻어온다. 그런 다음 경도 위도를 DB에 저장하고 Query를 이용해 기준 반경 내 업체를 구하는 식이다.

1. 네이버 지도 API에서 경도, 위도 받아오기
우선 네이버 지도 API를 이용하기 위해서는 Key를 등록해야 한다. http://dev.naver.com/openapi/register 에 접속한다. 로그인이 되어야 정상적으로 이용할 수 있다. 그런 다음 아래 화면처럼 지도키 발급에서 사이트 주소를 입력하고 키를 발급받도록 한다.

그런 다음 경도 위도를 확인하기 위해서 아래 주소로 접속한다. test_key 부분은 위에서 발급 받은 키로 변경한다. 좌표확인URL은 아래와 같다.

더 자세한 사용법은 http://dev.naver.com/openapi/apis/map/javascript_2_0/reference#CT_URL 에서 확인 가능.

아래는 결과 화면이다.

결과는 XML 포맷으로 전달되는 데 x, y 값이 우리가 원하는 값이다. XML 파싱 부분은 검색을 통해서.. ^^;

간단히 내가 사용한 XML Parser는 http://www.criticaldevelopment.net/xml/ 에서 얻을 수 있으며 파서 파일을 PHP 파일에 include 한 후 아래 코드를 이용해 XML에서 좌표를 얻어낸다.

test_key 부분은 위에서 발급받은 키로 변경해야 한다. 그리고 php 파일이 위치한 서버의 도메인과 발급받은 키의 도메인이 일치하지 않으면 실행되지 않는다. www가 붙은 도메인과 붙지 않은 도메인은 서로 다르게 인식되는 듯 하다.

2. MySQL Query를 이용해 기준 반경내 업체 검색
우선 경도 위도를 저장할 필드를 추가해줘야 한다. DATA 타입은 아래와 같이 하면 된다. 필드 명은 적당히 변경.

이제 기준점 (127.0000000, 37.0000000)에서 DB에 저장된 지점의 거리를 계산하는 Query를 작성해보자.

위의 쿼리는 TEST_TABLE에서 기준점에서 반경 5Km 이내의 id를 거리가 가까운 순서로 5개 가져오는 것이다.

참고 : http://code.google.com/intl/ko/apis/maps/articles/phpsqlsearch_v3.html

결과 값이 얻어지면 이제 원하는 기능을 하도록 코드를 작성하면 된다

출처 : http://blog.naver.com/blow1/150106632098


해당 위도와 경도가  주어진 구역반경에 들어오는지 체크 한다.

 

아래는 위,경도를 통한 도분초를 계산하는 방법이며 마지막에 실제 함수를 작성하였다.

 

구글 거리계산기와 아래 함수를 비교하여 보니 정확한 계산치를 확인 할 수 있었다.

 

하지만, 아래 계산법은 우리 나라에 한해서만 적용되어야 할 듯 하다.( 서핑 하다 보니 이러저러한 이유로 지구 전체에 대한 것은 좀더 상세한 계산법이 필요 할 듯 하다)


 lat : 위도 , lon: 경도.

 

 ex>35.3036944

 도 : 35
 분 : 0.3036944 * 60 : int : 18
 초 : (0.3036944 * 60 - 18)*60 : 13.3

 35도 18분 13.3초


  A 지점 : 동경 127도 30분 20초    북위 : 36도 27분 08초 
  B 지점 : 동경 127도 29분 30초    북위 : 36도 28분 00초 
  C 지점 : 경도  00도   1분 10초    위도 : 00도 01분 08초

  경도간 거리 : 0도*88.8 +  1분 * 1.48 + 10초 * 0.025 = 1.73km
  위도간 거리 : 0도*111  +  1분 * 1.85 +   8초 * 0.031 = 2.10km

  두지점간 거리 : 루트 (1.73^2 + 2.10^2) = 2.72km

 

#define DIV_VALUE    10000000

 

int distanceCmp(unsigned int lat1, // 기준 위도,

unsigned int lon1, // 기준 경도,

unsigned int lat2,  // 대상 위도,

unsigned int lon2,  // 대상 경도

unsigned int nCmpLat, // 위도간 거리

unsigned int nCmpLon // 경도간 거리

)

{

/*

위도,경도에 대한 절대값 계산

*/
 double lon = lon1 > lon2  ? (lon1 - lon2)/(double)DIV_VALUE   : (lon2-lon1)/(double)DIV_VALUE;
 double lat =  lat1 > lat2  ? (lat1 - lat2)/(double)DIV_VALUE   : (lat2-lat1)/(double)DIV_VALUE;

 

/*

경도에 대한 도분초및 거리 계산

*/
 int rad = (int)lon;
 int min = (lon-rad)*60;
 double sec = ((lon-rad)*60 - min)*60;
 unsigned int lon_dist, lat_dist;

 lon_dist = ((rad * 88.8) + (min*1.48) + (sec*0.025)) * 1000; // m단위

 

/*

위도에 대한 도분초및 거리 계산

*/

 rad = (int)lat;
 min = (lat-rad)*60;
 sec = ((lat-rad)*60 - min)*60;

 lat_dist = ((rad * 111) + (min*1.85) + (sec*0.031)) * 1000; // m단위

 

 if( nCmpLat == 0 ){ // 원 형태의 구역반경

 // 직선거리만을 조건으로 한다.
  int realDist = sqrt((lon_dist*lon_dist)+(lat_dist*lat_dist));

  if( nCmpLon >= realDist ){
   return 1;
  }
 }else if( nCmpLat >= lat_dist && nCmpLon >= lon_dist ){ // 사각 형태의 구역반경

// 종/횡측 거리안에 들어오는지 확인한다.
  return 1;
 }
  
 return 0;
}


출처 : http://ggari.tistory.com/229


안드로이드 스튜디오와 이클립스디벨로퍼 등 툴이 많이 있다. 기존 이클립스 사용자가 intellij 기반인 스튜디오를 쓰기에는 조금 힘든점이있다. 


개발할때 이클립스가 단축키및 UI 등이 이미 몸에 익어있어 편한게 사실임 나만 그런가 ....

하지만 스튜디오를 사용하면 XML 화면단 레이아웃을 만드는데 있어서는 기가 막히게 좋다. 나는 그래서 이클립스와 스튜디오를 켜놓고 레이아웃을 작업할때는 스튜디오를 쓰는 편이다..... 하지만 그것도 불편하다... 여러모드를 찾다가 발견~


1. 일단 File -> Settings를 선택 합니다.




2. IDE Settings 부분에서 Keymap 부분을 클릭해주세요.




3. 그럼 아래와 같이 Keymaps 부분에서 Eclipse 를 선택 할수 있는 부분이 나옵니다.



그럼  완벽하지는 않지만 이클립스와 동일한 단축키를 쓸 수 있습니다.  스튜디오를 이제 조금더 친해저보세요 ㅋㅋ




끝~~

출처 : http://messi.adnaru.com/guide/guide04.html


튜토리얼 결과물 소개

 

튜토리얼의 최종 결과물입니다. 휴대전화를 사용하고 있는 사용자의 위치 주변에 치킨, 중국집, 보쌈, 피자등의 배달 음식점을 찾아주는 애플리케이션입니다. 이 튜토리얼은 다음 좌표계변환 API를 이용해 GPS 위도,경도정보를 주소 정보로 변환한 후에, 네이버 지역정보 API를 통해 주변 배달 음식점 정보를 받아오게 됩니다. 두개의 API를 매쉬업해 주변 배달 음식을 찾는 앱을 만드는 가이드를 따라해봅시다.


가이드를 시작하기에 앞서

주의사항: 이 과정을 꼭 거쳐주세요. 반드시 필요로하는 사항입니다

이 가이드는 Messi 라이브러리를 이용해 다음 쇼핑 API를 기반으로 최저가 검색기 앱을 만드는 가이드를 담은 문서입니다. 가이드를 진행하시기 앞서 아래의 사항들이 필요합니다.

  • ADT또는 안드로이드 스튜디오
  • Android SDK(2.2 Froyo 이상)
  • Messi 라이브러리

안드로이드를 처음 개발하는 개발자분들은, “복사-붙여넣기”코너는 그대로 소스코드를 복사해서 붙여넣으시면 편리합니다. 또한 최종적으로 개발된 코드 결과물을 압축파일로 제공하므로, 코딩하는 과정에서 어려움을 느끼신다면 해당 결과물 파일을 참고해주세요.


Open API 키 발급받기

다음 Open API

다음 DNA(http://dna.daum.net) 에서 로컬형 Open API키를 발행하여 주십시오. 기존에 발행한 키가 있다면 해당 키를 사용하셔도 무관합니다.

발행받을 키는 로컬형 key로 발행하여 주시고, 해당 key를 계속해서 사용하여야 하니 저장해두시는 편이 편리합니다.
또한 다음은 쇼핑, 검색, 컨텐츠, 로컬API키가 모두 다르므로, 특별히 유의해서 발급받아 주십시오.


네이버 Open API

네이버 개발자센터(http://developer.naver.com) 에서 Open API키를 발행하여 주십시오. 기존에 발행한 키가 있다면 해당 키를 사용하셔도 무관합니다.

발행받을 키는 검색 key로 발행하여 주시고, 해당 key를 계속해서 사용하여야 하니 저장해두시는 편이 편리합니다.


라이브러리 연동

안드로이드 프로젝트를 생성하여 주십시오. ADT혹은 안드로이드 스튜디오에서 새 프로젝트를 생성하여 주세요. 프로젝트에 설정된 SDK버전은 기존값을 따라가셔도 무관합니다.

libs에 라이브러리 넣기

해당 프로젝트의 libs 폴더에 messi.jar 파일을 끌어넣어 복사해주십시오. messi.jar 파일은 라이브러리 폴더 상단에 있습니다.


프로젝트와 라이브러리 연동

생성하신 프로젝트에서 messi 라이브러리를 사용하도록 설정하여야 합니다. ADT 기준으로 프로젝트 최상위 폴더에서 오른쪽 마우스를 누른 후 [Properties] – [Java Build path] – [Libraries]로 들어가 주십시오. 그리고 오른쪽에 있는 Add Jar을 눌러 앞서 붙여 넣기 한 라이브러리 파일을 추가해 주십시오.


권한 설정

Messi는 기본적으로 인터넷 연결 권한이 필요합니다. AndroidMenifest.xml에서 인터넷 권한을 추가해주십시오. 아울러 이 프로젝트에선 사용자의 위치정보를 가져오기 위해 위치정보를 사용할 권한과, 전화를 걸기 위한 권한이 필요합니다. 아래의 소스코드를 복사-붙여넣기 하셔도 무관합니다.

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

레이아웃 구성

이제 화면 레이아웃을 구성해 봅시다. 레이아웃 구성은 자유이지만, 가이드라인을 따라하고 싶으면 아래의 내용을 참고하셔도 좋습니다. 레이아웃 구성은 메인페이지와 각 개별 아이템구성으로 나뉘어집니다.

메인페이지

이번 튜토리얼은 각 업종별 조회 버튼과 그 목록 결과를 받아오는 ListView로 구성되어있다고 생각해봅시다. 그리고 각 버튼을 눌렀을때, Messi를 이용하여 검색 결과값을 받아오는 화면 구성으로 진행됩니다. 화면 구성은 자유자재로 바꾸시면서 진행하셔도 무관합니다.

복사-붙여넣기 할때는 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"
    tools:context="${relativePackage}.${activityClass}" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" 
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn1"
            android:layout_width="match_parent"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="치킨" />

        <Button
            android:id="@+id/btn2"
            android:layout_width="match_parent"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="중국집" />

        <Button
            android:id="@+id/btn3"
            android:layout_width="match_parent"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="피자" />

        <Button
            android:id="@+id/btn4"
            android:layout_width="match_parent"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="족발" />

    </LinearLayout>

    <ListView
        android:id="@+id/listView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </ListView>

</LinearLayout>

개별 아이템 구성

화면 구성을 모두 마쳤으면 가게별 목록 개별 아이템을 만들어봅시다. 이 가이드라인에는 가게의 이름, 주소, 전화번호 정보가 표시됩니다. 아래의 소스코드를 그대로 복사-붙여넣기 하시거나, 아니면 더 창의적이고 멋진 UI를 만드셔도 괜찮습니다. 복사-붙여넣기으로 진행하실 분들은 item_row.xml이라는 레이아웃 파일을 만드신 후 아래의 코드를 붙여넣기 해주세요.

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

    <TextView
        android:id="@+id/item_tv1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="기사 제목"
        android:layout_marginTop="10dp"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
        android:id="@+id/item_tv2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="기사 내용"
        android:layout_marginBottom="10dp"
        android:textAppearance="?android:attr/textAppearanceSmall" />

</LinearLayout>

레이아웃 구성을 마쳤으면, 이제 소스코드를 작성해봅시다. 이 단계에서는 messi를 활용하여 API를 연동하는 과정을 다룹니다. 모든 과정에 대한 소스코드는 아래에서 다운로드 하실 수 있습니다.

임포트

프로젝트의 메인이 되는 액티비티인 MainAcitivty.java파일로 들어가 주십시오. 그리고 아래의 소스코드를 import 부분에 삽입하여 주십시오.

import com.hhdd.messi.Daum;
import com.hhdd.messi.Naver;
import com.hhdd.messi.event.DaumEventListener;
import com.hhdd.messi.event.NaverEventListener;
import com.hhdd.messi.naver.object.search.LocalObject;

복사-붙여넣기로 진행하셔도 무관합니다. 위의 클래스들은, 다음과 네이버의 API 객체, 결과처리를 통보할 이벤트리스너, 결과값 검색 객체와 관련된 내용입니다.


이벤트 리스너 추가

Messi는 이벤트 기반으로 값을 주고받으며, API 호출 성공시에는 OnResult와 실패시에는 OnFault로 결과값을 보내줍니다. 이벤트 리스너와 연동하기 위해 이벤트 객체를 implements 합시다.

public class MainActivity extends Activity implements NaverEventListener.OnLocalListener

이벤트 객체를 implements 했다면, 결과값을 받아올 OnResult과 실패시 원인을 통보할 OnFalut 메서드가 필요합니다. 키보드에서 Alt키 다음 S키 다음 V키를 눌러 생성하거나, 아니면 아래의 코드를 Oncreate 함수 하단에 복사-붙여넣기하여 주십시오.

private String dong_name = "";
private Naver naver_api;
private Daum daum_api;

@Override
public void onFaultResult(int arg0, String arg1) {
// 실패시 원인과 결과값을 리턴		
}
	
@Override
public void onResult(ArrayList<LocalObject> arg0) {
// 성공시 결과목록을 ArrayList 제너릭 형태로 리턴
}

오픈API 객체 생성

OnCreate 메서드 아래에 Daum 객체를 new로 만들어주십시오. 그리고 이어서 네이버 객체는, 앞서 발급받은 API Key값을 설정하는 부분을 추가합시다. API Key값은 setSearchKey 메서드에 key 값을 넣으면 다시 설정할 필요 없이 반복해서 사용할 수 있습니다. 그리고 다음 객체에도 앞서 발급받은 로컬 API Key 값을 설정하여 주십시오. 다음의 로컬 API Key값은 setLocalKey 메서드로 설정할 수 있습니다. 복사-붙여넣기는 OnCreate 메서드 안에 해주세요.

naver_api = new Naver();
daum_api = new Daum();
daum_api.setLocalKey("다음 로컬API 키");
naver_api.setSearchKey("네이버 검색API 키");
naver_api.setLocalListener(this);
							

각 객체들을 초기화 하는 절차를 마쳤습니다. 이어서, GPS 정보를 받아오는 부분을 추가합시다. 사용자의 GPS 정보는 LocationManager 클래스를 통해 받아올 수 있습니다. 이 튜토리얼에서는 사용자의 네트워크를 기준으로 위치를 찾아보는걸로 진행하겠습니다. LocationManager와 관련되어 더 참고하실 정보가 있다면, 구글 개발자 사이트를 방문하여 참고하여 주십시오. 그리고, LocationManager를 통해 받은 위도, 경도값을 주소 단위로 변환하는 메서드를 실행하고 그 결과값을 받는 리스너를 추가합니다. 위의 처럼 별도로 implements 하지 않고 생성자를 통해 처리하도록 구현해봅시다. 아래의 소스코드를 아까 만든 다음 객체 아래에 복사-붙여넣기 하거나, 아니면 코드를 위의 로직처럼 작성해 주세요.

		daum_api.setCoord2addrListener(new DaumEventListener.OnCoord2addrListener() {
			public void onResult(String arg0, String arg1, String arg2, String arg3) {
				dong_name = arg0;
				naver_api.LocalSearch(dong_name + " 근처 치킨");
			}
			public void onFaultResult(int arg0, String arg1) {
				// TODO Auto-generated method stub
				
			}
		});
        LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        Location location = manager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
        daum_api.Coord2addr(location.getLongitude(), location.getLatitude(), "WGS84");
		

위와 같이 만들면 별도로 implements 하지 않더라도, argument으로 결과값을 처리받을 수 있습니다. OnResult는 결과를 받는 메서드로, 여기서 사용자의 위치 정보를 행정동 주소로 변환한 결과를 알 수 있습니다. 첫번째 파라미터는 행정동이며, 그 뒤로 자치구, 자치시로 이어집니다. 이중에서 행정동 정보만 dong_name 변수에 저장합시다. 그리고 바로 네이버 지역검색 API에 "행정동 근처 치킨"이라는 키워드를 검색해 주변 치킨집 목록을 검색할 수 있게됩니다. 그리고, 앞서 만들어둔 각 배달 음식별 메뉴를 클릭했을때 주소 근처에 있는 가게를 찾도록 하는 로직을 추가합시다.

		Button btn1 = (Button) findViewById(R.id.btn1);
        Button btn2 = (Button) findViewById(R.id.btn2);
        Button btn3 = (Button) findViewById(R.id.btn3);
        Button btn4 = (Button) findViewById(R.id.btn4);
        
        btn1.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View v) {
				naver_api.LocalSearch(dong_name + " 근처 치킨");
			}
        });
        
        btn2.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View v) {
				naver_api.LocalSearch(dong_name + " 근처 중국집");
			}
        });
        
        btn3.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View v) {
				naver_api.LocalSearch(dong_name + " 근처 피자");
			}
        });
        
        btn4.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View v) {
				naver_api.LocalSearch(dong_name + " 근처 족발");
			}
        });

어댑터 만들기

위의 과정까지 마치면 자동으로 소셜픽 검색 결과를 통해 뉴스를 검색하고 그 결과값을 다시 OnFsult나 OnResult로 결과값을 알려줍니다. OnResult 호출시에 결과값을 앞서 구상한 ListView에 뿌려줍시다. ListView는 Adapter를 통해 연결할 수 있습니다. Adapter는 아까 만든 사전 검색 개별아이템 결과와 연결되게됩니다. Adapter에 대해 잘 이해가 가지 않는다면 아래의 코드를 복사-붙여넣기하셔서 사용하셔도 무관합니다.

public class ListAdapter extends ArrayAdapter<LocalObject>{
    	public ArrayList<LocalObject> items;
    	
    	public ListAdapter(Context context, int textViewResourceId, ArrayList<LocalObject> items) {
            super(context, textViewResourceId, items);
    		this.items = items;
    	}
    	
    	@Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View v = convertView;
            if (v == null) {
                LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.item_row, null);
            }
            
            LocalObject Info = items.get(position);
            
            if (Info != null) {
            	TextView tv1 = (TextView) v.findViewById(R.id.item_tv1);
            	TextView tv2 = (TextView) v.findViewById(R.id.item_tv2);
            	tv1.setText(Info.getTitle());
            	tv2.setText(Info.getAddress()+"\n"+Info.getTelephone());
            }
            return v;
        }
    	
    }

LocalObject 네이버 지역 검색결과를 담는 Object입니다. Object의 구조는 문서에서 살펴볼 수 있습니다. 위 코드에서 getTitle은 가게의 이름을, getAddress는 가게의 주소를, getTelephone은 가게의 전화번호를 가져올 수 있습니다. 그리고, 앞서 만든 어댑터에 붙여넣겠습니다.


어댑터와 연결

어댑터 클래스를 만들었다면, 어댑터와 검색결과값을 연동시켜주어야합니다. 검색결과는 OnResult에서 불러옵니다. 메인 페이지에있는 ListView를 찾은 후 어댑터를 연결하여 완성시켜 줍시다. 아래의 소스코드를 OnResult 함수 안에 그대로 복사-붙여넣기 하셔도 괜찮습니다.

ListView listView = (ListView) findViewById(R.id.listView1);
ListAdapter b1_adapter = new ListAdapter(this, R.layout.item_row, arg0);
listView.setAdapter(b1_adapter);

전화 걸기

이렇게 끝나면 재미가 없죠? 조금 더 새로운 기능을 추가해봅시다. 배달음식을 찾는 앱이니, 바로 전화를 거는 기능도 추가해봅시다. 리스트뷰의 각 아이템을 눌렀을때 발생하는 setOnItemClickListener를 통해 사용자가 선택한 가게로 바로 전화를 걸 수 있도록 하는 로직을 추가합시다. 아래의 소스코드를 어뎁터 연결 부분 밑에 그대로 복사-붙여넣기 하셔도 괜찮습니다.

listView.setOnItemClickListener(new OnItemClickListener(){

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				LocalObject obj = arg0.get(position);
				Intent callIntent = new Intent(Intent.ACTION_CALL);
				callIntent.setData(Uri.parse("tel:"+obj.getTelephone()));
				startActivity(callIntent);
			}
			
		});

여기까지 따라오시느라 수고가 정말 많으셨습니다! 이제 모든 코드 작성이 완료되었습니다 앱을 실행하면 아래와 같이 나옵니다.

 

앱을 실행하자 마자 바로, 내 주변에 있는 치킨 가게들이 나옵니다. 얏호! 오늘 저녁은 치킨 한마리 어떠신지요? 그런데 이 프로젝트를 진행하면서 아래와 같은 고민을 한번 해보시면서 튜토리얼을 마쳤으면 좋겠습니다.

  • 행정동 단위로 검색하는것이 과연 정확할까요? 중동만 하더라도 서울시 마포구와 경기도 부천시에 있습니다. 조금 더 정확도를 높일 방법이 없을까요?
  • 가게의 정보를 미리 데이터베이스화 해서 검색하는것이 조금 더 빠르지 않을까요? 1년에 얼마나 많은 가게들이 새롭게 문을 열고 닫을까요?
  • GPS 정보 이외에 더 정확하게 사용자의 위치를 받아올 수 있는 방법이 없을까요?

오늘은 여기에서 숙제로 남기고 가겠습니다! Just Do IT!


소스코드 다운로드

이 과정으로 튜토리얼을 마칩니다. 따라오느라 수고가 많았습니다. 혹시 해당 과정에서 문제가 있거나 이해하기 어려운 부분이 있다면 소스코드를 다운받아 한번 살펴봐 주세요.

다운로드

안사 이쁜이  2014-03-12 (수) 17:00
축하드립니다. ;)
냐옹이류님은 안사 이쁜이에 당첨되어 2 포인트 지급되었습니다.

glaxy  2014-03-12 (수) 17:42
베플로 선택된 게시물입니다. 


Google Map Ver.2 현재 위치에 마커 찍는 소스



GibtHub 주소 : https://github.com/bear2u/GoogleMapTestApp.git
public class MainActivity extends FragmentActivity implements LocationListener{
    private GoogleMap mMap;
    private LocationManager locationManager;
    private String provider;

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

        int googlePlayServiceResult = GooglePlayServicesUtil.isGooglePlayServicesAvailable(MainActivity.this);
        if( googlePlayServiceResult !=   ConnectionResult.SUCCESS){ //구글 플레이 서비스를 활용하지 못할경우 <계정이 연결이 안되어 있는 경우
            //실패
            GooglePlayServicesUtil.getErrorDialog(googlePlayServiceResult, this, 0, new DialogInterface.OnCancelListener()
            {
                @Override
                public void onCancel(DialogInterface dialog)
                {
                    finish();
                }
            }).show();
        }else { //구글 플레이가 활성화 된 경우
            locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
            Criteria criteria = new Criteria();
            provider = locationManager.getBestProvider(criteria, true);

            if (provider == null) {  //위치정보 설정이 안되어 있으면 설정하는 엑티비티로 이동합니다
                new AlertDialog.Builder(MainActivity.this)
                        .setTitle("위치서비스 동의")
                        .setNeutralButton("이동", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                startActivityForResult(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS), 0);
                            }
                        }).setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialog) {
                        finish();
                    }
                })
                        .show();
            } else {   //위치 정보 설정이 되어 있으면 현재위치를 받아옵니다

                locationManager.requestLocationUpdates(provider, 1, 1, MainActivity.this); //기본 위치 값 설정
                setUpMapIfNeeded(); //Map ReDraw
            }

            setMyLocation(); //내위치 정하는 함수
        }
    }//onCreate


    private LatLng myLocation;
    double[] myGps;

    private void setMyLocation(){
        mMap.setOnMyLocationChangeListener(myLocationChangeListener);

    }
    Marker mMarker;
    private GoogleMap.OnMyLocationChangeListener myLocationChangeListener = new GoogleMap.OnMyLocationChangeListener() {
        @Override
        public void onMyLocationChange(Location location) {
            LatLng loc = new LatLng(location.getLatitude(), location.getLongitude());
            mMarker = mMap.addMarker(new MarkerOptions().position(loc));
            if(mMap != null){
                mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(loc, 16.0f));
            }
        }
    };

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {//위치설정 엑티비티 종료 후
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case 0:
                locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
                Criteria criteria = new Criteria();
                provider = locationManager.getBestProvider(criteria, true);
                if(provider==null){//사용자가 위치설정동의 안했을때 종료
                    finish();
                }else{//사용자가 위치설정 동의 했을때
                    locationManager.requestLocationUpdates(provider, 1L, 2F, MainActivity.this);
                    Log.d("KTH","117 locationMaanger done");
                    setUpMapIfNeeded();
                }
                break;
        }
    }

    @Override
    public void onBackPressed() {
        this.finish();
    }

    @Override
    protected void onResume() {
        super.onResume();
        setUpMapIfNeeded();

    }

    @Override
    protected void onPause() {
        super.onPause();
        locationManager.removeUpdates(this);
    }

    private void setUpMapIfNeeded() {
        if (mMap == null) {
            mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapView)).getMap();
            if (mMap != null) {
                setUpMap();
            }
        }
    }

    private void setUpMap() {
        mMap.setMyLocationEnabled(true);
        mMap.getMyLocation();

    }

    boolean locationTag=true;

    @Override
    public void onLocationChanged(Location location) {
        if(locationTag){//한번만 위치를 가져오기 위해서 tag를 주었습니다
            Log.d("myLog"  , "onLocationChanged: !!"  + "onLocationChanged!!");
            double lat =  location.getLatitude();
            double lng = location.getLongitude();

            Toast.makeText(MainActivity.this, "위도  : " + lat +  " 경도: "  + lng ,  Toast.LENGTH_SHORT).show();
            locationTag=false;
        }

    }

    @Override
    public void onProviderDisabled(String provider) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onProviderEnabled(String provider) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        // TODO Auto-generated method stub

    }
}
AndroidMainfest.xml

    
    
    
    
    

 
 
ui xml


    



Try this...

  1. Create libs folder under the application folder.
  2. Add .jar files to libs folder.
  3. Then add .jar files to app's build.gradle dependency.
  4. Finally Sync project with Gradle files.

1.Create libs folder:

enter image description here

2.Add .jar to libs folder:

enter image description here

3.Edit app's build.gradle dependency:

  • Open app/build.gradle

enter image description here

4.Sync project with Gradle files:

  • Finally add .jar files to your application.

enter image description here

Happy coding....



'Android > Android Studio' 카테고리의 다른 글

Android Studio에 GitHub를 붙여보자!!  (1) 2014.12.12
Android Studio 단축키 모음  (0) 2014.12.12

출처 : http://www.londonappdeveloper.com/how-to-use-git-hub-with-android-studio/

How to use GitHub with Android Studio

This article will explain how to use GitHub with Android Studio.

Firstly, let’s login to github.com and create a new repository. From the top right corner of the screen, click the +sign and select New repository.

GitHub "New repository" option

Now complete the form to create a new repository called testproject. Leave the Initialize this repository with a README unticked.

GitHub create new repository form

Next, open Android Studio and create a new project. Call your new application TestProject. Click Next to continue.

Android Studio new project window

Leave the next page as default and click Next.

Android Studio "Select the form factors your app will run on" screen

On the Add an activity to Mobile screen select Blank Activity and click Next.

Android Studio "Add an activity to Mobile" screen

In the next screen, leave the default activity name of MyActivity and click Finish.

Android Studio "New file options" screen

Your new project will open in Android Studio. On the top menu, select VCS > Import into Version Control >Create Git Repository.

Android Studio "Create Git Repository" option.

On the next screen, leave it all as default and click OK.

Android Studio "Select directory for git init" screen

Now use Internet Explorer and navigate to the root of your projects folder. Right click and select Git Bash (If you do not see this option, then first install Git for Windows).

When the Git bash screen appears, type:

1
git remote add origin https://github.com/[username]/[project_name].git

An example of a Git repository URL is: https://github.com/markwint/testproject.git

Entering command into Git Bash

Then press enter. The GitHub remote will be added to your Git repository.

Next, jump back into Android Studio, right click your projects root directory and select Git > Add. This will add all your project files to your Git repository.

Android Studio "Git > Add" option

It will seem like nothing has happened, but trust me, the project files are added.

Now right click the project name again and this time select Git > Commit Directory.

Android Studio "Commit Directory" option

In the next screen, type a Commit Message and select Commit.

Android Studio "Commit Changes" option

If a Code Analysis warning appears, click Commit. (Unless it’s a real project, in which case review and fix the issue before committing!)

Android Studio "Code Analysis" warning

Now, right click the project name, select Git > Repository > Push.

Android Studio "Git Push" option

Check the box Push current branch to alternative branch and leave the branch name as master. Then select push.

Android Studio "Git Push" prompt

Now enter your GitHub Login (email address) and Password. Then click OK.

Android Studio GitHub Remote Login

If it’s all good, you will see this message.

Android Studio Successful Git Push

Now your code is pushed to your GitHub repository. Don’t believe me? Logon and check for yourself.

GitHub repository pushed from Android Studio

Hope that was helpful

'Android > Android Studio' 카테고리의 다른 글

Android Studio에 Lib jar 추가  (0) 2014.12.12
Android Studio 단축키 모음  (0) 2014.12.12

출처 http://blog.naver.com/komseki/130185867089


Editing

 

Ctrl + Space : 기본 코드 완성

Ctrl + Shift + Space : 스마트 코드 완성(예상되는 타입의 메소드또는 변수명 )

Ctrl + Q : 빠른 문서보기

Shift + F1 : 외부 문서보기(http://developer.android.com/reference로 이동)

Ctrl + mouse over code : 간단한 설명.

Alt + Insert : Generate code( Getters, Setters, Constructors, hashCode/equals, toString )

Ctrl + O : Override methods

Ctrl + I : Implement methods

Ctrl + Alt + T : Surround with… (if..else, try..catch, for, synchronized, etc.)

Ctrl + / : 한줄주석

Ctrl + Shift + / : 블럭주석

Ctrl + W : 연속적인 코드블럭 선택

Alt + Enter : 빠른수정.

Ctrl + Alt + L : Reformat code
Ctrl + Alt + O : Optimize imports
Ctrl + Alt + I : Auto-indent line(s)

Ctrl + Shift + V : 이전에 클립보드에 복사한 히스토리 열기.

Ctrl + D : 라인복제 또는 선택블록 복제

Ctrl + Y : 라인삭제

Ctrl + Shift + J : 라인합치기(Smart line join)

Ctrl + Enter : 라인분리(Smart line split)

Ctrl + Shift + U : 대소문자 변환

Ctrl + Shift + ] / [ : 코드블럭 처음또는 끝까지 선택

Ctrl + Delete : 단어끝까지 삭제

Ctrl + Backspace : 단어처음까지 삭제

 

 

 

Search/Replace

 

Double Shift : 모든곳에서 찾기.

Ctrl + F : 찾기

F3 : 다음찾기

Shift + F3 : 이전찾기

Ctrl + R : 바꾸기

Ctrl + Shift + F : 경로에서 찾기(Find in path)
Ctrl + Shift + R : 경로에서 바꾸기(Replace in path)

 

 

 

Usage Search

 

Alt + F7 / Ctrl + F7 : 사용내용 전체찾기 / 파일에서 사용한것 찾기
Ctrl + Shift + F7 : 현재파일에서 하이라이트
Ctrl + Alt + F7 : 사용된것 새창으로 보여줌.

 

 

 

Compile and Run

 

Shift + F10 : Run

 

 

 

Debugging


F8 : Step over
F7 : Step into
Shift + F7 : Smart step into
Shift + F8 : Step out
Alt + F9 : Run to cursor
Alt + F8 : Evaluate expression
F9 : Resume program
Ctrl + F8 : Toggle breakpoint
Ctrl + Shift + F8 : View breakpoints

 

 

 

Navigation


Ctrl + N : 클래스 열기
Ctrl + Shift + N : 파일열기
Ctrl + Alt + Shift + N : Go to symbol
Alt + Right/Left : 문서탭이동

F12 : 이전에 사용한 도구창 열기

Shift + Esc : 마지막에 사용한 도구창 닫기
Ctrl + G : 줄번호로 이동.
Ctrl + E : 이전에 열었던파일 목록창 열기
Ctrl + B or Ctrl + Click : Go to declaration
Ctrl + Alt + B : Go to implementation(s)
Ctrl + Shift + I : Open quick definition lookup
Ctrl + Shift + B : Go to type declaration
Ctrl + U : super-method/super-class 이동.
Alt + Up/Down : 이전/다음 함수 이동

Ctrl + ] / [ :  코드블럭 처음/끝 이동
Ctrl + F12 : 파일 구조보기

F2 / Shift + F2 : 다음/이전 하이라이트된 에러로 이동.
F4 : 해당 소스로 이동

 

 

 

Refactoring

 

F5 : 복사
F6 : 이동
Alt + Delete : 안전하게 삭제(지우기전에 사용된곳 확인 가능)

Shift + F6 : 이름바꾸기

 

 

 

Live Templates


Ctrl + Alt + J : Surround with Live Template
Ctrl + J : Insert Live Template
iter : Iteration according to Java SDK 1.5 style
inst : Check object type with instanceof and downcast it
itco : Iterate elements of java.util.Collection
itit : Iterate elements of java.util.Iterator
itli : Iterate elements of java.util.List
psf : public static final
thr : throw new



'Android > Android Studio' 카테고리의 다른 글

Android Studio에 Lib jar 추가  (0) 2014.12.12
Android Studio에 GitHub를 붙여보자!!  (1) 2014.12.12

http://quadflask.tistory.com/315 Android Studio 에 관한 내용이 공감이 많이 간다.



TextView 에서 원하는 부분에 말줄임 넣는 프로그래밍 
final TextView title = (TextView)findViewById(R.id.text);
        title.setText("A really long text");
        ViewTreeObserver vto = title.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

            @Override
            public void onGlobalLayout() {
                ViewTreeObserver obs = title.getViewTreeObserver();
                obs.removeGlobalOnLayoutListener(this);
                if(title.getLineCount() > 3){
                    Log.d("","Line["+title.getLineCount()+"]"+title.getText());
                    int lineEndIndex = title.getLayout().getLineEnd(2);
                    String text = title.getText().subSequence(0, lineEndIndex-3)+"...";
                    title.setText(text);
                    Log.d("","NewText:"+text);
                }

            }
        });


출처 : http://imsoli.blogspot.kr/2014/07/android-javalangnoclassdeffounderror.html


[Android] java.lang.NoClassDefFoundError: android.support.v7.appcompat.R$styleable

[Android] java.lang.NoClassDefFoundError: android.support.v7.appcompat.R$styleable


<현상>

안드로이드 개발자 사이트의 Support Library Setup(https://developer.android.com/tools/support-library/setup.html) 을 참고하여 Adding libraries with resources 방식으로 Android Support Library 를 추가하고 개발프로젝트를 실행하니 제목과 같은 에러가 발생.


<원인>

Adding libraries with resources 방식은, 라이브러리 프로젝트를 생성하여 개발프로젝트에 라이브러리를 추가하는 방법.
컴파일 할때는 라이브러리 프로젝트의 소스를 참고하여 이상이 없었으나,
실행하기 위해 APK를 만들 때 라이브러리 프로젝트의 Bin 폴더에 있는 리소스를 가져와서 APK를 만드는데, 라이브러리 프로젝트를 한 번도 Build 안했다면 Bin폴더에 아무것도 존재하지 않아 실행시 라이브러리를 찾을 수 없어 위와 같은 에러가 발생.


<해결방법>

라이브러리 프로젝트를 Build하고, 개발프로젝트를 Clean & Build 하고 실행하니 위의 에러가 해결.


'Android > TroubleShooting' 카테고리의 다른 글

Fragment - Activity has been destoryed Problem  (0) 2016.07.17

D

소스 다운로드 :

RecylerListViewExamProject.zip

이번 Android L 프리뷰 버전에 새롭게 등장한 뷰들이 몇 개가 있다. 그 중 제일 눈여겨봐야 할 게 RecyclerView 인 것 같아서 분석을 해볼려고 한다.

우선 RecylerView의 장점은 기존 ListView보다 좀 더 유연하고 성능이 향상되고 커스터마이징을 하는 부분이 상당히 개선됐다고 강조를 한다.

구조를 살펴보면 대략 이런 구조이다.

RecylerView ( LayoutManager) – Adapter (DataSet) 이다.

기존 리스트뷰를 그대로 사용하되 추가적인 LayoutManager를 적용하면 된다.

그럼 이 LayoutManager가 과연 무엇일까..

RecylerView를 생성시 필수적으로 생성되어야 하며, 이 Manager를 통해서 아이템들의 뷰 형태를 관리를 해주고 있다.

  1. LinearLayoutManager – 수평 / 수직의 스크롤 형태를 만듬
  2. GridLayoutManager – 그리드 레이아웃 형태
  3. StaggeredGridLayoutManager – 높이가 불규칙적이고 다양한 형태의 그리드 리스트 (오우..이제 이게 공식적으로 지원이 되는군요..ㅠㅠ)

이밖에도 많은 확장 LayoutManager를 만들어서 적용해서 다양한 형태를 개발 할 수 있다.

Adapter 부분도 이전과 다른 형태를 갖는다.

우선 RecyclerView는 RecyclerView.Adapter를 베이스로 한 Adapter를 가져야 한다.

필수적으로 세가지의 함수를 인터페이스를 구현해야 된다.

@Override

public int getItemCount() {}

  • ListView의 Adapter에서 사용하는 리스트 개수 구하는 함수

@Override

public void onBindViewHolder(ViewHolder holder, int position) {}

  • 주어진 ViewHolder에 데이터들을 바인딩하는 역할 (Adapter의 getView()와 동일)

@Override

public ViewHolder onCreateViewHolder(ViewGroup parent, int arg1) {}

  • ViewHolder 를 생성하는 함수

 

예전 Adapter에서는 ViewHolder를 선택적으로 쓰면 좋고 귀찮으면 빼서 사용을 했지만 이번 RecylerView에서는 필수적으로 사용을 해야한다.ㅠ

아주 기본적인 내용을 파악했으니 코드 넣어서 일단 작동이 되는 지 테스트를 해보자.

결과물은 다음과 같다. 정말 간단하다..;;

 

만들고 보니.. 기존 리스트뷰와 큰 차이가 없어 보인다가 아니라..없다..ㅠㅠ

일단 코드를 잠깐 살펴보면

Layout 은 ListView대신 밑에 적혀있는 것 처럼 RecyclerView를 사용하면 된다..

MainActivity 에선 이걸 바인딩해주면 끝..(넘 쉽나..ㅋㅋ)

기존 ListView처럼 뷰 바인딩하고 Adapter연결해주면 끝..그리고 중요한게 꼬~옥 setLayoutManager를 지정해줘야 런타임시 에러가 안난다..

에러내용이 setMesure 머시기 하면서 NullPoinerExption 을 뽑아낸다.. (중요!!)

마지막으로 Adapter를 보겠다.

 

별거 없지만 처음 언급했던 세가지 메소드를 꼭 호출해 줘야 하는게 중요하다.

소스 파일은 위에 첨부했으며 초보분들은 보고 참고하시면 될 것 같다.

 

참고 사이트 :

  1. http://www.kmshack.kr/android-recyclerview
  2. https://github.com/antoniolg/RecyclerViewExtensions
  3. https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html
  4. http://www.vogella.com/tutorials/AndroidRecyclerView/article.html

 

이상입니다.

[펌] http://changyeopkim.blogspot.kr/2013/05/android.html

Android 추천 라이버러리

UI

ActionbarSherlock: http://actionbarsherlock.com/
ActionBar의 호환성을 보장하는 라이브러리

Android Query: http://code.google.com/p/android-query/
UI 엘리먼트를 비동기적으로 처리할 수 있도록 도와주는 라이브러리

Android Pull To Refresh: https://github.com/johannilsson/android-pulltorefresh
iOS에서 많이 사용하는 리스트를 당겨서 새로고침 라이브러리


AndroidViews: http://www.androidviews.net/
각종 커스텀 View를 소개하는 사이트

전반적

Otto: http://square.github.com/otto/
믿고 쓰는 스퀘어산 이벤트 버스이벤트 버스를 통해 만든 이벤트를 포스트하고 subscribe하고 있는 부분에서 해당 이벤트를 받을 수 있다더럽게 Activity Result를 통해서 번들을 주고 받거나 하지 않아도 되서 편리.

Wishlist: https://github.com/kevinsawicki/wishlist
안드로이드의 각종 귀찮은 점을 편하게 만들어준 고마운 라이브러리

ButterKnifehttps://github.com/JakeWharton/butterknife
View Injection 라이브러리. 코드량을 줄여준다. 이쁜 코드는 덤

데이터

Simple XML: http://simple.sourceforge.net/
XML과 자바 클래스의 serialize, deserialize

Gson: https://code.google.com/p/google-gson/
JSON과 자바 클래스의 serialize / deserialize

네트워크

http-request: https://github.com/kevinsawicki/http-request
InputStream같은거 신경쓰지 않고 처리해주는 좋은 http 라이브러리(HttpURLConnection 기반)


배힝기모드설정코드


'Android > GUI & Activity' 카테고리의 다른 글

앱 최신버전 체크하는 방법  (0) 2014.11.19
Animation 종류  (0) 2014.10.28
[펌[] Android ActionBar 활용  (0) 2014.10.22
AutoScaleTextView 추천 소스  (0) 2014.10.16
AutoScale TextView (4.4버전 테스트완료)  (0) 2014.10.15

바로가기 : http://nekomimi.tistory.com/666

출처 : http://reddolphin.tistory.com/100


* 카카오톡과 마이피플 심층 분석이랄까….???

  - 카톡, 마플 앱 트래픽, 예상 구현 방법.

* Networking Tutorial for iOS: How To Create A Socket Based iPhone App and Server

* SocketRocket Objective-C WebSocket Client(beta)
  - Socket을 이용한 Chat 구현 오픈 소스.
  - Client, Server 

* MultipeerGroupChat 
  - Apple 예제. iOS7 or later

* XMPP
  - 위키피디아 정리
  - 사이트

* XMPP 소개
  - 소개글. (아키택처, 프로토콜, Ruby 예제 등 간략.)

* XMPPFramework
  - Open Source

* [Server] 공개 채팅서버 OpenFire 설치, 구동 
  - XMPP 윈도우 설치

* XMPP 소개

* Openfire
  - XMPP 서버를 사용하여 IM, Group Chat 등 가능, JAVA, Apache License 
  - Jive software의 igniteRealTime에서 운영.

* Google App Engine XMPP를 활용하여 Android Push Service 만들기(2)

* 구글 앱 엔진 XMPP 활용해 안드로이드 푸시 서비스 구현

* Building a Jabber Client for iOS: XMPP Setup

* APNS, Sockets,  Polling 에 대한 질문.
  - APNS 사용하라고 얘기.

* 아이폰챗 v0.9
  - 개인 블로그, 에제, 서버 & 클라이언트.

* MultipeerGroupChat
  - 
* 안드로이드 채팅 예제

* 채팅 관련 맥부기 Q&A
  -  클래스를 쓰레드로 만들수있나요? 채팅앱만들고있습니다.
  - 카카오톡 등의 채팅어플에서 대화방의 이모티콘 출력 방식 질문드립니다..
  - XMPP 관련 도움부탁드려요,
  - 채팅UI제작중에 입력칸 질문입니다.
  - NSStream vs CGSocket

* Tigase Install
  - 설치 할 때의 정리 문서.(한글)

* Tigase Project
  - Open Source and Free XMPP/Jabber Software

* GitHub Searching ‘chat’

* IBM x-ioschat

* 비영리 오픈소스 메신저 ‘텔레그램’

* Facebook 메신저와 MQTT


출처 : http://charlie0301.blogspot.kr/2013/06/fragmentactivity-fragmenttabhost.html

FragmentActivity, FragmentTabHost 사용하기

이전 블로그에서 이전 함 (원본 글 2013/06/27 작성)

아래 처럼 FragmentTabHost를 사용하면서 이것저것 하려니 개고생 함..
그냥 Android Project를 하나 만들고 MainActivity를 만들때 Navigation Type을 Scrollable Tabs+Swipe로 선택하여
SectionPagerAdapter + FragmentActivity 예제를 만들어 참고하여 app 만드는게 편함..


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

TabActivity가 deprecated 되면서 FragmentActivity & FragmentTabHost를 사용하게 되어
보던 중 생각보다 Google documentation이 부실해서 여기저기 찾아보고 정리함.

[Android Support Libraries 다운로드 및 설치]

> 아래 처럼 Android SDK Manager를 통해서 다운로드 하고 개발중인 project의 lib에 복사하고 project libraries로 추가

 Downloading the Support Package

The Support Package is provided as a downloadable package from the Android SDK Manager. To install:
  1. Launch the Android SDK Manager.
    From Eclipse, you can select Window > Android SDK Manager. Or, launch SDK Manager.exe from the <sdk>/ directory (on Windows only) or android from the <sdk>/tools/ directory.
  2. Expand the Android Repository, check Android Support package and click Install selected.
  3. Proceed to install the package.
When done, all files (including source code, samples, and the JAR files) are saved into the<sdk>/extras/android/support/ directory. This directory contains each of the different support libraries, such as the library for API level 4 and up and the library for API level 13 and up, each named with the respective version (such as v4/).

Setting Up a Project to Use a Library


To add one of the libraries to your Android project:

Add the JAR file to your project.
Copy the JAR file for the library you want to use into your Android project. To do this:

  • Create the directory libs/ at the root of your project (next to src/, res/, and so forth).
  • Locate the JAR file for the library you want to use and copy it into the libs/ directory.
    For example, the library that supports API level 4 and up is located at <sdk>/extras/android/support/v4/android-support-v4.jar.
Your build system may expect to find the JAR file in a directory other than libs. Read the documentation for your build system to learn where to put the JAR file.

<dl style="color: rgb(34, 34, 34); font-family: Roboto, sans-serif; font-size: 14px; line-height: 19px; background-color: rgb(249, 249, 249);">
If necessary, add the libs/ directory to your build path.
Read the documentation for your build system to learn how to add the JAR file to the build path.
</dl>


[Fragment 개념] 
> Fragment에 대한 전반적인 tutorial.. 추천

[FragmentTabHost reference]

> 사실 아래 예제가 다임.. 좀 더 자세한 설명은 아래 링크를 참고. 
   TabHost.addTab() 에서 class들은 Fragment를 상속받아 만든 class 들임.

 Here is a simple example of using a FragmentTabHost in an Activity:
import com.example.android.supportv4.R;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;
/**
 * This demonstrates how you can implement switching between the tabs of a
 * TabHost through fragments, using FragmentTabHost.
 */
public class FragmentTabs extends FragmentActivity {
    private FragmentTabHost mTabHost;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.fragment_tabs);
        mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
        mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);

        mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
                FragmentStackSupport.CountingFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
                LoaderCursorSupport.CursorLoaderListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
                LoaderCustomSupport.AppListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
                LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);
    }
}
This can also be used inside of a fragment through fragment nesting:
import com.example.android.supportv4.R;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTabHost;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class FragmentTabsFragmentSupport extends Fragment {
    private FragmentTabHost mTabHost;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        mTabHost = new FragmentTabHost(getActivity());
        mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.fragment1);

        mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
                FragmentStackSupport.CountingFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
                LoaderCursorSupport.CursorLoaderListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
                LoaderCustomSupport.AppListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
                LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);

        return mTabHost;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mTabHost = null;
    }
}

[FragTabHost 사용 상세 예제들]

> 모든 코드(Fragment classes) 포함

> 좀 자세한 설명

[FragTabs를 아래로 위치시키기]

> 웹상에서는 Relative를 사용하거나 Linear의 weight를 사용하는 방법 아니면 Custom tab을 사용하는 방법이 있지만 위에서는 간단하게 해결 함. 아래는 살짝 수정한 코드
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="1" >

    <FrameLayout
        android:id="@+id/realtabcontent"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1" />

    <android.support.v4.app.FragmentTabHost
        android:id="@android:id/tabhost"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="0dp"
            android:layout_height="0dp" />

        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
    </android.support.v4.app.FragmentTabHost>

</LinearLayout>


[Fragment Tab 간 data 전달]
> Android Developers site의 Fragment 관련 내용에서 나오는 내용.

> 좀 더 상세한 내용, 사실 Fragment의 Tag를 알아내는 방법을 몰라 좀 고생했었음.
   Activity에 Tag를 받는 함수를 만들고 각 Fragment Tab이 생성 되었을 때 Activity의 함수를 통해 Tag을 등록
   좀 나이스 한 방법은 아니지만.. 일단 뭐...
 public class MyFragmentB extends Fragment {

 TextView b_received;
 
 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState) {
  View myFragmentView = inflater.inflate(R.layout.fragment_b, container, false);
  
  b_received = (TextView)myFragmentView.findViewById(R.id.b_received);
  String myTag = getTag();
  
  ((AndroidViewPagerActivity)getActivity()).setTabFragmentB(myTag);


[기타]
> 코드가 좀 이상하네...


출처 : http://givenjazz.tistory.com/44



20개 정도 규칙이 있으며 출처는 source.android.com에서 좀 더 자세한 내용을 볼 수 있다.

build된 sdk에는 없지만 sdk 소스를 다운받으면 이클립스용 코딩 포맷과 import순서가 정보가 적힌 xml파일도 같이 받을 수 있는데, 이 글에 첨부했다.

android-formatting.xml은 "Window › Preferences › Java › Code Style > Formatter 에 import하고,
android.importorder "Organize Imports에 import하면
Shift+command+F로 자동포멧정리 기능을 안드로이드에 맞게 사용할 수 있다.

  1. Exceptions: 예외 무시하지말고 처리하기.
  2. Exceptions: 상위 Exception으로 싸잡아서 처리하지 않기.
  3. Finalizers: 왠만하면 쓰지않기 (언제 적용될지 모름)
  4. Imports: *쓰지말고 정확하게 풀네임 적기.

Java Library Rules

표준 코딩컨벤션이 바뀌어서 예전 코딩컨벤션과 충돌이 난다면 예전 코딩컨벤션으로 작성해서 일관성을 유지하기.

Java Style Rules

자바표준 컨벤션에서 추가사항:

  1. Comments/Javadoc: 표준대로 작성하기.
  2. Short methods: 메소드는 40줄이 넘지않게 짧게 작성하기
  3. Fields: 초기에 선언하기나 사용하기 바로 전에 선언할 것.
  4. Local variables: 지역변수 범위는 최소화하기.
  5. Imports: 안드로이드, 서드파티(알파벳 순), java, javax 순으로 import하기.
  6. Indentation: 탭안쓰고 공백 4개 사용하기.
  7. Line length: 한줄에 100칸 이하 유지하기.
  8. Field names: Non-public, non-static 변수는 m으로 시작하고, static변수는 s로 시작하기.
  9. Braces: { 는 줄넘기지말고 사용하기
  10. Annotations: 표준 어노테이션 사용하기.
  11. Acronyms are words: XMLHTTPReques처럼 적지말고 XmlHttpRequest로 적기
  12. TODO style: "TODO: write this description"
  13. Consistency: 일관적으로 작성하기
  14. Logging: 로그도 비용이 드니 적절하기 사용하기
    ERROR > WARNING > INFORMATION > DEBUG > VERBOSE 사용할 것.
    한줄에 출력할 수 있는 80~100글자가 적당.
    StringBuilder는 기본버퍼가 16character라 String보다 항상 좋다고 할 수 없으니 확신이 없으면 그냥 String연산이 무난.
    System.out.print는 어차피 /dev/null로 던져버리니 절대 쓰지말 것. 괜히 비용만 잡아먹음.

Javatests Style Rules

  1. Naming test methods: testMethod_specificCase 이런식으로 이름짓기


출처 : http://202psj.tistory.com/571


http://code.google.com/p/android-market-api/ 

 

개발자 입장에서 쌔가빠지게 업데이트 게속 해줘도

 

업데이트 하나도 안하는 사용자들이 너무 많다!!

 

주위에 보면 그런 사람 잇더라..

 

그렇다고 따로 서버 둬서 체크하자니까 그냥 앱혼자노는 어플은 부담스럽다

 

구글플레이에 돈주고 개발자 등록했는데 요정도 서비스는 해줘야하는거 아닌가~~

 

 

그렇다 해준다.

 

버전체크 api를 이용해서

 

정보를 가져와서 사용하자~

 

Build.VERSION.SDK_INT 일케 가져온담에 맞춰서 하자

 

 MarketSession session = new MarketSession();
   session.login("id","pw"); // 구글 아무 계정이나 되는듯..?
//   session.getContext.setAndroidId(myAndroidId);

   String query = "com.kwon.kwonyangsanbus"; // 앱 이름 또는 패키지 명 다 쿼리 되는듯.. 근데 내꺼 안뜨냐 ?
   AppsRequest appsRequest = AppsRequest.newBuilder()
                                   .setQuery(query)
                                   .setStartIndex(0).setEntriesCount(10)
                                   .setWithExtendedInfo(true)
                                   .build();

   session.append(appsRequest, new Callback<AppsResponse>() {
            @Override
            public void onResult(ResponseContext context, AppsResponse response) {
                     // Your code here
                     // response.getApp(0).getCreator() ...
                     // see AppsResponse class definition for more infos
             Logger.error("앱갯수 : "+response.getAppCount());
             for(int i = 0 ; i < response.getAppCount(); i++){
              Logger.error(i+"  "+response.getApp(i).getTitle());
              Logger.error(i+"  "+response.getApp(i).getCreator());
              Logger.error(i+"  "+response.getApp(i).getPackageName());
              Logger.error(i+"  "+response.getApp(i).getVersion());
              Logger.error(i+"  "+response.getApp(i).getVersionCode());
             }
            }
   });
   session.flush();



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

출처: http://diyall.tistory.com/846


[안드로이드] 안드로이드 APK 버전 체크하기

 

안드로이드의 APK 버전을 체크해서 요즘은 업데이트 여부를 알려주고 있습니다.

그래서 저도 시도해 볼려고 하니.. 여러가지 어렵더군요.

 

우선! 설치되어 있는 APK 의 버전은 쉽게 얻을 수 있습니다.

 

    public static String getVersionName(Context context) {
    	Log.i(TAG, "here in getVersionName");
        try {
            PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
            return packageInfo.versionName;
        } catch (NameNotFoundException e) {
        	Log.i(TAG, "err NameNotFoundException -> " + e.toString());
            return null;
        }
    }

 

 

하지만 문제는 마켓에 올린 최신버전과 비교를 하는 문제였습니다.

 

방법은

1. 서버를 운영하여 서버에 최신버전 내용을 넣고 비교하는 방법

2. 마켓의 내용을 HTML 파싱하는 방법 등이 있는 것 같습니다.

하지만.. 아직 초보를 그것도 쉽지 않더군요.

 

그러다가 찾은 방법이 구글에서 제공하는 Google Market API 를 이용하는 방법입니다.

하지만 query 부분에 패키지명을 넣으면 해결될 줄 알았는데.. 계속 null 값을 반환합니다.

 

임의적으로 "maps" 등의 단어를 넣으면 데이타를 가져올 수는 있는데.. 뿌려주는 결과값이 왜 그렇게 나오는지를 알수가 없었습니다.

 

마켓에서 "maps" 로 검색한 것과는 다른 결과를 보여주기 때문입니다.

 

그러다가.. 문제를 해결 하였습니다.

 

저와 같은 고민을 하는 사람들이 많은 것 같아서.. 포스트 남깁니다.

 

AndroidId 값 가져오는 방법

 

    private static final Uri URI = Uri.parse("content://com.google.android.gsf.gservices");
    private static final String ID_KEY = "android_id";
     
    static String getAndroidId(Context context) {
    	Log.i(TAG, "here in getAndroidId");
        String[] params = { ID_KEY };
        Cursor c = context.getContentResolver()
                .query(URI, null, null, params, null);
     
        if (!c.moveToFirst() || c.getColumnCount() < 2)
            return null;
     
        try {
        	Log.i(TAG, "getAndroidId() : " + Long.toHexString(Long.parseLong(c.getString(1))));
            return Long.toHexString(Long.parseLong(c.getString(1)));
        } catch (NumberFormatException e) {
            return null;
        }
    }

AndroidManifest.xml 안에 권한을 넣어줘야 함

 

 

마켓의 정보 가져오기

 

    public static String getMarketVersionName(Context context) {
    	Log.i(TAG, "here in getMarketVersionName");
    	
    	try {
    		MarketSession session = new MarketSession();
        	session.login(email, pass);
        	//Log.i(TAG, "session : "+session.getAuthSubToken());
        	session.getContext().setAndroidId(getAndroidId(context));
        	String query = "패키지명";
        	
        	AppsRequest appsRequest = AppsRequest.newBuilder()
        			.setQuery(query)
        			.setStartIndex(0).setEntriesCount(1)
        			.setOrderType(AppsRequest.OrderType.NEWEST)
        			.setWithExtendedInfo(false)
        			.build();
        	
        	session.append(appsRequest, new Callback() {

    			@Override
    			public void onResult(ResponseContext context, AppsResponse response) {
    				//Log.i(TAG, "getAppCount() : " + response.getAppCount());
    				for (int i=0; i " + e.toString());
    	}
    	
    	return marketVersion;
    }

 

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

import com.gc.android.market.api.MarketSession;
import com.gc.android.market.api.MarketSession.Callback;
import com.gc.android.market.api.model.Market.AppsRequest;
import com.gc.android.market.api.model.Market.AppsResponse;
import com.gc.android.market.api.model.Market.ResponseContext;


위 마켓 api를 사용하기 위해 필요한 파일

파일에 최신버전은

http://code.google.com/p/android-market-api/

이쪽에서 왼쪽측 download 를 보면 받을수 있다.


 androidmarketapi-0.6.jar

 protobuf-java-2.2.0.jar

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


출처: http://www.androidside.com/plugin/mobile/board.php?bo_table=B49&wr_id=75819

Kick-Start: Bower – A Simple Tutorial of Setting-Up and Using Bower.JS

The goal of this post is to provide a simple description of how to install Bower JS and how to use Bower JS to manage client side dependencies. The first time I tried to use Bower I had problems. Hopefully this tutorial will provide others a complete resource to navigate around the issues that I found.

Assumptions:

  • You are a Windows developer
  • You will use the Windows Command Prompt instead of Bash
  • You have little or no knowledge of Node.js
  • You have little or no knowledge of GIT

1. Download and install Node.js

To run Bower you will need to download and install Node.js. Go to http://nodejs.org/ website and select the “install” button (see image below). This should download the version of Node.js you need. For me, when I clicked the “install” the version for Windows 64-bit downloaded. Once Node.js is download, execute the file.

I will not go thought the steps for installing Node.js; it’s very straight forward. During the install I used all default options.

2. Confirm Node.js is installed

When Node.js installation has completed we need to confirm it was installed successfully. Open a Windows Command Prompt and type “Node” and [enter]. You should get prompted with a “>”.

(If you previously had Windows Command Prompt open, you will need to close it and reopen it. The reason is that Node will be added to Environment Variable Path. If the Command Prompt is open when you install Node, it will not have the new Node Path.)


Now at the prompt type something like “2 + 2″ and [enter]. You should get a result. I got back 4. Now we have confirmed that Node.js is installed correctly. You can quit Node.js by using the keyboard and typing [ctrl]+C twice.

3. Create Folder Structure

Create the following folder structure.

(In the image above, ignore “External Libraries”. This is part of the WebStorm IDE)

4. Install Bower

The primary reason to use Bower is so that you do not have to manage client side dependencies (css, JavaScript, and etc). Here we will install Bower so that we can use it latter to manage dependencies.

Use Node Package Manger (npm) to install Bower. Since we are using the “-g” (global) switch we can install Bower from any directory.

(The npm statement is case sensitive.)

5. Test Bower is Installed

Since we will want to install the dependencies in the “app” direction, go ahead and navigate to the “app” directory”

Lets do a Bower search for jQuery. Remember, it is case sensitive

There is a ton of jQuery libraries. But that’s okay.

6. Install Dependencies (jQuery & Underscore)

In the command window enter “bower install jQuery” and press [Enter]. Again remember case sentitivity.

You may receive an error if you do not have GIT installed.

Install GIT

From Bower’s website (bower.io) you can get to GIT’s (git-scm.com) website to down GIT.

From GIT’s (git-scm.com) download GIT

When I installed GIT, I used all the defaults. But a key option that needs to be select is to “Run Git from the Windows Command Prompt”. This will add the PATH variable for Git.

8.Install Dependencies (jQuery & Underscore) – Again

Important – Close the current Command Prompt. If you attempt to install jQUery again with the current command prompt you will get the same error.

Open a new Command Prompt and navigate to the “app” directory that we created previously.

Install jQuery using Bower. Remember, it’s case sensitive.

Now install Underscore

9. Confirm Dependencies

There should be a new directory create by Bower call “bower_components” this is where jQuery and Underscore should have been installed at.

10. Finished

No you can go out and create your application without having to worry maintaining client side dependencies.

I hope this helped.


http://www.yongcloud.co.kr/android_tip.html

'Android > Tip&Tech' 카테고리의 다른 글

[펌]안드로이드 코딩 스타일 안내(가이드)  (0) 2014.11.19
npm 및 bower 설치..  (0) 2014.11.18
[펌]LoaderManager 동작이해  (0) 2014.10.21
[펌]안드로이드 Loader 활용하기  (0) 2014.10.21
자바 표준 스타일 정의  (0) 2014.09.30
@android:anim/accelerate_decelerate_interpolator
 
        애니메이션이 점점 빠르게 동작하다가 점점 천천히 동작합니다.
 
 
    @android:anim/accelerate_interpolator
 
        애니메이션이 점점 빠르게 동작합니다.
 
 
    @android:anim/anticipate_interpolator
 
        애니메이션이 시작할 때 반대 방향으로 동작을 한 후에 본래의 방향으로 동작합니다.
 
 
    @android:anim/anticipate_overshoot_interpolator
 
        애니메이션이 시작할 때 반대 방향으로 동작을 한 후에 종료 지점을 지나갔다가 종료 지점으로
        돌아옵니다. 예를 들어 왼쪽에서 오른쪽으로 이동하는 애니메이션이 있다면 시작할 때 뷰가
        왼쪽으로 조금 움직인 후 오른쪽으로 이동하고, 원래 도착해야할 위치를 지났다가 다시 왼쪽으로
        이동합니다.
 
 
    @android:anim/bounce_interpolator
 
        애니메이션이 종료될 때 튕기면서 스프링 효과를 표현합니다.
 
 
    @android:anim/cycle_interpolator
  
        애니메이션을 동작한 후에 반대 방향으로 한번 더 동작합니다. 만약 오른쪽으로 50 위치까지
        이동하는 애니메이션에 이 효과가 적용되면 오른쪽으로 50 만큼 이동한 후에 왼쪽으로 -50
        위치까지 이동하게됩니다.
       
       
    @android:anim/decelerate_interpolator
 
        애니메이션의 움직임이 점점 느려집니다.
 
 
    @android:anim/linear_interpolator
 
        특별한 효과 없이 일정하게 애니메이션이 동작합니다.
 
 
    @android:anim/overshoot_interpolator
 
        애니메이션이 동작할 때 멈춰야할 위치를 지난 후에 다시 돌아옵니다.


출처 : http://www.vogella.com/tutorials/AndroidActionBar/article.html


Using the action bar in Android applications

This tutorial describes how to use the action bar in your Android applications. It is based on Eclipse 4.3 (Kepler), Java 1.6 and Android 4.4.


Table of Contents

1. Introduction to the action bar
1.1. What is the action bar?
1.2. Example
1.3. Action bar on devices before API 3.0
2. Using the ActionBar
2.1. Entries in the action bar (actions)
2.2. Creating actions
2.3. Reacting to action selection
2.4. Search an action in the action bar
2.5. Changing the menu
3. Customizing the action bar
3.1. Changing the visibility of the action bar
3.2. Assigning a Drawable
3.3. Dimming the navigation buttons
3.4. Using Immersive Full-Screen Mode
3.5. Enabling the split action bar
4. Contributing to the action bar with fragments
5. Making the action bar dynamic
5.1. Custom views in the action bar
5.2. Contextual action mode
5.3. Action view
6. Action provider
6.1. What is an action provider?
6.2. Example: usage of the ShareActionProvider
7. Navigation via the application icon
7.1. Application icon as home
7.2. Application icon as Up button
8.
8.1. Navigation drawer
8.2. Example: Using the navigation drawer
8.3. Tab navigation
8.4. Dropdown menu navigation
8.5. Evaluation
9. Exercise: ActionBar
9.1. Project
10. Exercise: Add an action bar to your application
10.1. Create an icon for the ActionBar
10.2. Add a menu XML resource
10.3. Add actions to your menu resource
10.4. Assign icons
10.5. Validate XML resource
10.6. Add the action bar to your activity
10.7. Run the application and test the action bar
10.8. Remove the refresh button
11. Exercise: Using the contextual action mode
12. Support this website
12.1. Thank you
12.2. Questions and Discussion
13. Links and Literature
13.1. Source Code
13.2. Android ActionBar Resources
13.3. vogella Resources

1. Introduction to the action bar

1.1. What is the action bar?

The action bar (ActionBar) is located at the top of the activity. It can display the activity title, icon, actions which can be triggered, additional views and other interactive items. It can also be used for navigation in your application.

The action bar is enabled for devices which specify a target SDK of API version 11 or higher. It is possible to disable the action bar via the used theme, but the default Android themes have it enabled.

Applications with a target SDK version less than API 11 use the options menu if such a button is present on the device. The option menu is displayed if the user presses the Option button. The action bar is superior to the options menu, as the action bar is clearly visible, while the options menu is only shown on request. In case of the options menu, the user may not recognize that options are available in the application.

1.2. Example

The following screenshot shows the action bar of the Google+ Android application with interactive items and a navigation bar. On top it also indicates that the user can open a navigation bar on the side of the application.

ActionBar Screenshot

1.3. Action bar on devices before API 3.0

The action bar has been introduced in Android 3.0. If you want to use the action bar on devices with an earlier Android release, you have two popular options.

First, you can use the Open Source project called ActionBar Sherlock which allows you to use the action bar on Android devices as of Android 1.6. You find this library under the following link.

http://actionbarsherlock.com 

The second option is to use the ActionBarCompat library from the Android support library v7, which supports the action bar as of Android 2.1. See the following link to setup the support library v7 in your project: Setting up the support library.

This section focuses on the description of using the action bar without the Open Source or support library. You can easily port your application to an earlier API version using one of the different libraries.

2. Using the ActionBar

2.1. Entries in the action bar (actions)

Entries in the action bar are typically called actions. While it is possible to create entries in the action bar via code, it is typically defined in an XML resource file.

Each menu definition is contained in a separate file in the res/menu folder. The Android tooling automatically creates a reference to this file in the R file, so that the menu resource can be accessed.

2.2. Creating actions

An activity adds entries to the action bar in its onCreateOptionsMenu() method.

The showAsAction attribute allows you to define how the action is displayed. For example, the ifRoom attribute defines that the action is only displayed in the action bar if there is sufficient screen space available.

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

    <item
        android:id="@+id/action_refresh"
        android:orderInCategory="100"
        android:showAsAction="always"
        android:icon="@drawable/ic_action_refresh"
        android:title="Refresh"/>
    <item
        android:id="@+id/action_settings"
        android:title="Settings">
    </item>

</menu> 

The MenuInflator class allows to inflate actions defined in an XML file and adds them to the action bar.MenuInflator can get accessed via the getMenuInflator() method from your activity. The following example code demonstrates the creation of actions.

@Override
  public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.mainmenu, menu);
    return true;
  } 

Tip

While you can define the actions also in your source code, it is good practice to do this via XML files, as this results in less boilerplate code.

2.3. Reacting to action selection

If an action is selected, the onOptionsItemSelected() method in the corresponding activity is called. It receives the selected action as parameter. Based on this information, you can decide what to do. The usage of this method is demonstrated in the following code snippet.

@Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    // action with ID action_refresh was selected
    case R.id.action_refresh:
      Toast.makeText(this, "Refresh selected", Toast.LENGTH_SHORT)
          .show();
      break;
    // action with ID action_settings was selected
    case R.id.action_settings:
      Toast.makeText(this, "Settings selected", Toast.LENGTH_SHORT)
          .show();
      break;
    default:
      break;
    }

    return true;
  } 

2.4. Search an action in the action bar

To search for a menu item in a menu you can use the findItem() method of the Menu class. This method allows to search by id.

2.5. Changing the menu

The onCreateOptionsMenu() method is only called once. If you want to change the menu later, you have to call theinvalidateOptionsMenu() method. Afterwards this onCreateOptionsMenu() method is called again.

3. Customizing the action bar

3.1. Changing the visibility of the action bar

You can change the visibility of the action bar at runtime. The following code demonstrates that.

ActionBar actionBar = getActionBar();
actionBar.hide();
// more stuff here...
actionBar.show(); 

You can also change the text which is displayed alongside the application icon at runtime. The following example shows that.

ActionBar actionBar = getActionBar();
actionBar.setSubtitle("mytest");
actionBar.setTitle("vogella.com"); 

3.2. Assigning a Drawable

You also add a Drawable to the action bar as background via the ActionBar.setBackgroundDrawable() method.

The action bar scales the image. Therefore it is best practice to provide a scalable drawable , e.g., a 9-patch or XML drawable.

Tip

As of Android 4.2 the background of the action bar can also be animated via anAnimationDrawable.

3.3. Dimming the navigation buttons

You can also dim the software navigation button in your Android application to have more space available. If the user touches the button of the screen, the navigation button is automatically shown again.

Dimming the navigation buttons is demonstrated by the following code snippet.

getWindow().
  getDecorView().
  setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); 

The following screenshots show an application with and without the navigation buttons.

Application with action bar

Application with dimmed action bar

3.4. Using Immersive Full-Screen Mode

As of Android 4.4 (API 19) you can put your application into full screen mode. The first time this happens the system displays the user the info that he can restore the system bars with a downward swipe along the region where the system bars normally appear.

For example the following method also to put an activity into full screen mode.

// This method hides the system bars and resize the content
  private void hideSystemUI() {
    getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
            | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
            // remove the following flag for version < API 19
            | View.SYSTEM_UI_FLAG_IMMERSIVE); 
  } 

3.5. Enabling the split action bar

You can define that the action bar should be automatically split by the system if not enough space is available.

You can activate this via the android:uiOptions="SplitActionBarWhenNarrow" parameter in the declaration of your application activity in the AndroidManifest.xml file.

Note

If this option is activated, Android has the option to split the action bar. Whether to split is decided by the system at runtime.

4. Contributing to the action bar with fragments

Fragments can also contribute entries to the action bar.

To do this, call setHasOptionsMenu(true) in the onCreate() method of the fragment. The Android framework calls in this case the onCreateOptionsMenu() method in the fragment class and adds its menu items to the ones added by the activity .

5. Making the action bar dynamic

5.1. Custom views in the action bar

You can also add a custom view to the action bar, for example, a button or a text field.

For this you use the setCustomView method of the ActionView class. You also have to enable the display of custom views via the setDisplayOptions() method by passing in the ActionBar.DISPLAY_SHOW_CUSTOM flag.

For example, you can define a layout file which contains a EditText element.

<?xml version="1.0" encoding="utf-8"?>
<EditText xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/searchfield"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:inputType="textFilter" >

</EditText> 

This layout can be assigned in an activity to the action bar via the following code. The example code also attaches a listener to the custom view.

package com.vogella.android.actionbar.customviews;

import android.app.ActionBar;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;

public class MainActivity extends Activity {

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

    ActionBar actionBar = getActionBar();
    // add the custom view to the action bar
    actionBar.setCustomView(R.layout.actionbar_view);
    EditText search = (EditText) actionBar.getCustomView().findViewById(R.id.searchfield);
    search.setOnEditorActionListener(new OnEditorActionListener() {

      @Override
      public boolean onEditorAction(TextView v, int actionId,
          KeyEvent event) {
        Toast.makeText(MainActivity.this, "Search triggered",
            Toast.LENGTH_LONG).show();
        return false;
      }
    });
    actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM
        | ActionBar.DISPLAY_SHOW_HOME);
  }

} 

5.2. Contextual action mode

A contextual action mode activates a temporary action bar that overlays the application action bar for the duration of a particular sub-task.

The contextual action mode is typically activated by selecting an item or by long clicking on it.

To implement this, call the startActionMode() method on a view or on your activity. This method gets anActionMode.Callback object which is responsible for the life cycle of the contextual action bar.

You could also assign a context menu to a view via the registerForContextMenu(view) method. A context menu is also activated if the user "long presses" the view. The onCreateContextMenu() method is called every time a context menu is activated as the context menu is discarded after its usage. You should prefer the contextual action mode over the usage of context menus.

5.3. Action view

An action view is a widget that appears in the action bar as a substitute for an action item's button. You can, for example, use this feature to replace an action item with a ProgressBar view. An action view for an action can be defined via the android:actionLayout or android:actionViewClass attribute to specify either a layout resource or widget class to use.

This replacement is depicted in the following screenshots.

Before activating the ActionView

ActionViews running

The following activity replaces the icon at runtime with an action view which contains a ProgressBar view.

package com.vogella.android.actionbar.progress;

import android.app.ActionBar;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends Activity {

  private MenuItem menuItem;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ActionBar actionBar = getActionBar();
    actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME
        | ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.menu_load:
      menuItem = item;
      menuItem.setActionView(R.layout.progressbar);
      menuItem.expandActionView();
      TestTask task = new TestTask();
      task.execute("test");
      break;
    default:
      break;
    }
    return true;
  }

  private class TestTask extends AsyncTask<String, Void, String> {

    @Override
    protected String doInBackground(String... params) {
      // Simulate something long running
      try {
        Thread.sleep(2000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      return null;
    }

    @Override
    protected void onPostExecute(String result) {
      menuItem.collapseActionView();
      menuItem.setActionView(null);
    }
  };
} 

The following code shows the layout used for the action view.

<?xml version="1.0" encoding="utf-8"?>
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/progressBar2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

</ProgressBar> 

The following code shows the XML files for the menu.

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

    <item
        android:id="@+id/menu_settings"
        android:orderInCategory="100"
        android:showAsAction="always"
        android:title="Settings"
        />

    <item
        android:id="@+id/menu_load"
        android:icon="@drawable/navigation_refresh"
        android:orderInCategory="200"
        android:showAsAction="always"
        android:title="Load"/>

</menu> 

6. Action provider

6.1. What is an action provider?

An action provider defines rich menu interaction in a single component. It can generate action views, which are used in the action bar, dynamically populate sub-menus of an action and handle default action invocations.

The base class for an action provider is the ActionProvider class.

Currently the Android platform provides two action providers: the MediaRouteActionProvider and theShareActionProvider.

6.2. Example: usage of the ShareActionProvider

The following demonstrates the usage of the ShareActionProvider. This action provider allows you to grab selected content from applications which have registered the Intent.ACTION_SEND intent.

To use ShareActionProvider, you have to define a special menu entry for it and assign an intent which contains the sharing data to it.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

   <item android:id="@+id/menu_share"
          android:title="Share"
          android:showAsAction="ifRoom"
          android:actionProviderClass="android.widget.ShareActionProvider" />
    <item
        android:id="@+id/item1"
        android:showAsAction="ifRoom"
        android:title="More entries...">
    </item>

</menu> 

@Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_main, menu);

    // Get the ActionProvider for later usage
    provider = (ShareActionProvider) menu.findItem(R.id.menu_share)
        .getActionProvider();
    return true;
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.menu_share:
      doShare();
      break;
    default:
      break;
    }
    return true;  
  }

  public void doShare() {
    // populate the share intent with data
    Intent intent = new Intent(Intent.ACTION_SEND);
    intent.setType("text/plain");
    intent.putExtra(Intent.EXTRA_TEXT, "This is a message for you");
    provider.setShareIntent(intent);
  } 

7. Navigation via the application icon

7.1. Application icon as home

The action bar shows an icon of your application. This is called the home icon. You can assign an action to this icon. The recommendation is to return to the main activity in your program if the user selects this icon.

If the action is selected, the onOptionsItemSelected() method is called with an action which has theandroid.R.id.home ID.

Before Android 4.1, you had to use the android.R.id.home ID in the onOptionMenuItemSelected() method and enable the selection of the home button. This is demonstrated by the following code in which the SecondActivity activity defines the MainActivity as home.

package com.vogella.android.actionbar.homebutton;

import android.os.Bundle;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.MenuItem;

public class SecondActivity extends Activity {

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

    // enable the home button
    ActionBar actionBar = getActionBar();
    actionBar.setHomeButtonEnabled(true);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case android.R.id.home:
      Intent intent = new Intent(this, MainActivity.class);
      intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
      startActivity(intent);
      break;
      // Something else
    case R.id.action_settings:
      intent = new Intent(this, ThirdActivity.class);
      startActivity(intent);
    default:
      break;
    }
    return super.onOptionsItemSelected(item);
  }

} 

Tip

As of Android 4.1 you can simply set the parentActivityName in theAndroidManifest.xml file pointing to the parent activity.

<activity
  android:name="SecondActivity"
  android:label="@string/app_name"
  android:parentActivityName="MainActivity" >
</activity> 

7.2. Application icon as Up button

You can use the application icon also as Up button, e.g., to go to the parent activity of the current activity. The back button on the device always returns to the previous activity.

Both can be different, for example, if the user started the option to write an email from the home screen, the back button will return the user to the home screen while the Up button would return the user to the activity which shows an overview of all emails.

To enable the Up display, you can use the following code snippet in your activity.

actionBar.setDisplayUseLogoEnabled(false);
actionBar.setDisplayHomeAsUpEnabled(true); 

Note

This snippet only enables the Up display on your home icon. You need to implement the correct behavior in your activity in the onOptionsItemSelected() method. The corresponding action still has the android.R.id.home ID.

Warning

The difference between Up and the Back button can be confusing for the end user. If you decide to implement Up, in your application, it is recommended to perform some end user testing to see if the Up implementation is intuitive for them or not.

8.1. Navigation drawer

A relatively new navigation pattern is the navigation drawer. The navigation drawer is a panel that displays the navigation options on the left side of the screen. It is hidden by default, but can be displayed with a swipe from the left side to the right or if the user touches the app icon.

The usage of the navigation drawer in the Gmail application is depicted in the following screenshot.

Navigation Drawer in Gmail

The navigation drawer is part of the compatibility library v4. To use this navigation pattern, you create a layout with the android.support.v4.widget.DrawerLayout layout manager. This layout manager must contain only two child views. The first is the element for the main content and the second one the container for the drawer menu. The drawer menu is typically implemented with a ListView widget. Such a layout is demonstrated by the following snippet.

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!-- The main content view -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <!-- The navigation drawer -->
     <!-- should not be larger than 320 to show content -->
    <ListView android:id="@+id/left_drawer"
        android:layout_width="180dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#111"/>
</android.support.v4.widget.DrawerLayout> 

You can fill the ListView in your activity code and register a listener via the ListView.OnItemClickListern method on the list item. In this listener you can perform the navigation action. For example, you start a new activity or replace a fragment in your layout.

8.2. Example: Using the navigation drawer

The following example demonstrates the usage of the navigation drawer. If you want to follow this example, create a new Android project and ensure that the support library is added to it.

Tip

To add the support library to a project, right-click on the project and select Android Tools → Add Support Library from the context menu.

Create a layout file called fragment_layout based on the following listing.

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

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:text="Placeholder Text"
        android:layout_gravity="center"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</LinearLayout> 

Afterwards, create the OpertingSystemFragment class for the fragment.

package com.vogella.android.actionbar.navigationdrawer;

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

public class OpertingSystemFragment extends Fragment {
  public static final String ARG_OS= "OS";
  private String string;
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_layout, null);
    TextView textView = (TextView) view.findViewById(R.id.textView1);
    textView.setText(string);
    return view;
  }
  @Override
  public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);  
  }
  @Override
  public void setArguments(Bundle args) {
    string = args.getString(ARG_OS);
  }
} 

Now add a few strings and a string array to your values/strings.xml file.

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

    <string name="app_name">Navigationdrawer</string>
    <string name="action_settings">Settings</string>
    <string name="action_update">Update</string>
    <string name="drawer_open">Open Drawer</string>
    <string name="drawer_close">Close Drawer</string>
    <string name="hello_world">Hello world!</string>
    <string-array name="operating_systems">
        <item >Android</item>
        <item >iPhone</item>
        <item >Windows Mobile</item>
    </string-array>

</resources> 

Finally create the activity as follows.

package com.vogella.android.actionbar.navigationdrawer;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends Activity {
    private String[] mPlanetTitles;
    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
  private ActionBarDrawerToggle mDrawerToggle;
  private CharSequence title;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        title = getActionBar().getTitle();
        mPlanetTitles = getResources().getStringArray(R.array.operating_systems);
        System.out.println(mPlanetTitles.length);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.left_drawer);

        // Set the adapter for the list view
        mDrawerList.setAdapter(new ArrayAdapter<String>(this,
                R.layout.drawer_item,R.id.content, mPlanetTitles));
        // Set the list's click listener
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
        
        mDrawerToggle = new ActionBarDrawerToggle(this,                  /* host Activity */
                mDrawerLayout,         /* DrawerLayout object */
                R.drawable.ic_drawer,  /* nav drawer icon to replace 'Up' caret */
                R.string.drawer_open,  /* "open drawer" description */
                R.string.drawer_close  /* "close drawer" description */) {

            
/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) { getActionBar().setTitle(title); }
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) { getActionBar().setTitle("Open Drawer"); } }; // Set the drawer toggle as the DrawerListener mDrawerLayout.setDrawerListener(mDrawerToggle); getActionBar().setDisplayHomeAsUpEnabled(true); getActionBar().setHomeButtonEnabled(true); } private class DrawerItemClickListener implements ListView.OnItemClickListener { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { selectItem(position); } } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); // Sync the toggle state after onRestoreInstanceState has occurred. mDrawerToggle.syncState(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mDrawerToggle.onConfigurationChanged(newConfig); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { // Pass the event to ActionBarDrawerToggle, if it returns // true, then it has handled the app icon touch event if (mDrawerToggle.onOptionsItemSelected(item)) { return true; } // Handle your other action bar items... switch (item.getItemId()) { case R.id.action_settings: Toast.makeText(this, "Settings selected", Toast.LENGTH_LONG).show(); break; default: break; } return super.onOptionsItemSelected(item); }
/** Swaps fragments in the main content view */
private void selectItem(int position) { // create a new fragment and specify the planet to show based on position Fragment fragment = new OpertingSystemFragment(); Bundle args = new Bundle(); args.putInt(OpertingSystemFragment.ARG_OS, position); fragment.setArguments(args); // Insert the fragment by replacing any existing fragment FragmentManager fragmentManager = getFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.content_frame, fragment) .commit(); // Highlight the selected item, update the title, and close the drawer mDrawerList.setItemChecked(position, true); getActionBar().setTitle((mPlanetTitles[position])); mDrawerLayout.closeDrawer(mDrawerList); } }

This activity uses a navigation drawer icon based on the recommendations of Google. You find an icon set from Google under the following URL: Navigation Drawer Icons.

This should be sufficient to add the navigation drawer to your application.

Tip

The usage of the navigation drawer is currently very popular for Android application. It seem that this navigation pattern is well accepted by end users.

8.3. Tab navigation

Fragments can also be used in combination with the action bar for navigation. For this your main activity needs to implement a TabListener, which is responsible for moving between the tabs.

To add a new tab to the action bar, use the newTab() method.

The following code shows such an activity. It uses dummy activities to demonstrate the switch.

package com.vogella.android.actionbar.tabs;

import android.app.ActionBar;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class MainActivity extends FragmentActivity implements
    ActionBar.TabListener {

  
/** * The serialization (saved instance state) Bundle key representing the * current tab position. */
private static final String STATE_SELECTED_NAVIGATION_ITEM = "selected_navigation_item"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Set up the action bar to show tabs. final ActionBar actionBar = getActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // for each of the sections in the app, add a tab to the action bar. actionBar.addTab(actionBar.newTab().setText(R.string.title_section1) .setTabListener(this)); actionBar.addTab(actionBar.newTab().setText(R.string.title_section2) .setTabListener(this)); actionBar.addTab(actionBar.newTab().setText(R.string.title_section3) .setTabListener(this)); } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { // Restore the previously serialized current tab position. if (savedInstanceState.containsKey(STATE_SELECTED_NAVIGATION_ITEM)) { getActionBar().setSelectedNavigationItem(savedInstanceState.getInt(STATE_SELECTED_NAVIGATION_ITEM)); } } @Override public void onSaveInstanceState(Bundle outState) { // Serialize the current tab position. outState.putInt(STATE_SELECTED_NAVIGATION_ITEM, getActionBar() .getSelectedNavigationIndex()); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { // When the given tab is selected, show the tab contents in the // container view. Fragment fragment = new DummySectionFragment(); Bundle args = new Bundle(); args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, tab.getPosition() + 1); fragment.setArguments(args); getFragmentManager().beginTransaction() .replace(R.id.container, fragment).commit(); } @Override public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { } @Override public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { }
/** * A dummy fragment representing a section of the app */
public static class DummySectionFragment extends Fragment { public static final String ARG_SECTION_NUMBER = "placeholder_text"; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { TextView textView = new TextView(getActivity()); textView.setGravity(Gravity.CENTER); textView.setText(Integer.toString(getArguments().getInt(ARG_SECTION_NUMBER))); return textView; } } }

8.4. Dropdown menu navigation

You can also use a spinner in the action bar. The following code demonstrates such an implementation.

package com.vogella.android.actionbar.spinner;

import android.app.ActionBar;
import android.app.Fragment;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class MainActivity extends FragmentActivity implements
    ActionBar.OnNavigationListener {

  
/** * The serialization (saved instance state) Bundle key representing the * current dropdown position. */
private static final String STATE_SELECTED_NAVIGATION_ITEM = "selected_navigation_item"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Set up the action bar to show a dropdown list. final ActionBar actionBar = getActionBar(); actionBar.setDisplayShowTitleEnabled(false); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); final String[] dropdownValues = getResources().getStringArray(R.array.dropdown); // Specify a SpinnerAdapter to populate the dropdown list. ArrayAdapter<String> adapter = new ArrayAdapter<String>(actionBar.getThemedContext(), android.R.layout.simple_spinner_item, android.R.id.text1, dropdownValues); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // Set up the dropdown list navigation in the action bar. actionBar.setListNavigationCallbacks(adapter, this); // use getActionBar().getThemedContext() to ensure // that the text color is always appropriate for the action bar // background rather than the activity background. } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { // Restore the previously serialized current dropdown position. if (savedInstanceState.containsKey(STATE_SELECTED_NAVIGATION_ITEM)) { getActionBar().setSelectedNavigationItem(savedInstanceState.getInt(STATE_SELECTED_NAVIGATION_ITEM)); } } @Override public void onSaveInstanceState(Bundle outState) { // Serialize the current dropdown position. outState.putInt(STATE_SELECTED_NAVIGATION_ITEM, getActionBar() .getSelectedNavigationIndex()); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override public boolean onNavigationItemSelected(int position, long id) { // When the given dropdown item is selected, show its contents in the // container view. Fragment fragment = new DummySectionFragment(); Bundle args = new Bundle(); args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1); fragment.setArguments(args); getFragmentManager().beginTransaction() .replace(R.id.container, fragment).commit(); return true; }
/** * A dummy fragment */
public static class DummySectionFragment extends Fragment { public static final String ARG_SECTION_NUMBER = "placeholder_text"; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { TextView textView = new TextView(getActivity()); textView.setGravity(Gravity.CENTER); textView.setText(Integer.toString(getArguments().getInt(ARG_SECTION_NUMBER))); return textView; } } }

8.5. Evaluation

While the navigation drawer is relatively new compared to the other options, it is pretty popular among users and Android applications. If in doubt which options to select, consider using the navigation drawer.

9. Exercise: ActionBar

9.1. Project

This chapter will demonstrate how to create actions in the action bar and react to the selection of the user.

It is based on the fragment tutorial which can be found under Android fragments tutorial. If you have already created this project, you can continue to reuse it. If not, the following describes the required setup to continue with this tutorial.

10. Exercise: Add an action bar to your application

10.1. Create an icon for the ActionBar

Continue to use the com.example.android.rssfeed project.

Use File → New → Other... → Android → Android Icon Set to create a refresh icon for your action bar. The wizard allows you to select which type of icons you want to create. Specify the name ic_refresh for the new icon and select a corresponding entry from the clipart.

Note

The Android design page also provides prepared icons for the ActionBar. You find the downloads on the following webpage.

http://developer.android.com/design/downloads/index.html 

If you choose to download and use these icons, select a fitting for a refresh action and place it into the /res/drawable-mdpi folder. Make sure that the filename of your icon isic_action_refresh

Warning

Icon filenames are not allowed to contain special character, cannot start with a number and must be in lower case.

10.2. Add a menu XML resource

Create a new XML resource called mainmenu.xml for your menu.

To create this XML file, select your project, right click on it and select File → New → Other... → Android → Android XML File.

Select the Menu option, enter mainmenu.xml as the filename and press the Finish button.

Creating a new XML resource for the menu

This creates a new menu file in the res/menu folder of your project.

10.3. Add actions to your menu resource

Open the mainmenu.xml file and select the Layout tab of the Android editor.

Press the Add button and select the Item entry.

Select Add in the Android menu editor

Select to add an item in the Android menu editor

Enter an entry similar to the following screenshot.

How to maintain the menu entries in an menu xml file

Add a second action to your menu. Use Refresh as the title attribute and action_refresh as the ID attribute.

Add a second entry to the menu with the ID attribute set to @+id/action_settings and the Title attribute set toSetting. Set the android:showAsAction to never.

10.4. Assign icons

Use the XML editor to assign the @drawable/ic_action_refresh to the action_refresh action via its android:iconproperty. You created or downloaded this icon in Section 10.1, “Create an icon for the ActionBar”.

Tip

It is suggested to add this icon to the action via the XML editor as the structured editor used to create invalid XML if you add it here directly. Potentially this bug is already fixed if you read this text.

10.5. Validate XML resource

The resulting XML should look similar to the following listing.

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

    <item
        android:id="@+id/action_refresh"
        android:orderInCategory="100"
        android:showAsAction="always"
        android:icon="@drawable/ic_action_refresh"
        android:title="Refresh"/>
    <item
        android:id="@+id/action_settings"
        android:title="Settings"
        android:showAsAction="never"
        >
    </item>

</menu> 

10.6. Add the action bar to your activity

Change your RssfeedActivity class to the following code to use the new menu resource file.

package com.example.android.rssfeed;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class RssfeedActivity extends Activity implements
    MyListFragment.OnItemSelectedListener {
  // Unchanged
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_rssfeed);
  }
  
  //NEW
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.mainmenu, menu);
    return true;
  }
  
  //NEW
  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.action_refresh:
      Toast.makeText(this, "Action refresh selected", Toast.LENGTH_SHORT)
          .show();
      break;
    case R.id.action_settings:
      Toast.makeText(this, "Action Settings selected", Toast.LENGTH_SHORT)
          .show();
      break;

    default:
      break;
    }

    return true;
  }

  // Other methods which this class implements
} 

10.7. Run the application and test the action bar

Run your application and validate that you can select both of your actions. Ensure that the correct info message is displayed if you select the different entries.

Social App running

Tip

If your device or emulator has an Option menu button, you will not see the overflow menu. Press the Option key to see your second action.

10.8. Remove the refresh button

If you have a refresh button in your fragment layout, you can remove it, as the action is used for the refresh operation.

11. Exercise: Using the contextual action mode

Create a project called de.vogella.android.socialapp with an activity called OverviewActivity.

Add an EditText element to your main.xml layout file.

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

    <EditText
        android:id="@+id/myView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10" >

        <requestFocus />
    </EditText>

</LinearLayout> 

Create a new menu XML resource with the contextual.xml file name.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:id="@+id/toast"
        android:title="Toast">
    </item>

</menu> 

Change your activity based on the default template to the following example.

package de.vogella.android.socialapp;

import android.app.Activity;
import android.os.Bundle;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;

public class OverviewActivity extends Activity {
  protected Object mActionMode;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    // define the contextual action mode
    View view = findViewById(R.id.myView);
    view.setOnLongClickListener(new View.OnLongClickListener() {
      // called when the user long-clicks on someView
      public boolean onLongClick(View view) {
        if (mActionMode != null) {
          return false;
        }

        // start the CAB using the ActionMode.Callback defined above
        mActionMode = OverviewActivity.this
            .startActionMode(mActionModeCallback);
        view.setSelected(true);
        return true;
      }
    });
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.mainmenu, menu);
    return true;
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    Toast.makeText(this, "Just a test", Toast.LENGTH_SHORT).show();
    return true;
  }

  private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {

    // Called when the action mode is created; startActionMode() was called
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
      // inflate a menu resource providing context menu items
      MenuInflater inflater = mode.getMenuInflater();
      // assumes that you have "contexual.xml" menu resources
      inflater.inflate(R.menu.contextual, menu);
      return true;
    }

    // called each time the action mode is shown. Always called after
    // onCreateActionMode, but
    // may be called multiple times if the mode is invalidated.
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
      return false; // Return false if nothing is done
    }

    // called when the user selects a contextual menu item
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
      switch (item.getItemId()) {
      case R.id.toast:
        Toast.makeText(OverviewActivity.this, "Selected menu",
            Toast.LENGTH_LONG).show();
        mode.finish(); // Action picked, so close the CAB
        return true;
      default:
        return false;
      }
    }

    // called when the user exits the action mode
    public void onDestroyActionMode(ActionMode mode) {
      mActionMode = null;
    }
  };

} 

If you run this example and long press the EditText view, your contextual action bar is displayed.

Contextual ActionBar demonstrated


'Android > GUI & Activity' 카테고리의 다른 글

앱 최신버전 체크하는 방법  (0) 2014.11.19
Animation 종류  (0) 2014.10.28
AutoScaleTextView 추천 소스  (0) 2014.10.16
AutoScale TextView (4.4버전 테스트완료)  (0) 2014.10.15
CustomView lifeCycle  (0) 2014.09.30
출처 : http://i5on9i.blogspot.kr/2013/02/loadermanager.html

LoaderManager Sequence Diagram / LoaderManager flowchart / 


android 3.0 이후부터 LoaderManager 를 제공한다. comparability package 를 사용하면 1.6 에서부터 사용가능하다고 한다.


Loaders 의 특징

  1. every Activities or Fragments : 모든 Activity 와 Fragment 에서 가능하다.(한 activity 또는 fragment 당 한개의 LoaderManager 를 갖는다. 한 개의 LoaderManager 는 여러개의 Loaders 를 가질 수 있다.)
  2. async data loading : data의 비동기 loading 을  을 제공한다.
  3. monitor and deliver the data source : data 의 source 를 모니터하면서 content 가 변경되면 전달해 준다.
  4. automatically reconnect : configuratoin 이 바뀐후(orientation 이 변경되는 것 등의)에 다시 만들어 질 때, 자동적으로 마지막으로 사용한 loader의 cursor 에 접속한다. 그래서 data 를 다시 query 할 필요가 없다.
만약 download 를 하고 있고, 그 progress 를 activity 에서 보여주고 있다면, download 를 하는 도중에 화면의 orientation 을 전환하면 값을 잃어버리게 된다. 이런 경우에 LoaderManager 를 이용하면 좋다고 한다.[ref. 9]



Loader Callbacks

LoaderManager 가 시작할 때 , 끝날 때 우리가 원하는 일을 시킬 수 있다. 이 일을 하는 것이 LoaderCallbacks 이다. 이 LoaderCallbacks 는 LoaderManager.initLoader() 에서 register 하게 된다.


LoaderManager.LoaderCallbacks<?> 을 implement 하면
  • onCreateLoader()
  • onLoadFinished()
  • onLoaderReset()
를 override 하게 된다. 여기서는 이 함수가 호출되는 시점을 알아보자.
  1. onCreateLoader() : getLoaderManager().initLoader()(support library 에서는 getSupportLoaderManager().initLoader) 를 호출하면 바로 onCreateLoader() 가 호출된다.
  2. onLoadFinished() : onStart() 이후, AsyncTask 가 동작을 시작한다. 이 AsyncTask 동작이 끝나면, onLoadFinished() 가 호출된다. 이 곳에는 data 가 load 되고 난 후의 UI update 내용을 적으면 된다.
  3. onLoadReset() : android.app.LoaderManager,restartLoader()에서 새로운 loader 를 가져오고 쓰이지 않는 loader 를 destroy() 하는데 이 때 destroy() 에서 onLoadReset() 이 호출된다.


ref. 6에서 LoaderManager 를 잘 설명해 주고 있다. 그리고 ref. 6의 글쓴이가 만든 source 이다.
https://github.com/alexjlockwood/AppListLoader
이 source 에서는 Fragment 가 LoaderManager.LoaderCallbacks 를 implement 하고 있으니 참고하자.
class AppListFragment extends ListFragment implements
      LoaderManager.LoaderCallbacks<List<AppEntry>>
아래는 위의 소스에 대한 대략적인 sequence diagram 이다.
소스는 대략적으로 아래처럼 동작한다.
  1. AppListFragment 에서 LoaderManager.initLoader() 를 호출(onStart() 이전에 호출해야할 듯 하다.)하면서, AppListFragment 를 LoaderCallBack 으로 등록하고,
  2. LoaderManager 가 onCreateLoader() 를 호출
  3. AppLoader() 가 만들어진다.
  4. Activity 가 만들어지면서 onStart() 를 호출할 때
  5. LoadManager.doStart() 를 호출하게 되고,
  6. AppLoader 의 startLoading() 을 호출한다.
  7. 이 때 forceLoading() 을 호출하는데,
  8. 이 forceLoading() (AsyncTaskLoader.onForceLoading()) 이 LoadTask() 를 만들고 Thread 를 이용해서 실행한다.
  9. 그러면 thread 가 doInBackground() 를 실행하게 되고,
  10. 이 작업이 끝난 후에 onPostExecute() 를 UI thread Handler 에게 넘기게 된다.
  11. 이 onPostExecute() 를 실행하면서 AppLoader 의 deliveryResult() 가 호출된다.
  12. 이 때 super.deliveryResult() 를 실행하면, onLoadFinished() 를 호출해 준다.

Diagrams

LoaderManager_seqDiagram


 +--------------------------+------------------------+
 |                          |                        |
 |   +-------------------+  |                        |
 |   | onCreateLoader()  |  |                        |
 |   +--------+----------+  |                        |
 |            |             |                        |
 |   +--------+----------+  |                        |
 |   | onStartLoading()  +--|-----------+            |
 |   +-------------------+  |           |            |
 |                          |           |            |
 |                          |  +--------+----------+ |
 |            +-------------|--+ loadInBackground()| |
 |            |             |  +-------------------+ |
 |            |             |                        |
 |   +--------+----------+  |                        |
 |   | deliverResult()   |  |                        |
 |   +--------+----------+  |                        |
 |            |             |                        |
 |   +--------+----------+  |                        |
 |   | onLoadFinished()  |  |                        |
 |   +-------------------+  |                        |
 +--------------------------+------------------------+



Stacks


AppListLoader : public class AppListLoader extends AsyncTaskLoader<List<AppEntry>>

UI Thread
Stack trace 

MainActivity$AppListFragment.onCreateLoader(int, Bundle) line: 87 
LoaderManagerImpl.createLoader(int, Bundle, LoaderManager$LoaderCallbacks) line: 487 
LoaderManagerImpl.createAndInstallLoader(int, Bundle, LoaderManager$LoaderCallbacks) line: 496 
LoaderManagerImpl.initLoader(int, Bundle, LoaderManager$LoaderCallbacks) line: 550 
MainActivity$AppListFragment.onActivityCreated(Bundle) line: 77 
FragmentManagerImpl.moveToState(Fragment, int, int, int, boolean) line: 892 
FragmentManagerImpl.moveToState(int, int, int, boolean) line: 1083 
BackStackRecord.run() line: 635 
FragmentManagerImpl.execPendingActions() line: 1431 
MainActivity(FragmentActivity).onStart() line: 523 
Instrumentation.callActivityOnStart(Activity) line: 1133 
MainActivity(Activity).performStart() line: 4475
... 


UI Thread
Stack trace 

AppListLoader.onStartLoading() line: 129 
AppListLoader(Loader).startLoading() line: 197 
LoaderManagerImpl$LoaderInfo.start() line: 263 
LoaderManagerImpl.doStart() line: 711 
MainActivity$AppListFragment(Fragment).onStart() line: 985 
MainActivity$AppListFragment(Fragment).performStart() line: 1336 
FragmentManagerImpl.moveToState(Fragment, int, int, int, boolean) line: 907 
FragmentManagerImpl.moveToState(int, int, int, boolean) line: 1083 
FragmentManagerImpl.moveToState(int, boolean) line: 1065 
FragmentManagerImpl.dispatchStart() line: 1849 
MainActivity(FragmentActivity).onStart() line: 536 
Instrumentation.callActivityOnStart(Activity) line: 1133 
MainActivity(Activity).performStart() line: 44753
... 


Stack trace 


AppListLoader.loadInBackground() line: 52 
AppListLoader.loadInBackground() line: 1 
AppListLoader(AsyncTaskLoader).onLoadInBackground() line: 240 
AsyncTaskLoader$LoadTask.doInBackground(Void...) line: 51 
AsyncTaskLoader$LoadTask.doInBackground(Object[]) line: 40 
ModernAsyncTask$2.call() line: 123
... 


UI Thread
Stack trace 

AppListLoader.deliverResult(List) line: 86 
AppListLoader.deliverResult(Object) line: 1 
AppListLoader(AsyncTaskLoader).dispatchOnLoadComplete(AsyncTaskLoader$LoadTask, Object) line: 221 
AsyncTaskLoader$LoadTask.onPostExecute(Object) line: 61 
AsyncTaskLoader$LoadTask(ModernAsyncTask).finish(Object) line: 461 
... 




UI Thread
Stack trace 

MainActivity$AppListFragment.onLoadFinished(Loader, List) line: 92 
MainActivity$AppListFragment.onLoadFinished(Loader, Object) line: 1 
LoaderManagerImpl$LoaderInfo.callOnLoadFinished(Loader, Object) line: 425 
LoaderManagerImpl$LoaderInfo.onLoadComplete(Loader, Object) line: 393 
AppListLoader(Loader).deliverResult(Object) line: 103 
AppListLoader.deliverResult(List) line: 111 
AppListLoader.deliverResult(Object) line: 1 
AppListLoader(AsyncTaskLoader).dispatchOnLoadComplete(AsyncTaskLoader$LoadTask, Object) line: 221 
AsyncTaskLoader$LoadTask.onPostExecute(Object) line: 61 
AsyncTaskLoader$LoadTask(ModernAsyncTask).finish(Object) line: 461 
...



See Also

  1. How to Use Loaders in Android | Grokking Android

References

  1. SimpleCursorLoader - content provider 가 필요없는 loader
  2. SimpleCursorLoader Example
  3. Android tutorial: Simple (but persistent) data storage with SQLite
  4. Get Started Developing For Android With Eclipse, Reloaded
  5. https://github.com/alexjlockwood/AppListLoader
  6. Life Before Loaders (part 1)
  7. http://code.google.com/codesearch#vhKRzqrOaj0/trunk/src/org/ray/veader/DataHelper.java&ct=rc&cd=14&q=openOrCreateDatabase&sq=
  8. Loaders | Android Developers
  9. Android Development - Example, tutorial, Source Code : Custom Loader : Loading data using Loader Manager in android asynchronously
  10. How to Use Loaders in Android | Grokking Android


'Android > Tip&Tech' 카테고리의 다른 글

npm 및 bower 설치..  (0) 2014.11.18
안드로이드 추천 팁 링크  (0) 2014.11.07
[펌]안드로이드 Loader 활용하기  (0) 2014.10.21
자바 표준 스타일 정의  (0) 2014.09.30
[링크]아날로그 시계 만드는 소스  (0) 2014.08.26

+ Recent posts