web analytics

Android Code : สร้าง App Widget เบื้องต้น ตอนที่ 3

cover-1

จากบทความ Widget ก่อนหน้านี้ด้พูดถึงการสร้าง App Widget แบบครบถ้วนพอสมควรแล้ว แต่ยังเหลืออีกนิดหน่อย บทความนี้เป็นภาคเสริมครับ ผมมีโอกาสได้ทำวิตเจ็ตเครื่องคิดเลข ก็เลยจะมาสรุปในบทความนี้ครับ ย้ำว่าต้องอ่านสองตอนก่อนหน้านี้ก่อนนะครับ เพราะเดี๋ยวจะไม่เข้าใจ

บทความตอนก่อนหน้านี้

Android Code : สร้าง App Widget เบื้องต้น ตอนที่ 1

https://benzneststudios.com/blog/android/how-to-create-app-widget-2/

 

สร้าง Layout

ก่อนอื่นสร้าง layout ตามต้องการก่อนครับ ผมจะทำเครื่องคิดเลขก็เขียนได้แบบนี้
ตั้งชื่อว่า widget_calculator_standard.xml ละกัน

1

 

กำหนด Appwidget provider

กำหนดตั้งค่าต่างๆใน widget ครับ ที่ไฟล์ appwidget.xml ตรงนี้ก็คือเอา layout ที่ทำมากำหนดที่ initialLayout

2

 

ส่วนไฟล์ provider_path.xml ก็ทำเหมือนเดิม

3

 

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 ของทุกปุ่มนั่นเอง

7 4

 

Problem loading widget

ในหลายๆครั้ง ก็พบปัญหาว่าทำไม มันเกิด Error ขึ้นแบบข้างล่างนี้

6

 

ให้เราไปดูที่ Android monitor โดยเลือกแบบ No filters
เช่นตัวอย่างนี้คือ มันไม่ให้ใช้ View แบบเพียวๆ ใน Widget พร้อมบอกบรรทัดด้วย ว่าแก้ตรงไหน

5

 

สรุป

บทความนี้พามาทำ Widget แบบมีปุ่มแล้วทำ PendingIntent ในตัวเอง คือกดปุ่มแล้วใส่ข้อความใน textView สามารถนำปประยุกต์ได้ในหลายๆเรื่องใน widget ครับ