티스토리 뷰

Android/Widget

Android Widget - 위젯 Collection

강태종 2021. 12. 3. 11:22

Collection

ListView와 GridView같이 다양한 요소를 표현하는 View는 보통 Adapter와 연결되어 표현합니다. 위젯에도 컬렉션을 표현할 수 있으며 Adapter 연결을 RemoteViewsServiceRemoteViewsFactory로 진행합니다.

즉 개발자는 RemoteViewsFactory를 통해 Adapter의 기능을 구현하고, RemoteViewsService를 통해 RemoteViewsFactory를 생성하여 Collection에 연결할 수 있습니다.


 

RemoteViewsFactory

RemoteViewsFactory를 상속받아 Adapter처럼 구현하면 됩니다. getLoadingView는 Collection을 로딩할 때 보여줄 View를 반환하며 로딩할 때 보여줄 View가 없다면 null을 반환합니다.

class MemoWidgetRemoteViewsFactory(
    private val context: Context,
    private val memoRepository: MemoRepository
) : RemoteViewsService.RemoteViewsFactory {
    private var list = emptyList<Memo>()

    override fun onCreate() {

    }

    override fun onDataSetChanged() {
        runBlocking(Dispatchers.IO) {
            list = memoRepository.findAll()
        }
    }

    override fun onDestroy() {

    }

    override fun getCount(): Int {
        return list.size
    }

    override fun getViewAt(position: Int): RemoteViews {
        return RemoteViews(context.packageName, R.layout.widget_memo_remotes_view).apply {
            setTextViewText(R.id.memo_text_view, list[position].memo)
        }
    }

    override fun getLoadingView(): RemoteViews? {
        return null
    }

    override fun getViewTypeCount(): Int {
        return 1
    }

    override fun getItemId(position: Int): Long {
        return list[position].id.toLong()
    }

    override fun hasStableIds(): Boolean {
        return true
    }
}

 

RemoteViewsService

RemoteViewsService는 RemoteViews에게 Adapter를 제공하는 기능을 합니다. RemoteVeiwsService를 상속받고 onGetViewFactory를 구현하면 됩니다.

@AndroidEntryPoint
class MemoWidgetRemoteViewsService : RemoteViewsService() {
    @Inject
    lateinit var memoRepository: MemoRepository

    override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
        return MemoWidgetRemoteViewsFactory(this, memoRepository)
    }
}

 

RemoteViews

        val intent = Intent(context, MemoWidgetRemoteViewsService::class.java)
        val remoteViews = RemoteViews(context.packageName, R.layout.widget_memo).apply {
            setRemoteAdapter(R.id.list_view, intent)
        }

 

 

내부구조

RemoteViewsService

RemoteViewsService는 Service를 상속받고 있으며 onGetViewFactory를 통해 RemoteViewsFactory를 생성하고 onBind를 통해 RemoteViewsFactoryAdapter를 반환하여 RemoteViews에 Adapter를 제공합니다.

더보기

onGetViewFactory를 통해 RemoteViewsFactory를 생성하는 내부 코드

    @Override
    public IBinder onBind(Intent intent) {
        synchronized (sLock) {
            Intent.FilterComparison fc = new Intent.FilterComparison(intent);
            RemoteViewsFactory factory = null;
            boolean isCreated = false;
            if (!sRemoteViewFactories.containsKey(fc)) {
                factory = onGetViewFactory(intent);
                sRemoteViewFactories.put(fc, factory);
                factory.onCreate();
                isCreated = false;
            } else {
                factory = sRemoteViewFactories.get(fc);
                isCreated = true;
            }
            return new RemoteViewsFactoryAdapter(factory, isCreated);
        }
    }

 

 

RemoteViewsFactoryAdapter

RemoteViewsFactoryAdapter는 생성자로 RemoteViewsFactory를 받는데 getViewAt, getCount 등 Adapter의 주요 기능을 RemoteViewsFactory를 통해 구현합니다.

더보기

