定时获取来自服务器的消息

陈蕃
• 阅读 1444

定时获取来自服务器的消息

功能描述:

  界面中有一个消息功能,点击消息可以查看消息列表。
定时向服务器发送请求接口获取最新消息,并将消息数量以角标得形式显示到消息功能上,
从而用户可以直观得了解到接收了几条消息。

思路

step 1:开一个服务,定时发送请求到服务器,获取消息
    知识点:定时发送:observable.interval();
            网络请求:okhttp;
            后台运行:service;

step 2:得到消息实体后,通知界面更新(activity或者fragment)

    
step 3:显示消息数量的角标到对应控件
    知识点:badgeview;

实现

1,在后台不停跑的service-MonitorService

public class MonitorService extends Service {
    public MonitorService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return binder;
    }

    @Override
    public void onCreate() {
        LogUtil.d("onCreate");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        LogUtil.d("onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        LogUtil.d("onDestroy");
        super.onDestroy();
    }

    private MonitorBinder binder = new MonitorBinder();
    public class MonitorBinder extends Binder{

        /**
         * 每隔几秒向服务器发送请求,获取最新消息数量
         * @param  intervalSecond 时间间隔,单位秒
         */
        public Observable<String> getNewMessage(int intervalSecond){
            // 默认5秒
            if (intervalSecond<1) intervalSecond = 5;
            return io.reactivex.Observable
                    .interval(intervalSecond, TimeUnit.SECONDS)
                    .flatMap(new Function<Long, ObservableSource<String>>() {
                        @Override
                        public ObservableSource<String> apply(Long aLong) throws Exception {
                            return io.reactivex.Observable                    .create(new ObservableOnSubscribe<String>() {
                                @Override
                                public void subscribe(final ObservableEmitter<String> emitter) throws Exception {
                                    LogUtil.e("------subscribe-------");
                                    MessageModel model = new MessageModel();
                                    model.loadData(  "", new MessageModel.OnMessageRequestListener() {
                                        @Override
                                        public void onFailed(IOException e) {
                                            emitter.onNext("");
                                        }

                                        @Override
                                        public void onSuccess(String json) {
                                            emitter.onNext(json);
                                        }
                                    });
                                }
                            });
                        }
                    });
        }

    }
}

2,网络请求需要的Module

public class MessageModel {

    private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient();

    public void loadData(String url, final OnMessageRequestListener listener){
        LogUtil.e(url);
        Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = OK_HTTP_CLIENT.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                listener.onFailed(e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                listener.onSuccess(response.body().string());
            }
        });

    }

    public interface OnMessageRequestListener{
        void onFailed(IOException e);
        void onSuccess(String json);
    }
}

3,设置角标的view

public class BadgeView extends TextView {
    private boolean mHideOnNull;

    public BadgeView(Context context) {
        this(context, (AttributeSet)null);
    }

    public BadgeView(Context context, AttributeSet attrs) {
        this(context, attrs, 16842884);
    }

