Friday, March 29

Android EventBus เมล์นรก ซิ่งทั่วแอพ

Google+ Pinterest LinkedIn Tumblr +

ช่วงนี้เราจะเห็นว่ามีคนเอา Library เกี่ยวกับ EventBus มาเขียนบทความกันบ่อยๆ ตัวนึงที่เห็นบ่อยมากๆ เลยคือ Otto ของ Square ซึ่งเรามักจะเอามาใช้ในการสื่อสารระหว่าง Fragment เพื่อลดความปวดหัวในการเขียน Code แต่ EventBus ก็ยังมีตัวอีกตัวที่น่าสนใจเหมือนกันนั่นก็คือ EventBus ของ GreenRobo ซึ่งเราจะมาดูกัน

EventBus ของ GreenRobo นั่นโดยหลักการแล้วก็คล้ายๆกับ Otto คือมีการ Post ข้อมูลเพื่อ Broadcast แล้วก็มีตัว Subscribe เพื่อรับข้อมูล ซึ่งจะต่างจาก Otto ตรงที่ EventBus สามารถส่งข้อมูลได้ทั้ง MainThread และ BackgroundThread

EventBus-Publish-Subscribe

ถ้าใครอยากรู้ว่า Otto กับ EventBus ต่างกันอย่างไรแบบเต็มๆ สามารถดูได้ที่ Comparison with Square’s Otto

ไหนๆเราก็จะทำความรู้จักกับเจ้า EventBus กันแล้ว เรามาลองดูตัวอย่างการใช้งานง่ายๆกันดีกว่า ผมจะใช้ตัวอย่างจากเว็บ http://code.tutsplus.com/ ซึ่งจะเป็นการใช้ EventBus ส่ง Event เวลาเราเสียบสายชาร์จมาแสดงที่ TextView มาลองทำกันเลยดีกว่า

เริ่มแรกก็ใส่ Library เข้าไปใน gradle ก่อน
[xml] compile ‘de.greenrobot:eventbus:2.4.0’
[/xml]

จากนั้นเราก็มาสร้าง class สำหรับทำเป็น Event กันโดยให้ชื่อว่า ChargingEvent (ตั้งยังไงก็ได้นะครับ) โดยจะเป็น String เพื่อเอาไว้บอกสถานะว่าตอนนี้เสียบสายชาร์จอยู่หรือไม่
[java] public class ChargingEvent {
private String data;

public ChargingEvent(String data){
this.data = data;
}

public String getData(){
return data;
}
}
[/java]

ต่อมาเมื่อเรามี Event แล้ว เราก็ทำตัว Receiver เพื่อรับสถานะการเสียบเลยชาร์จกันเลยดีกว่า โดย class ChargingReceiver จะทำงานเมื่อมีการเสียบสายชาร์จ เดี๋ยวเราจะไปเพิ่ม intent-filter กันใน AndroidManifest.xml กันอีกที
[java] public class ChargingReceiver extends BroadcastReceiver {

private EventBus bus = EventBus.getDefault();

@Override
public void onReceive(Context context, Intent intent) {
ChargingEvent event = null;

// Get current time
Time now = new Time();
now.setToNow();
String timeOfEvent = now.format("%H:%M:%S");

String eventData = "@" + timeOfEvent + " this device started ";
if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
event = new ChargingEvent(eventData + "charging.");
} else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
event = new ChargingEvent(eventData + "discharging.");
}

// Post the event
bus.post(event);
}
}
[/java]

เนื่องจาก EventBus เป็น singleton จึงต้องใส่ EventBus.getDefault() ทุกครั้งก่อนใช้งาน เวลาจะใช้งานเราก็เอา ChargingEvent โยนใส่ bus.post เข้าไปเท่านี้เราก็จะส่ง Event ออกไปยัง Class อื่นๆได้แล้ว

เมื่อมีตัวส่งแล้วก็ต้องมีตัวรับ ผมขอใช้ class MainActivity นี่แหละครับ โดยเราจะรับเอา Event มาจาก onEvent(ChargingEvent event)
***สำคัญมาก อย่าลืมใส่ bus.register(this); ใน onResume() และ bus.unregister(this); ใน onPause() มิฉะนั้นจะรับ Event ไม่ได้และเกิดอาการแอพเด้ง

[java] public class MainActivity extends AppCompatActivity {
private EventBus bus = EventBus.getDefault();
private TextView textDisplay;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textDisplay = (TextView) findViewById(R.id.text_displayevent);
}

@Override
protected void onResume() {
bus.register(this);
super.onResume();
}

@Override
protected void onPause() {
bus.unregister(this);
super.onPause();
}

public void onEvent(ChargingEvent event){
textDisplay.setText(textDisplay.getText() + "\n" + event.getData());
}

}
[/java]

เท่านี้เราก็มีทั้งตัวส่งตัวรับแล้ว แต่อย่าลืมไปใส่ใน AndroidManifest.xml ให้ filter event การเสียบสายชาร์จด้วย
[xml] <application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<receiver android:name=".ChargingReceiver">
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>

</application>
[/xml]

Run แล้วลองเสียบสายชาร์จเข้าๆออกๆดูครับ จะแสดงข้อความแบบนี้

ลองถอดและเสียบสายชาร์จดูนะครับ

ลองถอดและเสียบสายชาร์จดูนะครับ

จะเห็นว่าการใช้ EventBus จะลดการเขียน Code ไปได้มาก (และเพิ่มเวลานอนให้กับ Developer) ถ้าเป็นเมื่อก่อนกว่าจะเขียนให้ส่ง Event มาแบบนี้ได้คงต้องเขียน BroadcastReceiver กันจนเหนื่อยเลย

หากใครสนใจเจ้า EventBus สามารถเข้าไปอ่าน Document หรือใน Github ได้เลยครับ

บทความที่น่าสนใจ
การทำ In-App Billing แบบง่ายๆด้วย Library
A/B Testing in Google Play Store
ทำชีวิตให้ง่ายด้วย Build Variants
ตัวอย่างการใช้ Vibrator ใน Android

Facebook Comments
Share.

About Author

สวัสดีครับ ผมไอซ์ กมลวัฒน์ ผู้ก่อตั้งช่อง Youtube Kamonway และเว็บไซต์ kamonway.com เพื่อช่วยแนะนำความรู้จากเกม และเป็นช่องทางที่ช่วยให้ทุกท่านเล่นเกมอย่างสนุกสนานยิ่งขึ้น

Comments are closed.