Android 计时器重复启动Activity问题(实际为发送广播的坑)

项目场景:

前两天在项目开发过程中,遇到这样的场景,需要做一个时间钟功能,开启时间钟后,在规定的时间(相对时间)到达后,弹出一个Activity。


问题描述:

上述的场景实现不难,通过开启时间钟功能发送广播,在广播接收器中定义Handler计时器,规定时间到达时启动Activity即可。然而,我发现,在规定时间到达时弹出的Activity是两个,哪怕我把这个Ac设定成singleTop启动模式依旧不能解决,这说明启动的这两个Ac实例并不是在一个栈中的。
苦思不得其解后,我请教了前辈。


原因分析:

我们的项目有一个MainActivity,我的模块是SettingActivity,他们同时继承于项目架构中的BaseActivity,我在发送广播的时候,调用的是Fragment(继承于BaseFragment)父类的属性activity,如图
在这里插入图片描述
而进入activity中去看
在这里插入图片描述
可以发现这个ac是被向上转型成了BaseActivity,用这个ac实例来发送广播会导致什么问题呢?
我们进入项目时,是先启动MainActivity,而MainActivity也是BaseActivity的子类,我们发送广播时,用的ac也是BaseActivity类型,这就导致,Java会将所有BaseActivity类型的实例都用来发送一次广播,所以计时器逻辑代码执行两次的原因就是MainActivity被传入一次,SettingActivity被传入一次。

广播接收器中的逻辑在这个例子里不重要,但是还是放出来看一下:

private int intervalTime = KVUtils.getInstance().getInt(Setting.INTERVAL_TIME, 60);