    public BadgeView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.mHideOnNull = true;
        this.init();
    }

    private void init() {
        if (!(this.getLayoutParams() instanceof LayoutParams)) {
            LayoutParams layoutParams = new LayoutParams(-2, -2, 53);
            this.setLayoutParams(layoutParams);
        }

        this.setTextColor(-1);
        this.setTypeface(Typeface.DEFAULT_BOLD);
        this.setTextSize(2, 11.0F);
        this.setPadding(this.dip2Px(5.0F), this.dip2Px(1.0F), this.dip2Px(5.0F), this.dip2Px(1.0F));
        this.setBackground(9, Color.parseColor("#d3321b"));
        this.setGravity(17);
        this.setHideOnNull(true);
        this.setBadgeCount(0);
    }

    public void setBackground(int dipRadius, int badgeColor) {
        int radius = this.dip2Px((float)dipRadius);
        float[] radiusArray = new float[]{(float)radius, (float)radius, (float)radius, (float)radius, (float)radius, (float)radius, (float)radius, (float)radius};
        RoundRectShape roundRect = new RoundRectShape(radiusArray, (RectF)null, (float[])null);
        ShapeDrawable bgDrawable = new ShapeDrawable(roundRect);
        bgDrawable.getPaint().setColor(badgeColor);
        this.setBackgroundDrawable(bgDrawable);
    }

    public boolean isHideOnNull() {
        return this.mHideOnNull;
    }

    public void setHideOnNull(boolean hideOnNull) {
        this.mHideOnNull = hideOnNull;
        this.setText(this.getText());
    }

    public void setText(CharSequence text, BufferType type) {
        if (!this.isHideOnNull() || text != null && !text.toString().equalsIgnoreCase("0")) {
            this.setVisibility(0);
        } else {
            this.setVisibility(8);
        }

        super.setText(text, type);
    }

    public void setBadgeCount(int count) {
        this.setText(String.valueOf(count));
    }

    public Integer getBadgeCount() {
        if (this.getText() == null) {
            return null;
        } else {
            String text = this.getText().toString();

            try {
                return Integer.parseInt(text);
            } catch (NumberFormatException var3) {
                return null;
            }
        }
    }

    public void setBadgeGravity(int gravity) {
        LayoutParams params = (LayoutParams)this.getLayoutParams();
        params.gravity = gravity;
        this.setLayoutParams(params);
    }

    public int getBadgeGravity() {
        LayoutParams params = (LayoutParams)this.getLayoutParams();
        return params.gravity;
    }

    public void setBadgeMargin(int dipMargin) {
        this.setBadgeMargin(dipMargin, dipMargin, dipMargin, dipMargin);
    }

    public void setBadgeMargin(int leftDipMargin, int topDipMargin, int rightDipMargin, int bottomDipMargin) {
        LayoutParams params = (LayoutParams)this.getLayoutParams();
        params.leftMargin = this.dip2Px((float)leftDipMargin);
        params.topMargin = this.dip2Px((float)topDipMargin);
        params.rightMargin = this.dip2Px((float)rightDipMargin);
        params.bottomMargin = this.dip2Px((float)bottomDipMargin);
        this.setLayoutParams(params);
    }

    public int[] getBadgeMargin() {
        LayoutParams params = (LayoutParams)this.getLayoutParams();
        return new int[]{params.leftMargin, params.topMargin, params.rightMargin, params.bottomMargin};
    }

    public void incrementBadgeCount(int increment) {
        Integer count = this.getBadgeCount();
        if (count == null) {
            this.setBadgeCount(increment);
        } else {
            this.setBadgeCount(increment + count);
        }

    }

    public void decrementBadgeCount(int decrement) {
        this.incrementBadgeCount(-decrement);
    }

    public void setTargetView(TabWidget target, int tabIndex) {
        View tabView = target.getChildTabViewAt(tabIndex);
        this.setTargetView(tabView);
    }

    public void setTargetView(View target) {
        if (this.getParent() != null) {
            ((ViewGroup)this.getParent()).removeView(this);
        }

        if (target != null) {
            if (target.getParent() instanceof FrameLayout) {
                ((FrameLayout)target.getParent()).addView(this);
            } else if (target.getParent() instanceof ViewGroup) {
                ViewGroup parentContainer = (ViewGroup)target.getParent();
                int groupIndex = parentContainer.indexOfChild(target);
                parentContainer.removeView(target);
                FrameLayout badgeContainer = new FrameLayout(this.getContext());
                android.view.ViewGroup.LayoutParams parentlayoutParams = target.getLayoutParams();
                badgeContainer.setLayoutParams(parentlayoutParams);
                target.setLayoutParams(new android.view.ViewGroup.LayoutParams(-1, -1));
                parentContainer.addView(badgeContainer, groupIndex, parentlayoutParams);
                badgeContainer.addView(target);
                badgeContainer.addView(this);
            } else if (target.getParent() == null) {
                Log.e(this.getClass().getSimpleName(), "ParentView is needed");
            }

        }
    }

    private int dip2Px(float dip) {
        return (int)(dip * this.getContext().getResources().getDisplayMetrics().density + 0.5F);
    }
}

4,activity中实现

public class MainActivity extends AppCompatActivity {

   
    private MonitorService.MonitorBinder binder;
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e("test","------onServiceConnected-------");
            binder = (MonitorService.MonitorBinder) service;
            // 假设json 不为空。为:有消息。
            disposable = binder.getNewMessage(6)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(json -> {
                        if (!TextUtils.isEmpty(json)) {
                            Log.e("test","------subscribe  success-------");
                            // 假设json 不为空。为:有消息。
                            View view = findViewById(R.id.tv_menu);
                            BadgeView badgeView = new BadgeView(MainActivity.this);
                            badgeView.setTargetView(view);
                            badgeView.setBadgeCount(1);
                        }
                    });
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initToolbar();
        bindService(new Intent(this,MonitorService.class),serviceConnection,BIND_AUTO_CREATE);
 

    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(disposable!=null&&!disposable.isDisposed()){
            disposable.dispose();
        }
        unbindService(serviceConnection);
    }

注意:

