Android Code : สร้าง App Widget เบื้องต้น ตอนที่ 3
จากบทความ Widget ก่อนหน้านี้ด้พูดถึงการสร้าง App Widget แบบครบถ้วนพอสมควรแล้ว แต่ยังเหลืออีกนิดหน่อย บทความนี้เป็นภาคเสริมครับ ผมมีโอกาสได้ทำวิตเจ็ตเครื่องคิดเลข ก็เลยจะมาสรุปในบทความนี้ครับ ย้ำว่าต้องอ่านสองตอนก่อนหน้านี้ก่อนนะครับ เพราะเดี๋ยวจะไม่เข้าใจ
บทความตอนก่อนหน้านี้
https://benzneststudios.com/blog/android/how-to-create-app-widget-2/
สร้าง Layout
ก่อนอื่นสร้าง layout ตามต้องการก่อนครับ ผมจะทำเครื่องคิดเลขก็เขียนได้แบบนี้
ตั้งชื่อว่า widget_calculator_standard.xml ละกัน
กำหนด Appwidget provider
กำหนดตั้งค่าต่างๆใน widget ครับ ที่ไฟล์ appwidget.xml ตรงนี้ก็คือเอา layout ที่ทำมากำหนดที่ initialLayout
ส่วนไฟล์ provider_path.xml ก็ทำเหมือนเดิม
MyWidegtProvider
ต่อมาเราจะมาทำให้กดปุ่มที่ widget แล้วเอาเลขไปแสดงใน TextView กัน
เริ่มต้นสร้าง Class MyWidgetProvider แล้ว extends AppWidgetProvider
สร้างตัวแปร สำหรับเก็บ ACTION ด้วย เพราะการคลิกที่ปุ่ม จะต้องสร้าง Intent ไป พอเรารับ intent มาก็เอาไว้ตรวจสอบได้ว่าเป็น action อะไร ของเราหรือป่าว
public static String KEY_WIDGET_BUTTON= "KEY_WIDGET_BUTTON";
ผมสร้าง method เอาไว้สำหรับ set onclick ให้ remoteView ด้วย เพราะมันมีหลายปุ่มจึงแยก method ออกมา
public class MyWidgetProvider extends AppWidgetProvider { public static String KEY_WIDGET_BUTTON= "KEY_WIDGET_BUTTON"; public static RemoteViews rv; public static String expression = ""; public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // loop each App Widget. for (int i = 0; i < appWidgetIds.length; i++) { int rows = 0; int columns = 0; int appWidgetId = appWidgetIds[i]; rv = new RemoteViews(context.getPackageName(), R.layout.widget_standard_calculator); setOnClickButtonOnWidget(context, rv, R.id.btn_num0, KEY_WIDGET_BUTTON, "0"); setOnClickButtonOnWidget(context, rv, R.id.btn_num1, KEY_WIDGET_BUTTON, "1"); // setData widget. appWidgetManager.updateAppWidget(appWidgetId, rv); } private void setOnClickButtonOnWidget(Context context, RemoteViews rv, int viewId, String action, String value) { // } @Override public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) { super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions); int[] appWidgetIds = {appWidgetId}; onUpdate(context, appWidgetManager, appWidgetIds); } }
กำหนด receiver ใน androidManifest
แต่ตรงนี้เพิ่ม action ใน intent-filter เป็นที่อยู่ตัวแปรสำหรับใช้เป็น Action ส่งไปพร้อม Intent
<action android:name="com.benzneststudios.calculatorstory.calculatorstory.widget.MyWidgetProvider.KEY_WIDGET_BUTTON"/>
<receiver android:name=".widget.MyWidgetProvider" android:label="Calculator Story"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> <action android:name="com.benzneststudios.calculatorstory.calculatorstory.widget.MyWidgetProvider.KEY_WIDGET_BUTTON"/> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget"/> </receiver> </application>
ต่อมาก็มา implement ให้ OnClick ของปุ่ม เนื่องจากว่ามันอยู่ใน Widget มันจะต่างจากปกตินิดหน่อย
คือสร้าง Intent ก่อน กำหนด action , ข้อมูล ใน intent
แล้วสร้าง PendingIntent พร้อมใส่ intent ที่สร้างเอาไว้ให้กับมัน แล้วค่อยเอา PendingIntent ใส่ onClick ของ remoteView
PendingIntent ก็คือตามชื่อเลย คือ Intent ที่รอการทำงาน
ผมขอใช้ KEY_WIDGET_BUTTON เป็นทั้ง action แล้วก็ Key ของ Extras เลยนะ
private void setOnClickButtonOnWidget(Context context, RemoteViews rv, int viewId, String action, String value) { Intent intent = new Intent(context, getClass()); intent.setAction(action); intent.putExtra(KEY_WIDGET_BUTTON, String.valueOf(value)); PendingIntent pdi = PendingIntent.getBroadcast(context, viewId, intent, PendingIntent.FLAG_UPDATE_CURRENT); rv.setOnClickPendingIntent(viewId, pdi); }
และเมื่อเรากดที่ปุ่ม PendingIntent จะทำงาน แล้ว method onReceive จะถูกเรียก พร้อมกับส่ง intent ที่เราแนบไว้กับมันมาด้วย
ตรงนี้เองเราก็ implement ว่าคลิกปุ่มแล้วให้ทำอะไร ผมให้เอาข้อความที่ส่งมาแปะไปที่ช่อง TextView
@Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); if (intent.getAction().equals(KEY_WIDGET_BUTTON)) { String value = intent.getExtras().getString(KEY_WIDGET_BUTTON); if (value.equals(KEY_WIDGET_BUTTON)) { MyWidgetProvider.expression += "" + intent.getExtras().getString(MyConstantApp.KEY_WIDGET_BUTTON); rv.setTextViewText(R.id.tv_result, "" + MyWidgetProvider.expression); } AppWidgetManager.getInstance(context).updateAppWidget(new ComponentName(context, MyWidgetProvider.class), rv); } }
ลองทดสอบดูเลย ลาก widget ออกมาก็จะสามารถกดปุ่มได้แล้ว จากนั้นก็ไปเพิ่ม remoteView ของทุกปุ่มนั่นเอง
Problem loading widget
ในหลายๆครั้ง ก็พบปัญหาว่าทำไม มันเกิด Error ขึ้นแบบข้างล่างนี้
ให้เราไปดูที่ Android monitor โดยเลือกแบบ No filters
เช่นตัวอย่างนี้คือ มันไม่ให้ใช้ View แบบเพียวๆ ใน Widget พร้อมบอกบรรทัดด้วย ว่าแก้ตรงไหน
สรุป
บทความนี้พามาทำ Widget แบบมีปุ่มแล้วทำ PendingIntent ในตัวเอง คือกดปุ่มแล้วใส่ข้อความใน textView สามารถนำปประยุกต์ได้ในหลายๆเรื่องใน widget ครับ