定时获取来自服务器的消息
功能描述:
界面中有一个消息功能,点击消息可以查看消息列表。定时向服务器发送请求接口获取最新消息,并将消息数量以角标得形式显示到消息功能上,从而用户可以直观得了解到接收了几条消息。
思路
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 getNewMessage(int intervalSecond){ // 默认5秒 if (intervalSecond<1) intervalSecond = 5; return io.reactivex.Observable .interval(intervalSecond, TimeUnit.SECONDS) .flatMap(new Function >() { @Override public ObservableSource apply(Long aLong) throws Exception { return io.reactivex.Observable .create(new ObservableOnSubscribe () { @Override public void subscribe(final ObservableEmitter 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。