안드로이드 개발 예술 탐구'독서노트(5) 제5장 RemoteViews 이해
제5장 RemoteViews 이해
5.1 RemoteViews 응용 프로그램
(1) RemoteViews는 다른 세션에 표시될 수 있는view 구조를 나타냅니다.다른 프로세스에 표시되기 때문에 인터페이스를 업데이트할 수 있도록 RemoteViews는 프로세스를 통해 인터페이스를 업데이트하는 데 사용할 수 있는 기초적인 작업을 제공합니다.(2) RemoteViews는 주로 알림 표시줄 알림과 데스크톱 위젯의 개발에 사용되며, 알림 표시줄 알림은
NotificationManager
의notify
방법을 통해 이루어진다.데스크톱 위젯은 AppWidgetProvider
을 통해 이루어지며, 본질적으로는 라디오 (BroadcastReceiver) 이다.이 두 인터페이스는 모두 SystemServer
프로세스에서 실행된다.(3) Notification에서 RemoteViews 활용 사례Notification notification = new Notification();
notification.icon = R.drawable.ic_launcher;
notification.tickerText = "hello world";
notification.when = System.currentTimeMillis();
notification.flags = Notification.FLAG_AUTO_CANCEL;
Intent intent = new Intent(this, DemoActivity_1.class);
intent.putExtra("sid", "" + sId);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_notification);
remoteViews.setTextViewText(R.id.msg, "chapter_5: " + sId);// textview
remoteViews.setImageViewResource(R.id.icon, R.drawable.icon1);
PendingIntent openActivity2PendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, DemoActivity_2.class), PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.open_activity2, openActivity2PendingIntent);//
notification.contentView = remoteViews;
notification.contentIntent = pendingIntent;
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(sId, notification);
(4) 데스크톱 위젯에서 RemoteViews의 적용 1.작은 위젯 인터페이스 정의하기;2. 위젯 설정 정보 정의:
updatePeriodMillis
위젯의 자동 업데이트 주기를 정의합니다. 단위는 ms입니다.
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/widget"
android:minHeight="84dp"
android:minWidth="84dp"
android:updatePeriodMillis="86400000" >
appwidget-provider>
3. 작은 위젯의 실현 클래스를 정의한다. 책의 예는 한 장의 그림을 표시하는 작은 위젯을 실현하고 작은 위젯을 클릭할 때마다 그림이 일주일 회전한다.
public class MyAppWidgetProvider extends AppWidgetProvider {
public static final String TAG = "MyAppWidgetProvider";
public static final String CLICK_ACTION = "com.ryg.chapter_5.action.CLICK";
public MyAppWidgetProvider() {
super();
}
@Override
public void onReceive(final Context context, Intent intent) {
super.onReceive(context, intent);
Log.i(TAG, "onReceive : action = " + intent.getAction());
// action, , ,
if (intent.getAction().equals(CLICK_ACTION)) {
Toast.makeText(context, "clicked it", Toast.LENGTH_SHORT).show();
new Thread(new Runnable() {
@Override
public void run() {
Bitmap srcbBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.icon1);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
for (int i = 0; i < 37; i++) {
float degree = (i * 10) % 360;
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
remoteViews.setImageViewBitmap(R.id.imageView1, rotateBitmap(context, srcbBitmap, degree));
Intent intentClick = new Intent();
intentClick.setAction(CLICK_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intentClick, 0);
remoteViews.setOnClickPendingIntent(R.id.imageView1, pendingIntent);
appWidgetManager.updateAppWidget(new ComponentName(context, MyAppWidgetProvider.class),remoteViews);
SystemClock.sleep(30);
}
}
}).start();
}
}
/**
*
*/
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
Log.i(TAG, "onUpdate");
final int counter = appWidgetIds.length;
Log.i(TAG, "counter = " + counter);
for (int i = 0; i < counter; i++) {
int appWidgetId = appWidgetIds[i];
onWidgetUpdate(context, appWidgetManager, appWidgetId);
}
}
/**
*
*/
private void onWidgetUpdate(Context context, AppWidgetManager appWidgeManger, int appWidgetId) {
Log.i(TAG, "appWidgetId = " + appWidgetId);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
// " " Intent
Intent intentClick = new Intent();
intentClick.setAction(CLICK_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intentClick, 0);
remoteViews.setOnClickPendingIntent(R.id.imageView1, pendingIntent);
appWidgeManger.updateAppWidget(appWidgetId, remoteViews);
}
private Bitmap rotateBitmap(Context context, Bitmap srcbBitmap, float degree) {
Matrix matrix = new Matrix();
matrix.reset();
matrix.setRotate(degree);
return Bitmap.createBitmap(srcbBitmap, 0, 0, srcbBitmap.getWidth(), srcbBitmap.getHeight(), matrix, true);
}
}
4. AndroidManifest.xml 파일에서 작은 위젯을 설명하는 다음 예에는 두 개의 액션이 포함되어 있습니다. 첫 번째 액션은 작은 위젯의 클릭 행위를 식별하는 데 사용되고, 두 번째 액션은 작은 위젯으로 반드시 존재해야 하는 액션
android.appwidget.action.APPWIDGET_UPDATE
입니다. 추가하지 않으면 작은 위젯을 표시할 수 없습니다.<receiver android:name=".MyAppWidgetProvider" >
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/appwidget_provider_info" >
meta-data>
<intent-filter>
<action android:name="com.ryg.chapter_5.action.CLICK" />
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
intent-filter>
receiver>
(5) AppWidget Provider는 자동으로 방송의 action에 따라
onReceive
방법에 따라 자동으로 방송을 나누어 준다. 즉, 다음과 같은 다른 방법을 호출한다. onEnable
: 작은 위젯이 처음 데스크톱에 추가되었을 때 호출하면 작은 위젯은 여러 번 추가할 수 있지만 처음 추가할 때만 호출할 수 있다.onUpdate
: 작은 부품이 추가되었을 때나 작은 부품이 업데이트될 때마다 이 방법을 한 번씩 사용하고 주기마다 작은 부품이 자동으로 업데이트됩니다.onDeleted
: 작은 위젯을 삭제할 때마다 호출하기;onDisabled
: 마지막으로 이 유형의 작은 위젯이 삭제되었을 때 이 방법을 호출합니다.onReceive
: 이것은 방송에 내장된 방법으로 구체적인 사건을 다른 방법에 나누어 주는 데 사용되기 때문에 이 방법은 일반적으로 호출super.onReceive(context, intent);
해야 한다. 만약에 다른 액션 방송을 사용자 정의한다면 부류 방법을 호출한 후에 판단할 수 있다. 위 코드와 같다.(6)PendingIntent
는 펜딩 상태에 있는 Intent를 나타낸다. 펜딩은 곧 발생할 것이라는 뜻으로 장래의 어느 불확정한 순간에 방생하고 Intent는 즉각 발생한다.(7) PendingIntent는 Activity(getActivity)를 시작하고 서비스(getService)를 시작하며 방송을 보내는 세 가지 미정의 의도를 지원한다.PendingIntent.getActivity(Context context, in requestCode, Intent intent, int flags)
PendingIntent를 획득하여 의도가 발생할 경우 Context와 같은 효과를 냅니다.startActivity(intent).두 번째 매개 변수requestCode
는 Pending Intent 발송자의 요청 코드로 대부분의 경우 0으로 설정하면 되고 Request Code는flags의 효과에 영향을 줄 수 있다.Pending Intent의 일치 규칙: 만약 두 Pending Intent 내부의 Intent가 같고 Request Code도 같다면 이 두 Pending Intent는 같은 것이다.Intent의 일치 규칙: 만약에 두 Intent의ComponentName과 intent-filter가 모두 같다면 이 두 Intent는 같고Extras는 Intent의 일치 과정에 참여하지 않는다.네 번째 파라미터flags에서 흔히 볼 수 있는 유형은 FLAG_ONE_SHOT
,FLAG_NO_CREATE
,FLAG_CANCEL_CURRENT
,FLAG_UPDATE_CURRENT
이다.FLAG_ONE_SHOT
: 현재 설명된 PendingIntent는 한 번만 호출되고 자동으로 cancel됩니다.나중에 동일한 Pending Intent가 있으면 send 메서드 호출이 실패합니다.알림 표시줄 메시지에 대해 이 flag을 사용하면 같은 종류의 알림은 한 번만 사용할 수 있고 후속 알림을 누르면 열 수 없습니다.FLAG_NO_CREATE
: 현재 기술한 Pending Intent는 주동적으로 만들지 않습니다. 현재 Pending Intent가 존재하지 않으면 get Activity, get Service와 get Broadcast 방법은null로 되돌아갑니다. 즉, Pending Intent를 가져오는 데 실패합니다.이 표지의 사용은 매우 적다.FLAG_CANCEL_CURRENT
: 현재 설명된 Pending Intent가 이미 존재하면 cancel에 의해 새 Pending Intent가 생성됩니다.알림 표시줄 메시지에 대해 cancel에 대한 알림을 누르면 열 수 없습니다.FLAG_UPDATE_CURRENT
: 현재 설명된 Pending Intent가 이미 존재하면 모두 업데이트됩니다. 즉, Intent의 Extras가 최신으로 바뀝니다.(8)분석
NotificationManager.nofify(id, notification)
[테스트하지 않아 어지러워 보임] 1.만약 매개 변수 id가 상수라면, notify를 여러 번 호출하면 알림 하나만 팝업할 수 있고, 후속 알림은 앞의 알림을 완전히 대체할 수 있습니다.2. 매개 변수 id가 매번 다르면 Pending Intent가 일치하지 않을 때 어떤 표지 위치를 사용하든 이 통지들은 서로 간섭하지 않는다.3. 매개 변수 id가 매번 다르고 Pending Intent가 일치할 때 표지 위치를 보아야 한다. 만약에 표지 위치가 FLAG 라면ONE_SHOT, 그러면 후속 알림 중의 Pending Intent는 첫 번째 알림과 완전히 일치합니다. 그 중의 Extras를 포함하여 어떤 알림을 눌렀을 때 나머지 알림은 다시 열 수 없습니다. 모든 알림이 지워진 후에 이 과정을 다시 반복합니다.플래그가 FLAG 이면CANCEL_CURRENT, 그러면 최신 알림만 열 수 있고 이전에 팝업한 모든 알림은 열 수 없습니다.플래그가 FLAG 이면UPDATE_CURRENT, 이전에 팝업한 알림의 Pending Intent가 업데이트되고, 최종적으로 최신 알림과 완전히 일치하며, 그 중의 Extras를 포함하여, 이 알림들은 모두 열 수 있습니다.5.2 RemoteViews의 내부 메커니즘
(1) RemoteViews의 구조 방법
public RemoteViews(String packageName, int layoutId)
, 첫 번째 파라미터는 현재 응용되고 있는 패키지 이름이고, 두 번째 파라미터는 불러올 레이아웃 파일이다.(2) RemoteViews는 일부 레이아웃과View 구성 요소만 지원하고 다음에 열거한 구성 요소의 하위 클래스는 지원하지 않는 레이아웃입니다. FrameLayout、LinearLayout、RelativeLayout、GridLayout
구성 요소: Button、ImageButton、ImageView、TextView、ListView、GridView、ViewStub
등 (3) RemoteViews는 일련의 set 방법으로view 설정을 완성했습니다. 이것은 반사로 완성된 호출입니다.예를 들어 방법setInt(int viewId, String methodName, int value)
은view 대상의 이름이methodName인 반사 호출 방법으로 매개 변수value를 전송하고 같은 방법setBoolean
,setLong
등이 있다.방법setOnClickPendingIntent(int viewId, PendingIntent pi)
은view에 클릭 이벤트를 추가하는 데 사용되며 이벤트 유형은 PendingIntent만 가능합니다.(4) 알림과 작은 위젯은 각각 NotificationManager
과 AppWidgetManager
로 관리되며, Binder는 각각 시스템 서버 프로세스NotificationManagerService
와 AppWidgetManagerService
를 통해 통신된다.따라서 레이아웃 파일은 실제로 두 개의 서비스로 로드되며 SystemServer 프로세스에서 실행됩니다.(5) RemoteViews는 Parcelable
인터페이스를 실현하고 Binder를 통해 SystemServer 프로세스에 전달하며 시스템은 RemoteViews의 패키지 이름 정보에 따라 응용 프로그램의 자원을 가져와 레이아웃 파일을 불러옵니다.(6) 시스템은view 작업을Action
대상으로 봉하고 Action은 Parcelable 인터페이스를 실현하여 Binder를 통해 시스템 서버 프로세스에 전달한다.원격 프로세스는 RemoteViewsapply
방법을 통해view 업데이트 작업을 진행하고, RemoteViews의 apply 방법 내부는 모든 액션 대상을 훑어보고 그들의 apply 방법을 호출하여view 업데이트 작업을 진행한다.이렇게 하면 대량의 Binder 인터페이스를 정의할 필요가 없고, 그 다음에 RemoteViews의 업데이트 작업을 대량으로 실행하여 프로그램 성능을 향상시킬 수 있다.(7) RemoteViews의 apply
와 reapply
방법의 차이점: apply
방법은 레이아웃을 불러오고 인터페이스를 업데이트하지만 reapply
방법은 인터페이스만 업데이트한다.(8)setOnClickPendingIntent
,setPendingIntentTemplate
와setOnClickFillIntent
의 차이setOnClickPendingIntent
는 일반적인view에 클릭 이벤트를 추가하는 데 사용되지만 집합(ListView와 StackView)의view에 클릭 이벤트를 설정할 수 없습니다. 비용이 너무 많이 들기 때문입니다.ListView와 StackView의 item에 클릭 이벤트를 추가하려면 setPendingIntentTemplate
와 setOnClickFillIntent
를 결합해서 사용해야 한다.[시도는 하지 않았다.⊙o⊙)]5.3 RemoteViews의 의미
RemoteViews의 가장 큰 의미는 크로스 프로세스의 UI 업데이트를 실현한 것이다. 이 부분에서 저자는 크로스 프로세스의 UI 업데이트, 원본 전송문을 시뮬레이션하는 알림 표시줄 효과의 응용을 실현했다.
OK, 이 장은 끝났습니다. 읽어 주셔서 감사합니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Service Configuration Error MessagesOccasionally, during bootup of Cisco hardware through Cisco IOS software, error messages similar to these are displayed:...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.