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 有什么区别?

EventBus源码赏析一 —— 基本使用