定時獲取來自服務器的消息
功能描述:
界面中有一個消息功能,點擊消息能夠查看消息列表。
定時向服務器發送請求接口獲取最新消息,並將消息數量以角標得形式顯示到消息功能上,
從而用戶能夠直觀得了解到接收了幾條消息。
思路
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。