LocalBroadcastReceiver + IntentService 是正确的做法吗?
Posted
技术标签:
【中文标题】LocalBroadcastReceiver + IntentService 是正确的做法吗?【英文标题】:Is LocalBroadcastReceiver + IntentService the correct practice? 【发布时间】:2017-02-25 04:15:48 【问题描述】:我正在尝试了解这些东西如何更好地工作。
所以我了解了 Runnables 和 Threads 以及 ASyncTasks,但显然它们在旋转屏幕等配置更改方面存在一些严重的缺点。
将 IntentService 用于应在后台运行的任何内容(如 SQL 数据库命令、文件系统过程、Internet 输入/输出进程等)是否更好 - 然后使用 LocalBroadcastReceiver 将结果传递回 Activity?
【问题讨论】:
当然,举个例子会有所帮助 【参考方案1】:将 IntentService 用于应在后台运行的任何内容(如 SQL 数据库命令、文件系统过程、Internet 输入/输出进程等)是否更好 - 然后使用 LocalBroadcastReceiver 将结果传递回 Activity?
如果您的 UI 可能会在工作进行时移至后台,并且您担心您的进程可能会在工作进行时终止,则需要服务。如果工作可能超过一秒钟左右,我倾向于只担心这一点。否则,一个普通的线程就足够了。
使用事件总线,如LocalBroadcastManager
,是让其他组件知道您的服务/线程何时完成其工作的合理方法。 This sample app 证明了这一点。就个人而言,我倾向于使用 greenrobot 的 EventBus——this sample app 是第一个的克隆,但使用 EventBus 而不是 LocalBroadcastManager
。
【讨论】:
但是是什么阻止了某人在线程进程中旋转手机? @user7025005:什么都没有。但线程不在乎。您正在使用事件总线让感兴趣的各方了解状态的变化。这样的一方会在事件总线上注册更新(例如,在LocalBroadcastManager
上调用registerReceiver()
),然后做一些事情来获取当前状态(例如,检查单例缓存管理器)。【参考方案2】:
下面是一个使用一个活动(聊天活动)的聊天示例,该活动在服务中运行一个类(实时类)。我使用 mvc webapi 来控制聊天者之间的聊天。当实时接收到由 LocalBroadcastManager 自动发送到聊天活动的消息“onConnected”或“ReceivedMessageServer”时。这样在“onReceive”中从 BroadcastReceiver 接收消息并运行其他任务。
a) ChatActivity.class
package br.com.yourapp;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.res.Configuration;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import java.util.Calendar;
import br.com.yourapp.model.MessageReceived;
import util.RealTime;
public class ChatActivity extends AppCompatActivity implements View.OnClickListener,
View.OnKeyListener , TextWatcher
AppController obj;
private ProgressDialog pDialog;
MediaPlayer mp;
private ListView lstChatLog;
private ArrayAdapter<String> listAdapter;
private EditText txtChatMessage;
private TextView lblTyping;
private Button btnSendChat;
private boolean resultRequest = true;
private String errorMessage = "Internet is not working";
private AlertDialog alertDialog;
private AlertDialog.Builder alertBuilder;
String userType = "V";
String spaces = "\u0020\u0020\u0020\u0020";
Calendar time;
MessageReceived msg;
private RealTime realTime;
private final Context mContext = this;
private boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
pDialog = new ProgressDialog(this);
pDialog.setMessage("Loading...");
pDialog.setCancelable(false);
showProgressDialog();
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
obj = (AppController) getApplicationContext();
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
lblTyping = (TextView) findViewById(R.id.lblTyping);
txtChatMessage = (EditText) findViewById(R.id.txtChatMessage);
txtChatMessage.setOnKeyListener(this);
txtChatMessage.addTextChangedListener(this);
btnSendChat = (Button) findViewById(R.id.btnSendChat);
btnSendChat.setOnClickListener(this);
alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle("Alert");
alertBuilder = new AlertDialog.Builder(this);
lstChatLog = (ListView) findViewById(R.id.lstChatLog);
listAdapter = new ArrayAdapter<String>(ChatActivity.this, android.R.layout.simple_list_item_1, android.R.id.text1)
@Override
public View getView(int position, View convertView, ViewGroup parent)
View view = super.getView(position, convertView, parent);
TextView tv = (TextView) view.findViewById(android.R.id.text1);
tv.setHeight(20);
tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12);
return view;
;
Intent intent = new Intent();
intent.setClass(mContext, RealTime.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
IntentFilter filter = new IntentFilter("Connect");
filter.addAction("RecMsg");
LocalBroadcastManager.getInstance(ChatActivity.this).registerReceiver(mMessageReceiver, filter);
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver()
@Override
public void onReceive(Context context, Intent intent)
if (intent.getAction().toString().equals("Connect"))
msg = (MessageReceived) intent.getExtras().getParcelable("msg");
if (msg == null || msg.Message == null)
return;
listAdapter.add(msg.Destiny + "" + msg.CurrentTime + " : " + msg.Message);
lstChatLog.setAdapter(listAdapter);
realTime.SendToSpecific(msg.Sender, "Hi !", userType, obj.getRiderId(), obj.getDriverId());
hideProgressDialog();
else
if (intent.getAction().toString().equals("RecMsg"))
msg = (MessageReceived) intent.getExtras().getParcelable("msg");
if (msg == null || msg.Message == null)
return;
if (msg.Message.equals("*0.+9=&!*#_&1|8%digi"))
lblTyping.setVisibility(View.VISIBLE);
else
if (msg.Message.equals("*0.+9=&!*#_&1|8%"))
lblTyping.setVisibility(View.INVISIBLE);
else
lblTyping.setVisibility(View.INVISIBLE);
listAdapter.add(msg.Sender + "" + msg.CurrentTime + " : " + msg.Message);
lstChatLog.setAdapter(listAdapter);
mp = MediaPlayer.create(ChatActivity.this, R.raw.notify);
mp.setLooping(false);
mp.setVolume(100, 100);
mp.start();
;
private final ServiceConnection mConnection = new ServiceConnection()
@Override
public void onServiceConnected(ComponentName className, IBinder service)
RealTime.LocalBinder binder = (RealTime.LocalBinder) service;
realTime = binder.getService();
mBound = true;
realTime.Connect(obj.getRiderName(), userType, obj.getRiderId(), obj.getLatitudeRider(), obj.getLongitudeRider(), obj.getDriverId(), obj.getVehicieId());
hideProgressDialog();
@Override
public void onServiceDisconnected(ComponentName arg0)
mBound = false;
;
@Override
protected void onStop()
if (mBound)
unbindService(mConnection);
mBound = false;
super.onStop();
public void SendToSpecific(String sender, String message, String userType, long userId, long operatorId)
realTime.SendToSpecific(sender, message, userType, userId,operatorId);
if (!message.equals("*0.+9=&!*#_&1|8%digi") && !message.equals("*0.+9=&!*#_&1|8%"))
time = Calendar.getInstance();
listAdapter.add(spaces + sender + " " + "(" + time.get(Calendar.HOUR) + ":" + time.get(Calendar.MINUTE) + ")" + " : " + message);
lstChatLog.setAdapter(listAdapter);
txtChatMessage.setText("");
@Override
public boolean onKey(View v, int keyCode, KeyEvent event)
if (keyCode==KeyEvent.KEYCODE_ENTER)
if (txtChatMessage.getText().length() > 0)
InputMethodManager imm = (InputMethodManager) this.getSystemService(Context.
INPUT_METHOD_SERVICE);
if (this.getCurrentFocus() != null)
imm.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0);
SendToSpecific(obj.getRiderName(), txtChatMessage.getText().toString(), userType, obj.getRiderId(), obj.getDriverId());
return false;
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after)
@Override
public void onTextChanged(CharSequence s, int start, int before, int count)
if (txtChatMessage.getText().toString().length() > 0)
if (txtChatMessage.getText().length() == 1)
SendToSpecific(obj.getRiderName(), "*0.+9=&!*#_&1|8%digi", userType, obj.getRiderId(), obj.getDriverId());
else
SendToSpecific(obj.getRiderName(), "*0.+9=&!*#_&1|8%", userType, obj.getRiderId(), obj.getDriverId());
@Override
public void afterTextChanged(Editable s)
public void onClick(View v)
switch (v.getId())
case R.id.btnSendChat:
if (txtChatMessage != null && txtChatMessage.getText().length() > 0)
InputMethodManager imm = (InputMethodManager) this.getSystemService(Context.
INPUT_METHOD_SERVICE);
if (this.getCurrentFocus() != null)
imm.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0);
SendToSpecific(obj.getRiderName(), txtChatMessage.getText().toString(), userType, obj.getRiderId(), obj.getDriverId());
break;
private void showProgressDialog()
if (!pDialog.isShowing())
pDialog.show();
private void hideProgressDialog()
if (pDialog.isShowing())
pDialog.hide();
@Override
protected void onDestroy()
try
if (pDialog != null && pDialog.isShowing())
pDialog.dismiss();
catch (Exception e)
e.printStackTrace();
super.onDestroy();
@Override
public boolean onTouchEvent(MotionEvent event)
InputMethodManager imm = (InputMethodManager) getSystemService(Context.
INPUT_METHOD_SERVICE);
if (getCurrentFocus() != null)
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
return true;
@Override
public boolean onOptionsItemSelected(MenuItem item)
mMessageReceiver.clearAbortBroadcast();
Intent i = new Intent(this, MenuPageActivity.class);
obj.setLastActivity("Chat");
startActivity(i);
return true;
public void ShowAlert()
hideProgressDialog();
if (resultRequest)
errorMessage = "Internet is not working";
alertBuilder.setTitle("Alert");
alertBuilder.setMessage(errorMessage);
alertBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener()
public void onClick(DialogInterface arg0, int arg1)
arg0.dismiss();
);
alertDialog = alertBuilder.create();
alertDialog.show();
errorMessage = "";
resultRequest = true;
@Override
public void onConfigurationChanged(Configuration newConfig)
super.onConfigurationChanged(newConfig);
b) Realtime.class
package util;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import java.util.concurrent.ExecutionException;
import br.com.yourapp.model.MessageReceived;
import microsoft.aspnet.signalr.client.Platform;
import microsoft.aspnet.signalr.client.SignalRFuture;
import microsoft.aspnet.signalr.client.http.android.AndroidPlatformComponent;
import microsoft.aspnet.signalr.client.hubs.HubConnection;
import microsoft.aspnet.signalr.client.hubs.HubProxy;
import microsoft.aspnet.signalr.client.hubs.SubscriptionHandler1;
import microsoft.aspnet.signalr.client.transport.ClientTransport;
import microsoft.aspnet.signalr.client.transport.ServerSentEventsTransport;
public class RealTime extends Service
private HubConnection mHubConnection;
private HubProxy mHubProxy;
private Handler mHandler;
private final IBinder mBinder = new LocalBinder();
public RealTime()
@Override
public void onCreate()
super.onCreate();
mHandler = new Handler(Looper.getMainLooper());
@Override
public int onStartCommand(Intent intent, int flags, int startId)
int result = super.onStartCommand(intent, flags, startId);
startSignalR();
return result;
@Override
public void onDestroy()
mHubConnection.stop();
super.onDestroy();
@Override
public IBinder onBind(Intent intent)
startSignalR();
return mBinder;
public class LocalBinder extends Binder
public RealTime getService()
return RealTime.this;
public void Connect(String userName, String userType, long userId, double latitude, double longitude, long driverId, long vehicleId)
mHubProxy.invoke("Connect", userName, userType, userId, latitude, longitude, driverId, vehicleId);
public void SendMessageToGroup(String userName, String userGroup, String userType, long userId, double latitude, double longitude, long vehicleId, short option)
mHubProxy.invoke("SendMessageToGroup", userName, userGroup, userType, userId, latitude, longitude, vehicleId, option);
public void SendToSpecific(String sender, String message, String userType, long userId, long operatorId)
mHubProxy.invoke("SendToSpecific", sender, message, userType, userId, operatorId);
private void startSignalR()
Platform.loadPlatformComponent(new AndroidPlatformComponent());
mHubConnection = new HubConnection("http://webapi.com");
mHubProxy = mHubConnection.createHubProxy("ChatHub");
ClientTransport clientTransport = new ServerSentEventsTransport(mHubConnection.getLogger());
SignalRFuture<Void> signalRFuture = mHubConnection.start(clientTransport);
try
signalRFuture.get();
catch (InterruptedException | ExecutionException e)
Log.e("SimpleSignalR", e.toString());
return;
mHubProxy.on("onConnected",
new SubscriptionHandler1<MessageReceived>()
@Override
public void run(final MessageReceived msg)
mHandler.post(new Runnable()
@Override
public void run()
Intent intent = new Intent("Connect");
intent.putExtra("msg", msg);
LocalBroadcastManager.getInstance(RealTime.this).sendBroadcast(intent);
);
, MessageReceived.class);
mHubProxy.on("ReceivedMessageServer",
new SubscriptionHandler1<MessageReceived>()
@Override
public void run(final MessageReceived msg)
mHandler.post(new Runnable()
@Override
public void run()
Intent intent = new Intent("RecMsg");
intent.putExtra("msg", msg);
LocalBroadcastManager.getInstance(RealTime.this).sendBroadcast(intent);
);
, MessageReceived.class);
【讨论】:
以上是关于LocalBroadcastReceiver + IntentService 是正确的做法吗?的主要内容,如果未能解决你的问题,请参考以下文章
Android面试每日一题:BroadcastReceiver 与 LocalBroadcastReceiver 有什么区别?