Android活动和服务通信:如何保持UI最新
作者:互联网
我有一个活动A(不是主要活动),它启动一个服务S,该服务在后台执行一些操作,与此同时,应该对A的UI进行一些更改.
我们只说S计数从0到100,而A应该实时显示此计数.由于S的实际工作非常复杂且占用CPU,因此我不希望使用AsyncTask(实际上,“理想情况下,AsyncTasks应该用于短操作(最多几秒钟).[…]” ),但只有普通的Service在新线程中启动(IntentService也可以).
这是我的活动A:
public class A extends Activity {
private static final String TAG = "Activity";
private TextView countTextView; // TextView that shows the number
Button startButton; // Button to start the count
BResultReceiver resultReceiver;
/**
* Receive the result from the Service B.
*/
class BResultReceiver extends ResultReceiver {
public BResultReceiver(Handler handler) {
super(handler);
}
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
switch ( resultCode ) {
case B.RESULT_CODE_COUNT:
String curCount = resultData.getString(B.RESULT_KEY_COUNT);
Log.d(TAG, "ResultReceived: " + curCount + "\n");
runOnUiThread( new UpdateUI(curCount) ); // NOT WORKING AFTER onResume()!!!
break;
}
}
}
/**
* Runnable class to update the UI.
*/
class UpdateUI implements Runnable {
String updateString;
public UpdateUI(String updateString) {
this.updateString = updateString;
}
public void run() {
countTextView.setText(updateString);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.counter);
countTextView = (TextView) findViewById(R.id.countTextView);
startButton = (Button) findViewById(R.id.startButton);
resultReceiver = new BResultReceiver(null);
}
public void startCounting(View view) {
startButton.setEnabled(false);
//Start the B Service:
Intent intent = new Intent(this, B.class);
intent.putExtra("receiver", resultReceiver);
startService(intent);
}
}
这是我的服务B:
public class B extends Service {
private static final String TAG = "Service";
private Looper serviceLooper;
private ServiceHandler serviceHandler;
private ResultReceiver resultReceiver;
private Integer count;
static final int RESULT_CODE_COUNT = 100;
static final String RESULT_KEY_COUNT = "Count";
/**
* Handler that receives messages from the thread.
*/
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
while ( count < 100 ) {
count++;
//Sleep...
sendMessageToActivity(RESULT_CODE_COUNT, RESULT_KEY_COUNT, count.toString());
}
//Stop the service (using the startId to avoid stopping the service in the middle of handling another job...):
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
//Start up the thread running the service:
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
this.count = 0;
//Get the HandlerThread's Looper and use it for our Handler
serviceLooper = thread.getLooper();
serviceHandler = new ServiceHandler(serviceLooper);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
this.resultReceiver = intent.getParcelableExtra("receiver");
//For each start request, send a message to start a job and deliver the start ID so we know which request we're stopping when we finish the job:
Message msg = serviceHandler.obtainMessage();
msg.arg1 = startId;
serviceHandler.sendMessage(msg);
//If we get killed, after returning from here, restart:
return START_REDELIVER_INTENT;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* Send a message from to the activity.
*/
protected void sendMessageToActivity(Integer code, String name, String text) {
Bundle bundle = new Bundle();
bundle.putString(name, text);
//Send the message:
resultReceiver.send(code, bundle);
}
}
一切正常,但是如果我单击“后退”按钮(或“主页”按钮),然后重新打开活动A,则A的UI不再更新(它仅显示A的初始配置-即“ startButton”为仍可点击,并且不显示计数-似乎runOnUiThread(…)不再起作用.但是,服务B仍在后台运行,我可以看到正确的计数已传递到Log.d(…)中的活动A.最后,如果我再次单击“ startButton”,则计数不是从开头(0)开始,而是从到达B的位置开始(我已经通过在通知栏中显示它进行了双重检查).
我该如何解决此问题?我希望这样,当我重新打开活动A时,它会自动继续从服务B接收和更新数据.换句话说,服务会保持活动A的UI为最新.
请给我一些提示,链接或一段代码.谢谢!
解决方法:
当您单击后退按钮时,您的活动被破坏.再次启动活动时,您将获得一个新的活动.旋转设备时也会发生这种情况.这是Android lifecycle event
该活动不利于繁重的业务逻辑,仅显示填充/控制stuf.
您需要做的是创建一个简单的MVCModel View Controller.视图(Activity)仅应用于显示结果和控制事件流.
服务可以保存一个数组,当您的Activity启动时,它将onBind()您正在运行的Service(或者如果未运行,则由于您绑定到该服务而启动了Service)让Activity(View)获取结果数组并显示出来.此简单设置不包括(M)Model业务逻辑.
更新资料
继续阅读此书,这是Android的官方文档,并且因为它确实可以满足您的要求,因此是一个完美的开始.如在onStart()中的示例中所见,Activity与服务建立了连接,而在onStop()中,该连接被删除了. onStop()之后没有任何连接.就像您要的一样.我会使用此设置,而不是让Service连续发送数据,因为这会浪费资源,并且Activity不会一直在侦听,因为它将在后台停止.
Here’s an activity that binds to LocalService and calls getRandomNumber() when a button is clicked:
标签:android-handler,android-service,android-activity,android-ui,android 来源: https://codeday.me/bug/20191122/2062439.html