gpt4 book ai didi

java - 定期更新我的应用程序的 UI

转载 作者:行者123 更新时间:2023-12-01 17:51:15 24 4
gpt4 key购买 nike

我希望我的 Android 应用程序能够根据 REST 服务的响应定期更新其 UI。我无法在主线程上执行此操作,因为在主线程上访问网络是不允许的/不好的做法。 SO 和互联网的一般智慧是使用 BroadcastReceiver 和 AlarmManager 的组合。例如,这是建议 here 。我尝试了两种设计,但都无法正常工作:

  1. 定义一个扩展 BroadcastReceiver 的类作为 MainActivity 的内部类。
  2. 定义与外部类相同的类。

使用(1)我得到这个运行时错误:

java.lang.RuntimeException: Unable to instantiate receiver com.dbs.alarm.MainActivity$AlarmReceiver: java.lang.InstantiationException: java.lang.Class<com.dbs.alarm.MainActivity$AlarmReceiver> has no zero argument constructor

对于(2),问题是我不知道如何访问我想要在 MainActivity 中修改的 View 。

以下是 (1) 的示例实现:

package com.dbs.alarm;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

// I tried making this its own class, but then findViewById isn't accessible.
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// I tried wrapping this in runOnUiThread() but it made no difference.
TextView myTextView = findViewById(R.id.my_text);
CharSequence myCharSequence = "Set from UpdateReceiver.onReceive()";
myTextView.setText(myCharSequence);
}
}

private void setRecurringAlarm(Context context) {
Intent intent = new Intent(context, AlarmReceiver.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

PendingIntent pendingIntent = PendingIntent.getBroadcast(
context, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

alarmManager.setInexactRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 1000,
1000, // Set so short for demo purposes only.
pendingIntent
);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRecurringAlarm(this);
}
}

我还将其添加到我的 AndroidManifest.xml 中,考虑到我收到异常,它似乎已成功注册:

<receiver android:name="com.dbs.alarm.MainActivity$AlarmReceiver">
</receiver>

最佳答案

由于您需要直接访问 TextView ,因此为接收器选择一个内部类是正确的做法。但是,声明为内部类的 BroadcastReceiver 必须是 static 才能在 list 中声明,这违背了使其成为内部类的初衷(在至少是你的场景)。因此,我建议在 onStart()onStop() 生命周期方法中动态注册/取消注册 BroadcastReceiver:

public class MainActivity extends AppCompatActivity {

private BroadcastReceiver alarmReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// the "MainActivity.this" tells it to use the method from the parent class
MainActivity.this.updateMyTextView();
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRecurringAlarm(this);
}

@Override
protected void onStart() {
super.onStart();
final IntentFilter filter = new IntentFilter();
filter.addAction("YOUR_ACTION_NAME");
registerReceiver(alarmReceiver, filter);
}

@Override
protected void onStop() {
unregisterReceiver(alarmReceiver);
super.onStop();
}

private void updateMyTextView(){
final TextView myTextView = findViewById(R.id.my_text);
if (myTextView != null){
CharSequence myCharSequence = "Set from UpdateReceiver.onReceive()";
myTextView.post(()-> myTextView.setText(myCharSequence));
}
}

private void setRecurringAlarm(Context context) {
Intent intent = new Intent("YOUR_ACTION_NAME");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

PendingIntent pendingIntent = PendingIntent.getBroadcast(
context, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

alarmManager.setInexactRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 1000,
1000, // Set so short for demo purposes only.
pendingIntent
);
}
}

您还会注意到,我在创建警报 Intent 时没有传入接收器类,而是将其更改为使用一个字符串 ("YOUR_ACTION_NAME"),您可以用它来定义BroadcastReceiver 将用于监听广播的 Intent 过滤器。

对于在 UI 线程上运行更新的问题,您始终可以从 View 中调用 post() 在 UI 线程上运行某些内容,或者使用 Activity 的 runOnUiThread 就像您尝试在 BroadcastReceiver 中所做的那样。我使“更新”方法属于 Activity 而不是广播接收器,因为在我看来这样更有意义。

<小时/>

编辑:在编写此答案时,我更专注于解决您在实现解决方案时遇到的问题,而不是实际尝试帮助解决执行定期 UI 更新的更大问题。 @Ashikee AbHi 建议使用 Handler 而不是警报,这绝对是您应该考虑的事情。当您必须在不同的进程中通知某些内容时,警报/广播接收器非常有用,但如果所有内容都包含在单个 Activity 中,那么使用 Handler.postDelayed 会更简洁。

关于java - 定期更新我的应用程序的 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49864703/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com