public class SMSToast extends Activity { // ❌ 錯誤:Toast 工具類不應繼承 Activity
public void showToast(Context context, String message) {
LayoutInflater inflater = getLayoutInflater(); // ❌ 錯誤:Activity 尚未附加到視窗,getLayoutInflater() 可能失效
View layout = inflater.inflate(R.layout.toast_sms, (ViewGroup) findViewById(R.id.toast_sms_root));
...
}
}
// BroadcastReceiver 中
SMSToast toast = new SMSToast(); // 實例化 Activity 但未經系統啟動,極度危險
toast.showToast(context, "...");
Activity 必須由系統透過 Intent 啟動,手動 new Activity() 會導致生命週期缺失、Context 不完整、資源洩漏。context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) 取得,而非 Activity.getLayoutInflater()。new Toast(context) 並 setView() 即可,無需繼承任何類別。public final class CustomToast {
private CustomToast() {} // 防止實例化
public static void show(Context context, String message, int duration) {
// 1. 從 Context 取得 LayoutInflater
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// 2. 充氣自訂佈局(root 參數傳 null,因 Toast 會自行加入 WindowManager)
View layout = inflater.inflate(R.layout.toast_sms, null);
// 3. 填充內容
TextView text = layout.findViewById(R.id.toast_sms_text);
text.setText(message);
// 4. 建立並顯示 Toast
Toast toast = new Toast(context);
toast.setDuration(duration);
toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
toast.setView(layout);
toast.show();
}
// 便利多載
public static void showShort(Context context, String message) {
show(context, message, Toast.LENGTH_SHORT);
}
public static void showLong(Context context, String message) {
show(context, message, Toast.LENGTH_LONG);
}
}
@Override
public void onReceive(Context context, Intent intent) {
String msg = "Received SMS from: " + msg_from + " Content: " + msgBody;
CustomToast.showLong(context, msg); // 直接靜態呼叫,傳入 onReceive 的 context
}
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:id="@+id/toast_sms_root"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/toast_bg_rounded"
android:padding="12dp"
android:orientation="horizontal">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_sms"
android:contentDescription="@string/sms_icon" />
<TextView
android:id="@+id/toast_sms_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textColor="@android:color/white"
android:textSize="14sp"
android:maxWidth="280dp"
android:ellipsize="end"
android:singleLine="false" />
</LinearLayout>
LayoutInflater **必須從傳入的 Context 取得系統服務**。inflater.inflate(layoutRes, null):Toast 會自行將 View 加入 WindowManager,root 應為 null。BroadcastReceiver.onReceive 中直接使用參數 context,該 Context 已具備顯示 Toast 的能力。遵循此模式,自訂 Toast 即可在任何元件(Activity、Service、Receiver、Application)中穩定顯示。