Get messages from the server regularly

Keywords: Android JSON network OkHttp

Function Description:

  There is a message function in the interface. Click message to view the message list.
Regularly send the request interface to the server to obtain the latest messages, and display the number of messages in the form of corner marks to the message function,
Thus, users can intuitively know that they have received several messages.

thinking

step 1: start a service, send the request to the server regularly, and get the message
    Knowledge point: scheduled sending: observable.interval();
            Network request: okhttp;
            Background operation: service;

step 2: after getting the message entity, notify the interface to update (activity or fragment)

    
step 3: display the corner mark of the number of messages to the corresponding control
    Knowledge point: badgeview;

Realization

1. service - MonitorService running continuously in the background

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{

        /**
         * Send requests to the server every few seconds to get the latest number of messages
         * @param  intervalSecond Time interval in seconds
         */
        public Observable<String> getNewMessage(int intervalSecond){
            // Default 5 seconds
            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 required for network request

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. Set the view of the angle sign

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. Implementation in 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;
            // Assume json is not empty. Yes: there is a message.
            disposable = binder.getNewMessage(6)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(json -> {
                        if (!TextUtils.isEmpty(json)) {
                            Log.e("test","------subscribe  success-------");
                            // Assume json is not empty. Yes: there is a message.
                            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);
    }

Be careful:

1. Remember to configure the MonitorService service service in Android manifest.xml
 2. If the target view to be set is button, it may not be displayed. The TV menu in the code is textview.

Posted by vidhu on Fri, 13 Dec 2019 07:04:20 -0800