有高手能说一下alarm manager应该怎么用吗?
androidstudio吧
全部回复
仅看楼主
level 3
这两天写一个简单的APP,希望每个小时记录一下当前走路的步数,用alarm manager设定了触发器,结果发现只有APP在前台的时候才起作用。手机熄屏或者APP在后台的时候都不起作用,看了很多相关文章,好像根本无解。
2025年04月25日 08点04分 1
level 2
安卓系统版本更新,会做出各种修改限制。现在应用程序的后台能力被大幅限制,你需要在通知栏发个常驻通知,或者显示一个悬浮窗,或者创建个前台服务保证程序不被限制
2025年04月25日 13点04分 2
感谢大神的指教
2025年04月27日 03点04分
@无忧斋散人 我也是自己弄helloworld自己弄着玩的。安卓的东西变来变去的又多又杂
2025年04月27日 03点04分
@滴水穿石柔克刚 还好现在有各种AI工具,这要是全靠自己查资料真的要累死。刚试了一下,后台进程出来了,通知信息也有了,还要打开允许后台行为权限,真是够复杂的,再测试一晚上,看看好不好使。
2025年04月27日 14点04分
level 3
感谢大神
2025年04月26日 10点04分 3
level 3
鼓捣出来了,还挺复杂,需要创建一个service还需要创建一个notification发一个常驻通知,下面把代码分享出来,有兴趣的同学可以参考一下。
2025年05月01日 07点05分 4
level 3
MainActivity.java:
package com.example.myalarm;
import android.os.Bundle;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class MainActivity extends AppCompatActivity {
private TextView timeTextView;
private static final String FILE_NAME = "time_log.txt";
private static final String TAG = "MyAlarm";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
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;
});
timeTextView = findViewById(R.id.logText);
timeTextView.setText("Alarm Manager测试代码,设置每分钟一次的Alarm,可后台运行,锁屏也可触发\n" +
"需要以下权限:\n" +
"1、通知管理权限\n" +
"2、允许完全后台行为(在耗电管理中设置)\n" +
"点击刷新日志查看触发情况\n" +
"测试完成后请立即卸载,以免占用手机资源");
writeLogToFile("\nAlarm Manager测试代码,设置每分钟一次的Alarm,可后台运行,锁屏也可触发\n" +
"需要以下权限:\n" +
"1、通知管理权限\n" +
"2、允许完全后台行为(在耗电管理中设置)\n" +
"点击刷新日志查看触发情况\n" +
"测试完成后请立即卸载,以免占用手机资源");
writeLogToFile("启动程序...");
//启动Service
startService();
// 为刷新按钮添加点击事件监听器
Button refreshButton = findViewById(R.id.log_button);
refreshButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
displayFileContent();
}
});
}
private void startService() {
Intent serviceIntent = new Intent(this, AlarmService.class);
startService(serviceIntent);
Toast.makeText(this, "服务已启动", Toast.LENGTH_SHORT).show();
}
private void displayFileContent() {
StringBuilder content = new StringBuilder();
try (FileInputStream fis = openFileInput(FILE_NAME);
BufferedReader reader = new BufferedReader(new InputStreamReader(fis))) {
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
} catch (IOException e) {
e.printStackTrace();
}
timeTextView.setText(content.toString());
}
private void writeLogToFile(String log) {
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
String currentTime = timeFormat.format(new Date());
log = "[" + currentTime + "] " + log + "\n";
try (FileOutputStream fos = openFileOutput(FILE_NAME, Context.MODE_APPEND)) {
fos.write((log).getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
2025年05月01日 07点05分 5
level 3
AlarmService.java:
package com.example.myalarm;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.content.IntentFilter;
import android.os.Build;
import android.content.Context;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import java.util.Calendar;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import androidx.core.app.NotificationCompat;
public class AlarmService extends Service {
private static final int NOTIFICATION_ID = 1;
private static final String FILE_NAME = "time_log.txt";
private static final String CHANNEL_ID = "MyAlarmChannel";
private static final String TAG = "AlarmService";
private static final String ACTION_TIME_UPDATE = "com.example.myalarm.TIME_UPDATE";
private static final long INTERVAL = 1 * 60 * 1000; // 1分钟的毫秒数
@Override
public IBinder onBind(Intent intent) {
return null;
}
public void onCreate() {
super.onCreate();
Log.d(TAG, "Service onCreate called");
createNotificationChannel();
startForeground(NOTIFICATION_ID, createNotification());
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 注册定时器广播接收器
IntentFilter filter = new IntentFilter(ACTION_TIME_UPDATE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerReceiver(timeUpdateReceiver, filter, Context.RECEIVER_EXPORTED);
}
}
//设置闹钟,每十分钟触发一次
setAlarmTask();
return START_STICKY;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
"我的脚步服务",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel);
}
}
private Notification createNotification() {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
return new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("MyAlarm")
.setContentText("MyAlarm正在后台运行,请勿关闭。")
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentIntent(pendingIntent)
.build();
}
private void setAlarmTask() {
writeLogToFile("设置每分钟一次的alarm...");
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent myIntent = new Intent(ACTION_TIME_UPDATE);
PendingIntent myPendingIntent = PendingIntent.getBroadcast(
this,
0,
myIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
//alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, alarmCalendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, myPendingIntent);
// 设置闹钟,每1分钟触发一次
if (alarmManager != null) {
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(),
INTERVAL,
myPendingIntent
);
}
}
//Alarm定时器广播接收
private BroadcastReceiver timeUpdateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
writeLogToFile("alarm已触发,进入BroadcastReceiver...");
if (ACTION_TIME_UPDATE.equals(intent.getAction())) {
//调试代码每分钟设置一个定时器,以便测试只用,测试后注释掉
Calendar testCalendar = Calendar.getInstance();
int nextMinute = testCalendar.get(Calendar.MINUTE) + 1;
testCalendar.set(Calendar.MINUTE, nextMinute);
setAlarmTask();
}
}
};
private void writeLogToFile(String log) {
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
String currentTime = timeFormat.format(new Date());
log = "[" + currentTime + "] " + log;
try (FileOutputStream fos = openFileOutput(FILE_NAME, Context.MODE_APPEND)) {
fos.write((log + "\n").getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
2025年05月01日 07点05分 6
level 3
Activity_main.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=".MainActivity">
<ScrollView
android:id="@+id/logScrollView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="1dp"
app:layout_constraintBottom_toTopOf="@+id/log_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0">
<EditText
android:id="@+id/logText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
android:hint="测试日志"
android:inputType="textMultiLine"
android:minHeight="48dp" />
</ScrollView>
<Button
android:id="@+id/log_button"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="刷新日志"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.482"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.976" />
</androidx.constraintlayout.widget.ConstraintLayout>
2025年05月01日 07点05分 7
level 3
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- 声明发送通知的权限 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- 声明前台服务的权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyAlarm"
tools:targetApi="31">
<service
android:name=".AlarmService"
android:foregroundServiceType="dataSync"
android:enabled="true"
android:exported="false">
</service>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
2025年05月01日 07点05分 8
1