프로그래밍/안드로이드

안드로이드 - 앱위젯 appwidget 만들기 2탄

가카리 2013. 12. 27. 23:45
반응형

0. History


- 이 글은 2012-01-14 초안 작성 시작하였습니다.
- 잘못된 정보, 오래된 정보, 오타가 있다면 Comment 남겨 주세요. 확인 후 수정하겠습니다.
- 이 글은 2012-01-16 초안 작성 완료하였습니다.




1. Prerequisite & References


- Java에 대한 기초
- Android 에 대한 기초

2012/01/14 - [프로그래밍 놀이터/안드로이드] - [Tutorial] 개념을 통해 배우는 간단한 안드로이드 AppWidget. 함께 만들어 봐요. #1




2. Intro


 

이 글을 왜 쓰시나요?


 이전 Tutorial에서 안드로이드 앱 위젯에 대한 개념을 살펴보았습니다.
하지만 개념만 가지고는 실제로 앱 위젯을 만들기가 참 힘들죠.
개발자들에게는 예제를 통한 학습 가장 빠르고 중요하다고 생각합니다.
그래서 이번 섹션에는 지난 섹션에서 공부한 개념들을 바탕으로 아주아주 간단한 버튼 하나를 가진 앱 위젯을 만들고자 합니다.



 




 

3. Information


 

이번 글은 어떤 식으로 진행되나요?


2012/01/14 - [프로그래밍 놀이터/안드로이드] - [Tutorial] 개념을 통해 배우는 간단한 안드로이드 AppWidget. 함께 만들어 봐요. #1


지난 글을 통해서 앱 위젯을 만들 때 필요한 준비물들과 그 준비물들의 특성, 그리고 조립 방법에 대해 알아보았습니다.  
자 이제 예제를 통해 실제로 조립을 해봅시다.



어떤 위젯을 만들건가요? - Mission


Button 하나를 가지는, 가장 작은 Widget 을 만들 예정입니다.
그 Button 을 클릭했을 때 빈 Activity 하나를 띄워보겠습니다.
( 이것만 하면 뭐 하냐고요?? 나머지는 여러분들이 구현해야죠!! ㅎㅎ 제가 학원 선생도 아니구.. ㅋ )



시작 전에 준비물 좀 다시 되짚고 넘어가요.


네에~ 시작하기 전에 먼저 준비물들을 다시 한번 되짚어보죠.

- AppWidgetProvider class 를 상속하는 provider class 
 
- Widget 의 View Layout 를 기술한 xml 파일
 
- Widget 의 속성 ( Meta data ) 을 기술한 xml 파일 ( AppWidgetProviderInfo 와 매칭 )
 
- 부가적인 것 : Widget 의 configuration 변경을 제공할 activity

 




어서 빨리 만들어봐요~


자 그럼 하나씩 만들어봅시다.
먼저 Widget 의 layout 부터 만들어볼까요? 아주 간단히 버튼 하나를 가진 Widget 을 만들어봅시다요.

 /res/layout/widget_layout.xml

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

 

<Button 
    android:id="@+id/btn"
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content"
    android:text="Click Here!"
    />

 

</LinearLayout>

 

 
자 여기서 약간 주의가 필요합니다.
나중에 AppWidgetProvider 를 상속한 class 를 구현할 때 RemoteViews 라는 class 를 쓰게 됩니다.
이것에 대해서는 나중에 자세히 설명하겠습니다.
 



 


우선은.. 이 RemoteViews 가 지원하는 view 는 한정되어 있다는 것을 기억하면서 layout을 짜야 합니다.
( 모든 layout, view 를 지원하지 않습니다. )

FrameLayout
LinearLayout
RelativeLayout

AnalogClock
Button
Chronometer
ImageButton
ImageView
ProgressBar
TextView

 


위와 같이 Remote가 지원하는 View가 한정됩니다.
이외의 View 는 RemoteView 로 연결이 불가능합니다.
나중가서 "오오. 왜 안 돼지? 열받어!! " 해봐야 소용 없다는 것!
이 부분 별 다섯개입니다. 





자 그럼 위젯의 속성을 지정하는 ( Meta data 를 포함하는 ) xml 입니다.

/res/xml/widget_configuration.xml

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth = "72dp"
android:minHeight = "72dp"
android:initialLayout = "@layout/widget_layout"/>

 

 
자 여기서 minWidth 와 minHeight 를 72 dp 로 둔 이유를 모르시는 분들은..  
요기 다시 돌아가셔서 복습하시기를.!

나머지 속성들도 있지만, 여기서는 딱히 필요가 없기 때문에 기술하지 않겠습니다. 후후..
( configure 를 지정해서 activity 를 띄울 수도 있지만, widget 이 붙는 순간 바로 호출되기 때문에 의도와는 맞지 않죠. )