private Handler handler = new Handler() <
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 Android 炫酷倒计时应用的完整代码,其中包括了连接数据库和使用广播接收器的相关代码。 首先,我们需要创建一个数据库帮助类 `CountdownDBHelper`,用于创建和管理数据库: ```java public class CountdownDBHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "countdown.db"; private static final int DATABASE_VERSION = 1; public static final String TABLE_COUNTDOWNS = "countdowns"; public static final String COLUMN_ID = "_id"; public static final String COLUMN_TITLE = "title"; public static final String COLUMN_DATE = "date"; private static final String CREATE_TABLE_COUNTDOWNS = "CREATE TABLE " + TABLE_COUNTDOWNS + "(" + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + COLUMN_TITLE + " TEXT, " + COLUMN_DATE + " TEXT);"; public CountdownDBHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_TABLE_COUNTDOWNS); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + TABLE_COUNTDOWNS); onCreate(db); } } ``` 接下来,我们需要创建一个 `Countdown` 类,用于表示一个倒计时对象,并实现相关的数据库操作: ```java public class Countdown { private long id; private String title; private Date date; public Countdown(long id, String title, Date date) { this.id = id; this.title = title; this.date = date; } public long getId() { return id; } public void setTitle(String title) { this.title = title; } public String getTitle() { return title; } public void setDate(Date date) { this.date = date; } public Date getDate() { return date; } public static List<Countdown> getAllCountdowns(Context context) { List<Countdown> countdowns = new ArrayList<>(); CountdownDBHelper dbHelper = new CountdownDBHelper(context); SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor cursor = db.query(CountdownDBHelper.TABLE_COUNTDOWNS, new String[]{CountdownDBHelper.COLUMN_ID, CountdownDBHelper.COLUMN_TITLE, CountdownDBHelper.COLUMN_DATE}, null, null, null, null, null); while (cursor.moveToNext()) { long id = cursor.getLong(cursor.getColumnIndex(CountdownDBHelper.COLUMN_ID)); String title = cursor.getString(cursor.getColumnIndex(CountdownDBHelper.COLUMN_TITLE)); String dateString = cursor.getString(cursor.getColumnIndex(CountdownDBHelper.COLUMN_DATE)); Date date = new Date(Long.parseLong(dateString)); countdowns.add(new Countdown(id, title, date)); } cursor.close(); db.close(); dbHelper.close(); return countdowns; } public static long addCountdown(Context context, String title, Date date) { CountdownDBHelper dbHelper = new CountdownDBHelper(context); SQLiteDatabase db = dbHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(CountdownDBHelper.COLUMN_TITLE, title); values.put(CountdownDBHelper.COLUMN_DATE, String.valueOf(date.getTime())); long id = db.insert(CountdownDBHelper.TABLE_COUNTDOWNS, null, values); db.close(); dbHelper.close(); return id; } public static void deleteCountdown(Context context, long id) { CountdownDBHelper dbHelper = new CountdownDBHelper(context); SQLiteDatabase db = dbHelper.getWritableDatabase(); db.delete(CountdownDBHelper.TABLE_COUNTDOWNS, CountdownDBHelper.COLUMN_ID + " = ?", new String[]{String.valueOf(id)}); db.close(); dbHelper.close(); } } ``` 接下来,我们需要创建一个 `CountdownAdapter` 类,用于将倒计时对象列表展示在 `RecyclerView` 中: ```java public class CountdownAdapter extends RecyclerView.Adapter<CountdownAdapter.ViewHolder> { private List<Countdown> countdowns; private Context context; public CountdownAdapter(Context context, List<Countdown> countdowns) { this.context = context; this.countdowns = countdowns; } public class ViewHolder extends RecyclerView.ViewHolder { public TextView titleTextView; public TextView countdownTextView; public ViewHolder(View itemView) { super(itemView); titleTextView = itemView.findViewById(R.id.titleTextView); countdownTextView = itemView.findViewById(R.id.countdownTextView); } } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.list_item_countdown, parent, false); return new ViewHolder(itemView); } @Override public void onBindViewHolder(ViewHolder holder, int position) { Countdown countdown = countdowns.get(position); holder.titleTextView.setText(countdown.getTitle()); holder.countdownTextView.setText(getCountdownString(countdown.getDate())); } @Override public int getItemCount() { return countdowns.size(); } private String getCountdownString(Date date) { long diff = date.getTime() - new Date().getTime(); long days = TimeUnit.MILLISECONDS.toDays(diff); diff -= TimeUnit.DAYS.toMillis(days); long hours = TimeUnit.MILLISECONDS.toHours(diff); diff -= TimeUnit.HOURS.toMillis(hours); long minutes = TimeUnit.MILLISECONDS.toMinutes(diff); diff -= TimeUnit.MINUTES.toMillis(minutes); long seconds = TimeUnit.MILLISECONDS.toSeconds(diff); return String.format("%02dd %02dh %02dm %02ds", days, hours, minutes, seconds); } } ``` 接下来,我们需要创建一个 `CountdownActivity` 类,用于处理倒计时的各种操作: ```java public class CountdownActivity extends AppCompatActivity { private RecyclerView countdownRecyclerView; private CountdownAdapter countdownAdapter; private BroadcastReceiver countdownReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { countdownAdapter.notifyDataSetChanged(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_countdown); countdownRecyclerView = findViewById(R.id.countdownRecyclerView); countdownRecyclerView.setLayoutManager(new LinearLayoutManager(this)); List<Countdown> countdowns = Countdown.getAllCountdowns(this); countdownAdapter = new CountdownAdapter(this, countdowns); countdownRecyclerView.setAdapter(countdownAdapter); LocalBroadcastManager.getInstance(this).registerReceiver(countdownReceiver, new IntentFilter("countdown-updated")); FloatingActionButton addCountdownButton = findViewById(R.id.addCountdownButton); addCountdownButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showAddCountdownDialog(); } }); } @Override protected void onDestroy() { super.onDestroy(); LocalBroadcastManager.getInstance(this).unregisterReceiver(countdownReceiver); } private void showAddCountdownDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Add Countdown"); View view = LayoutInflater.from(this).inflate(R.layout.dialog_add_countdown, null); final EditText titleEditText = view.findViewById(R.id.titleEditText); final DatePicker datePicker = view.findViewById(R.id.datePicker); final TimePicker timePicker = view.findViewById(R.id.timePicker); timePicker.setIs24HourView(true); builder.setView(view); builder.setPositiveButton("Add", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String title = titleEditText.getText().toString(); Calendar calendar = Calendar.getInstance(); calendar.set(datePicker.getYear(), datePicker.getMonth(), datePicker.getDayOfMonth(), timePicker.getCurrentHour(), timePicker.getCurrentMinute()); long id = Countdown.addCountdown(CountdownActivity.this, title, calendar.getTime()); countdownAdapter.notifyDataSetChanged(); Intent intent = new Intent("countdown-updated"); LocalBroadcastManager.getInstance(CountdownActivity.this).sendBroadcast(intent); } }); builder.setNegativeButton("Cancel", null); builder.show(); } } ``` 最后,我们需要创建一个 `BroadcastReceiver` 类,用于在倒计时结束时发送通知: ```java public class CountdownReceiver extends BroadcastReceiver { private static final int NOTIFICATION_ID = 1; @Override public void onReceive(Context context, Intent intent) { NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "default") .setSmallIcon(R.drawable.ic_notification) .setContentTitle(intent.getStringExtra("title")) .setContentText("Countdown has ended!") .setPriority(NotificationCompat.PRIORITY_HIGH) .setAutoCancel(true); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("default", "Countdown", NotificationManager.IMPORTANCE_HIGH); notificationManager.createNotificationChannel(channel); } notificationManager.notify(NOTIFICATION_ID, builder.build()); } } ``` 以上就是一个简单的 Android 炫酷倒计时应用的完整代码,其中包括了连接数据库和使用广播接收器的相关代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值