IBinder 实现
1、Service
java
复制代码
public class FloatTextService extends Service {
private TextView tvFloat;
private WindowManager windowManager;
private final IBinder binder = new FloatTextServiceBinder();
public class FloatTextServiceBinder extends Binder {
public FloatTextService getService() {
return FloatTextService.this;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
super.onCreate();
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
// 创建布局参数
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
);
// 设置位置为左下角
params.gravity = Gravity.BOTTOM | Gravity.START;
params.x = 0;
params.y = 0;
LayoutInflater inflater = LayoutInflater.from(this);
tvFloat = (TextView) inflater.inflate(R.layout.float_text, null);
// 添加到窗口
windowManager.addView(tvFloat, params);
}
public void showFloatText(String text) {
tvFloat.setText(text);
}
@Override
public void onDestroy() {
super.onDestroy();
if (tvFloat != null) {
windowManager.removeView(tvFloat);
}
}
}
xml
复制代码
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv_float"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="12dp"
android:textSize="14sp" />
2、Manifest
xml
复制代码
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<application>
...
<service
android:name=".viewfixed.service.FloatTextService"
android:enabled="true"
android:exported="false" />
</application>
3、Activity Layout
- activity_float_text_service_test.xml
xml
复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".viewfixed.FloatTextServiceTestActivity">
<Button
android:id="@+id/btn_show_float_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="显示悬浮文本"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
4、Activity Code
- FloatTextServiceTestActivity.java
java
复制代码
public class FloatTextServiceTestActivity extends AppCompatActivity {
private ActivityResultLauncher<Intent> floatPermissionLauncher;
private FloatTextService floatTextService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_float_text_service_test);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
test();
}
private void test() {
floatPermissionLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (checkFloatPermission()) {
createFloatText();
} else {
Toast.makeText(this, "未开启浮窗权限", Toast.LENGTH_SHORT).show();
}
}
);
if (checkFloatPermission()) {
createFloatText();
} else {
requestFloatPermission();
}
Button btnShowFloatText = findViewById(R.id.btn_show_float_text);
btnShowFloatText.setOnClickListener(v -> {
floatTextService.showFloatText("Hello Float Text");
});
}
private boolean checkFloatPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return Settings.canDrawOverlays(this);
}
return true;
}
private void requestFloatPermission() {
Intent intent = new Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName())
);
floatPermissionLauncher.launch(intent);
}
private void createFloatText() {
bindService(new Intent(this, FloatTextService.class), new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
FloatTextService.FloatTextServiceBinder binder = (FloatTextService.FloatTextServiceBinder) iBinder;
floatTextService = binder.getService();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
}, BIND_AUTO_CREATE);
}
}
BroadcastReceiver 实现
1、Service
java
复制代码
public class FloatTextService extends Service {
private TextView tvFloat;
private WindowManager windowManager;
private final IBinder binder = new FloatTextServiceBinder();
public class FloatTextServiceBinder extends Binder {
public FloatTextService getService() {
return FloatTextService.this;
}
}
public static final String ACTION = "SHOW_FLOAT_TEXT";
private BroadcastReceiver FloatTextServiceBroadcastReceiver;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
super.onCreate();
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
// 创建布局参数
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
);
// 设置位置为左下角
params.gravity = Gravity.BOTTOM | Gravity.START;
params.x = 0;
params.y = 0;
LayoutInflater inflater = LayoutInflater.from(this);
tvFloat = (TextView) inflater.inflate(R.layout.float_text, null);
// 添加到窗口
windowManager.addView(tvFloat, params);
FloatTextServiceBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra("text")) {
String newText = intent.getStringExtra("text");
tvFloat.setText(newText);
}
}
};
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION);
registerReceiver(FloatTextServiceBroadcastReceiver, intentFilter);
}
public void showFloatText(String text) {
tvFloat.setText(text);
}
@Override
public void onDestroy() {
super.onDestroy();
if (tvFloat != null) {
windowManager.removeView(tvFloat);
}
}
}
xml
复制代码
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv_float"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="12dp"
android:textSize="14sp" />
2、Manifest
xml
复制代码
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<application>
...
<service
android:name=".viewfixed.service.FloatTextService"
android:enabled="true"
android:exported="false" />
</application>
3、Activity Layout
- activity_float_text_service_test.xml
xml
复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".viewfixed.FloatTextServiceTestActivity">
<Button
android:id="@+id/btn_show_float_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="显示悬浮文本"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
4、Activity Code
- FloatTextServiceTestActivity.java
java
复制代码
public class FloatTextServiceTestActivity extends AppCompatActivity {
private ActivityResultLauncher<Intent> floatPermissionLauncher;
private FloatTextService floatTextService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_float_text_service_test);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
test();
}
private boolean checkFloatPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return Settings.canDrawOverlays(this);
}
return true;
}
private void requestFloatPermission() {
Intent intent = new Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName())
);
floatPermissionLauncher.launch(intent);
}
private void createFloatText() {
bindService(new Intent(this, FloatTextService.class), new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
FloatTextService.FloatTextServiceBinder binder = (FloatTextService.FloatTextServiceBinder) iBinder;
floatTextService = binder.getService();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
}, BIND_AUTO_CREATE);
}
private void test() {
floatPermissionLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (checkFloatPermission()) {
createFloatText();
} else {
Toast.makeText(this, "未开启浮窗权限", Toast.LENGTH_SHORT).show();
}
}
);
if (checkFloatPermission()) {
createFloatText();
} else {
requestFloatPermission();
}
Button btnShowFloatText = findViewById(R.id.btn_show_float_text);
btnShowFloatText.setOnClickListener(v -> {
Intent intent = new Intent(FloatTextService.ACTION);
intent.putExtra("text", "Hello Float Text");
sendBroadcast(intent);
});
}
}