1,记得在androidManifest.xml中配置MonitorService服务
2,如果需要设置的目标view是button的话可能会不显示,代码中的tv_menu 是textview。
点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
4年前
Java消息服务JMS详解
JMS:Java消息服务(JavaMessageService)JMS是用于访问企业消息系统的开发商中立的API。企业消息系统可以协助应用软件通过网络进行消息交互。JMS的编程过程很简单,概括为:应用程序A发送一条消息到消息服务器的某个目得地(Destination),然后消息服务器把消息转发给应用程序B。因为应
Stella981 Stella981
4年前
RabbitMQ学习:RabbitMQ的基本概念及RabbitMQ使用场景(二)
1、RabbitMQ的基本概念RabbitMQ是一种消息中间件,用于处理来自客户端的异步消息。服务端将要发送的消息放入到队列池中。接收端可以根据RabbitMQ配置的转发机制接收服务端发来的消息。RabbitMQ依据指定的转发规则进行消息的转发、缓冲和持久化操作,主要用在多服务器间或单服务器的子系统间进行通信,是分布式系统
Stella981 Stella981
4年前
RabbitMQ学习:安装RabbitMQ及RabbitMQ的初步配置(一)
RabbitMQ基础含义RabbitMQ是一种消息中间件,用于处理来自客户端的异步消息。服务端将要发送的消息放入到队列池中。接收端可以根据RabbitMQ配置的转发机制接收服务端发来的消息。RabbitMQ依据指定的转发规则进行消息的转发、缓冲和持久化操作,主要用在多服务器间或单服务器的子系统间进行通信,是分布式系统标准的配置。
Wesley13 Wesley13
4年前
ActiveMQ消息特性:延迟和定时消息投递(Delay and Schedule Message
有时候我们不希望消息马上被broker投递出去,而是想要消息60秒以后发给消费者,或者我们想让消息没隔一定时间投递一次,一共投递指定的次数。。。类似这种需求,ActiveMQ提供了一种broker端消息定时调度机制。我们只需要把几个描述消息定时调度方式的参数作为属性添加到消息,broker端的调度器就会按照我们想要的行为去处理消息。一共有四个属性
Stella981 Stella981
4年前
RabbitMQ延迟消息发送
为什么使用延迟消息?不同于同步消息,有些业务场景下希望可以实现延迟一定时间再消费消息。典型的场景有微信、支付宝等第三方支付回调接口,会在用户支付后3秒、5秒、30秒等等时间后向应用服务器发送回调请求,确保应用服务器可以正确收到消息。那有些朋友就会说了,把需要定时处理的数据存到数据库中用定时任务就可以实现,为什么还弄个异步消息。增加后台维护
程序员小五 程序员小五
1年前
融云IM干货丨IM服务聊天室中离线消息同步需要多久一次?
关于离线消息同步的频率,根据搜索结果,这里有几个关键点可以提供参考:离线消息的获取是自上而下的方式(按时间序),客户端一次获取200条离线消息,如果离线消息过多,则会分页多次拉取。客户端拉取离线消息时,需要带上当前客户端缓存的消息的最大时间戳,服务器会根据
程序员小五 程序员小五
2年前
IM 应用场景中如何限制只有好友之间才能互发消息?
功能介绍好友关系由开发者的应用服务器自行维护好友关系,融云服务器提供消息发送能力,消息发送过程中默认不会做任何权限校验得到userId后即可发送消息,例如:A发送消息给B,只需要把B的userId传给融云服务即可发送消息这样易用的设计可以使开发者高度自由集
程序员小五 程序员小五
2年前
消息丢失排查方法?
遇到丢消息问题,如果是单聊,群聊,聊天室,系统消息可以在开发者后台北极星自助查询一下消息是否发送成功。根据您实际发送的相关信息(发送者、接收者、时间、消息ID……)看是否可以查到消息如果消息查不到一般有几种可能:信息有误(获取token的用户id跟您系统中
程序员小五 程序员小五
2年前
IM 应用场景中如何限制只有好友之间才能互发消息?
功能介绍好友关系由开发者的应用服务器自行维护好友关系,融云服务器提供消息发送能力,消息发送过程中默认不会做任何权限校验得到userId后即可发送消息,例如:A发送消息给B,只需要把B的userId传给融云服务即可发送消息这样易用的设计可以使开发者高度自由集
程序员小五 程序员小五
2年前
撤回聊天室消息, 再次加入聊天室, 仍然显示已经被撤销的消息
用户的聊天如果开启了拉取特定消息功能,需要在后台做一下修改:把聊天室“加入聊天室获取指定消息类型”加上RC:RcCmd消息类型,这样就可以隐藏元消息详情查看:https://www.rongcloud.cn/?utmsourceSEO&utmtermhel