RemoteViewsFactoryAdapter가 RemoteViewsFactory에 의존하여 Adapter의 기능을 구현하는 내부 코드

    private static class RemoteViewsFactoryAdapter extends IRemoteViewsFactory.Stub {
        public RemoteViewsFactoryAdapter(RemoteViewsFactory factory, boolean isCreated) {
            mFactory = factory;
            mIsCreated = isCreated;
        }
        public synchronized boolean isCreated() {
            return mIsCreated;
        }
        public synchronized void onDataSetChanged() {
            try {
                mFactory.onDataSetChanged();
            } catch (Exception ex) {
                Thread t = Thread.currentThread();
                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
            }
        }
        public synchronized void onDataSetChangedAsync() {
            onDataSetChanged();
        }
        public synchronized int getCount() {
            int count = 0;
            try {
                count = mFactory.getCount();
            } catch (Exception ex) {
                Thread t = Thread.currentThread();
                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
            }
            return count;
        }
        public synchronized RemoteViews getViewAt(int position) {
            RemoteViews rv = null;
            try {
                rv = mFactory.getViewAt(position);
                if (rv != null) {
                    rv.addFlags(RemoteViews.FLAG_WIDGET_IS_COLLECTION_CHILD);
                }
            } catch (Exception ex) {
                Thread t = Thread.currentThread();
                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
            }
            return rv;
        }
        public synchronized RemoteViews getLoadingView() {
            RemoteViews rv = null;
            try {
                rv = mFactory.getLoadingView();
            } catch (Exception ex) {
                Thread t = Thread.currentThread();
                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
            }
            return rv;
        }
        public synchronized int getViewTypeCount() {
            int count = 0;
            try {
                count = mFactory.getViewTypeCount();
            } catch (Exception ex) {
                Thread t = Thread.currentThread();
                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
            }
            return count;
        }
        public synchronized long getItemId(int position) {
            long id = 0;
            try {
                id = mFactory.getItemId(position);
            } catch (Exception ex) {
                Thread t = Thread.currentThread();
                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
            }
            return id;
        }
        public synchronized boolean hasStableIds() {
            boolean hasStableIds = false;
            try {
                hasStableIds = mFactory.hasStableIds();
            } catch (Exception ex) {
                Thread t = Thread.currentThread();
                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
            }
            return hasStableIds;
        }
        public void onDestroy(Intent intent) {
            synchronized (sLock) {
                Intent.FilterComparison fc = new Intent.FilterComparison(intent);
                if (RemoteViewsService.sRemoteViewFactories.containsKey(fc)) {
                    RemoteViewsFactory factory = RemoteViewsService.sRemoteViewFactories.get(fc);
                    try {
                        factory.onDestroy();
                    } catch (Exception ex) {
                        Thread t = Thread.currentThread();
                        Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
                    }
                    RemoteViewsService.sRemoteViewFactories.remove(fc);
                }
            }
        }

        private RemoteViewsFactory mFactory;
        private boolean mIsCreated;
    }

1. RemoteViews에서 RemoteViewsService를 통해 Adapter를 등록합니다.

2. AppWidgetManager에서 updateAppWidget을 호출하면 RemoteViewsFactory를 생성하여 Adapter와 연결합니다.

3. notifyAppWidgetViewDataChanged를 통해 RemoteViews 일부분을 업데이트 하며 RemoteViewsFactory는 onDataSetChanged 부터 진행하여 업데이트합니다.


 

Git (예제코드)

 

https://github.com/KangTaeJong98/TaeTae98/tree/main/Android/Widget

 

GitHub - KangTaeJong98/TaeTae98: Study Repository

Study Repository. Contribute to KangTaeJong98/TaeTae98 development by creating an account on GitHub.

github.com

 

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

Android Widget - 위젯 설정  (0) 2021.12.02
Android Widget - 위젯 이벤트  (0) 2021.12.02
Android Widget - 위젯 생성  (0) 2021.12.02
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함