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.