자 이제 Highlight 로 왔습죠. AppWidgetProvider 를 상속하는 class 입니다.
( 기초만을 정확히 짚어내기 위해 developers 를 95% 참조했습니다. ㅎ )

/src/package/SimpleAppWidget.java

public class SimpleAppWidget extends AppWidgetProvider{

 

 

 

 

 

 

 

@Override

 

 

 

public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
 super.onUpdate(context, appWidgetManager, appWidgetIds);
 for ( int i = 0; i < appWidgetIds.length; i++ ){
int widgetId = appWidgetIds[i];
Intent intent = new Intent( context, ConfigurationAct.class );
PendingIntent pendingIntent = PendingIntent.getActivity( context, 0, intent, 0 );
RemoteViews remoteView = new RemoteViews( context.getPackageName(), R.layout.widget_layout  );
remoteView.setOnClickPendingIntent( R.id.btn, pendingIntent );
appWidgetManager.updateAppWidget( widgetId, remoteView );
}
   }
}

 

 
자 요것도 한눈에 아시겠죠?? ( 응?? )
한눈에 알 수 없다면 아마도 RemoteVIews 와 들어보지 못한 updateAppWidget() 때문이겠죠?

자, 설명 들어갑니다.

닥디로 우선 설명해보면. ( RemoteViews )

다른 process 에서 보여지는 View hierarchy 를 기술하는 class 입니다.

Layout resource file 을 바탕으로 inflate 하고, 이 inflate 한 것을 바탕으로 기본적인 operation 을 줄 수 있습니다.

 


자 아시겠습니까?



 



잘 아시는 분은 아시겠지만, 원래 다른 thread ( process 는 물론 ) 에서는 UI thread 의 view 들을 조작할 수가 없습니다.
( 안드로이드 정책이지요. )
따라서 보통 thread 를 돌릴 때 handler 등을 사용하여 UI handling 을 하는데,
RemoteView 도 일종의 그런 역할을 하는 놈이라고 볼 수 있겠습니다.
Receiver 에서 처리하는 내용이 App Widget 의 View 에 적용되는 것이지요.

자 대~~충은 감이 오실거라 생각하고 코드의 흐름을 설명하면..

update 명령을 받았을 때, 띄워줄 activity 를 intent 로 만들고, 그것을 pending intent 로 감싸줍니다.
RemoteViews 를 통해서 app widget 에서 사용하는 layout 을 inflate 해오고요,
setOnClickPendingIntent( int, PendingIntent ) 를 통해서 그 inflate 해온 놈중에, 
하나의 view 를 click 시 pending intent 를 처리하도록 명령을 주는 것입니다.

마지막으로 이 RemoteViews 를 통해 연결했다는 이 내용이 
실제적으로는 AppWidget 을 관리하는 AppWidgetManager 의
updateAppWidget ( int, RemoteViews ) 를 통해 설정
이 되는 것입니다.

아. 설명 잘 한다. ㅋ




자 그럼 이제는 Manifest 기술과, 떨거지 activity 처리만 남았습니다.

src/package/ConfigurationAct.java

public class ConfigurationAct extends Activity{

}

 

 
목표는 activity 를 띄우는 것이니 여기까지만으로~ ㅎ



지금까지 다 구현했어도, Manifest 에 기술이 안 되면 모두 말짱 꽝입니다.!

AndroidMafniest.xml

<receiver android:name=".SimpleAppWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_configuration"/>
</receiver>

<activity android:name=".ConfigurationAct"/>

 

 
요기서~ 딴 broadcasting 은 알아서 들어오지만.

저기 기술된 APPWIDGET_UPDATE 만은 명시적으로 filter 를 걸어주어야만 합니다.
추가로!!! 지금까지 입이 닳도록 말해왔던 meta data,
widget_configuration.xml 을 meta-data tag 를 통해서 기술해줘야 합니다.
name = "android.appwidget.provider" 는 이 resource 의 형태를 기술해주는 것이죠.


이로써 아주 간단한 App Widget 을 만들어 봤습니다.
모두들 매우 쉽게 만들 수 있을꺼라 믿으며, 만든 것의 스샷을 살짝 올려드립죠. ㅎㅎ


 

 





 

4. Summary


- 예제를 통한 학습은 쉽고 빠르다.

- RemoteViews, PendingIntent, AppWidgetHost.updateWidget 등을 통해 widget 을 구현한다.

- 자세한 사항은 예제를 통해 학습한다.




5. References


-  http://developer.android.com/guide/topics/appwidgets/index.html 
 Android App Widget Dev Guide.




6. Tags

 

 

풀소스 다운은 바로 아래

 

appwidget_ex2.zip

 

출처 : http://aroundck.tistory.com/23