自定义初始化器和监听器

在SpringBoot 启动过程中,容器初始化之前,会提前设置一些环境变量,初始化器和监听器的信息,那么在这块可以对其中的初始化器和监听器进行扩展。

1、初始化器,设置外部自定义参数

实现如下:

public class MyApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        //自定义设置变量
        Map<String, Object> ipMap = getIpMap();

        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        MapPropertySource mapPropertySource = new MapPropertySource("myApplicationContextInitializer", ipMap);
        environment.getPropertySources().addLast(mapPropertySource);

    }

    private static Map<String, Object> getIpMap() {
        Map<String, Object> ipMap = new HashMap<>();
        ArrayList<String> list = new ArrayList<>();
        list.add("127.0.0.1");
        ipMap.put("DEV", list);
        return ipMap;
    }
}

在Spring.factories 文件添加如下配置

org.springframework.context.ApplicationContextInitializer=org.example.service.impl.MyApplicationContextInitializer

测试参数是否设置成功

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyInitializerTest {
    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void testMyInitializer() {
        String ipMap = applicationContext.getEnvironment().getProperty("DEV");
        System.out.println(ipMap);
    }
}

2、监听器根据外部参数类型进行自定义事件处理

@Component
public class MyApplicationListener implements ApplicationListener<MyEvent> {
    private String name;
//    内置自定义监听器
//    @Override
//    public void onApplicationEvent(ApplicationEvent event) {
//        System.out.println("添加自定义监听器");
//    }

    @Override
    public void onApplicationEvent(MyEvent event) {
        sendEail(event);
    }

    private void sendEail(MyEvent event) {
        if(1 == event.getStatus()) {
            name = "Lisa";
        } else {
            name = "goudan";
        }
        System.out.println("sendEmailTo: " + name);
    }
}

 自定义事件,并设置属性

@Getter
public class MyEvent extends ApplicationEvent {
    private Integer status;
    public MyEvent(Object source) {
        super(source);
    }

    public MyEvent(Object source, Integer status) {
        super(source);
        this.status = status;
    }
}

 测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyListenerTest {
    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void testMyListener() {
        applicationContext.publishEvent(new MyEvent("object", 2));
    }
}

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
应用启动页自定义跳转计时View Demo: CircleTextProgressbar.java: package com.demo.startpageskiptimerdemo.widget; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.text.TextUtils; import android.util.AttributeSet; import com.demo.startpageskiptimerdemo.R; /** * Created by Administrator on 2016/8/26. (自定义TextView,用于欢迎页跳过图标) */ public class CircleTextProgressbar extends android.support.v7.widget.AppCompatTextView { /** * 外部轮廓的颜色。 */ private int outLineColor = Color.BLACK; /** * 外部轮廓的宽度。 */ private int outLineWidth = 2; /** * 内部圆的颜色。 */ private ColorStateList inCircleColors = ColorStateList.valueOf(Color.TRANSPARENT); /** * 中心圆的颜色。 */ private int circleColor; /** * 进度条的颜色。 */ private int progressLineColor = Color.WHITE; /** * 进度条的宽度。 */ private int progressLineWidth = 8; /** * 画笔。 */ private Paint mPaint = new Paint(); /** * 进度条的矩形区域。 */ private RectF mArcRect = new RectF(); /** * 进度。 */ private int progress = 100; /** * 进度条类型。 */ private ProgressType mProgressType = ProgressType.COUNT; /** * 进度倒计时时间。 */ private long timeMillis = 5000; /** * View的显示区域。 */ final Rect bounds = new Rect(); /** * 进度条通知。 */ private OnCountdownProgressListener mCountdownProgressListener; /** * Listener what。 */ private int listenerWhat = 0; private String seconds; public CircleTextProgressbar(Context context) { this(context, null); } public CircleTextProgressbar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CircleTextProgressbar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initialize(context, attrs); } public void setSeconds(String seconds) { this.seconds = seconds; invalidate(); } /** * 初始化。 * * @param context 上下文。 * @param attributeSet 属性。 */ private void initialize(Context context, AttributeSet attributeSet) { mPaint.setAntiAlias(true); TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.CircleTextProgressbar); if (typedArray.hasValue(R.styleable.CircleTextProgressbar_in_circle_color)) inCircleColors = typedArray.getColorStateList(R.styleable.CircleTextProgressbar_in_circle_color); else inCircleColors = ColorStateList.valueOf(Color.TRANSPARENT); circleColor = inCircleColors.getColorForState(getDrawableState(), Color.TRANSPARENT); typedArray.recycle(); } /** * 设置外部轮廓的颜色。 * * @param outLineColor 颜色值。 */ // public void setOutLineColor(@ColorInt int outLineColor) { public void setOutLineColor(int outLineColor) { this.outLineColor = outLineColor; invalidate(); } /** * 设置外部轮廓的颜色。 * * @param outLineWidth 颜色值。 */ // public void setOutLineWidth(@ColorInt int outLineWidth) { public void setOutLineWidth(int outLineWidth) { this.outLineWidth = outLineWidth; invalidate(); } /** * 设置圆形的填充颜色。 * * @param inCircleColor 颜色值。 */ // public void setInCircleColor(@ColorInt int inCircleColor) { public void setInCircleColor(int inCircleColor) { this.inCircleColors = ColorStateList.valueOf(inCircleColor); invalidate(); } /** * 是否需要更新圆的颜色。 */ private void validateCircleColor() { int circleColorTemp = inCircleColors.getColorForState(getDrawableState(), Color.TRANSPARENT); if (circleColor != circleColorTemp) { circleColor = circleColorTemp; invalidate(); } } /** * 设置进度条颜色。 * * @param progressLineColor 颜色值。 */ // public void setProgressColor(@ColorInt int progressLineColor) { public void setProgressColor(int progressLineColor) { this.progressLineColor = progressLineColor; invalidate(); } /** * 设置进度条线的宽度。 * * @param progressLineWidth 宽度值。 */ public void setProgressLineWidth(int progressLineWidth) { this.progressLineWidth = progressLineWidth; invalidate(); } /** * 设置进度。 * * @param progress 进度。 */ public void setProgress(int progress) { this.progress = validateProgress(progress); invalidate(); } /** * 验证进度。 * * @param progress 你要验证的进度值。 * @return 返回真正的进度值。 */ private int validateProgress(int progress) { if (progress > 100) progress = 100; else if (progress < 0) progress = 0; return progress; } /** * 拿到此时的进度。 * * @return 进度值,最大100,最小0。 */ public int getProgress() { return progress; } /** * 设置倒计时总时间。 * * @param timeMillis 毫秒。 */ public void setTimeMillis(long timeMillis) { this.timeMillis = timeMillis; invalidate(); } /** * 拿到进度条计时时间。 * * @return 毫秒。 */ public long getTimeMillis() { return this.timeMillis; } /** * 设置进度条类型。 * * @param progressType {@link ProgressType}. */ public void setProgressType(ProgressType progressType) { this.mProgressType = progressType; resetProgress(); invalidate(); } /** * 重置进度。 */ private void resetProgress() { switch (mProgressType) { case COUNT: progress = 0; break; } } /** * 拿到进度条类型。 * * @return */ public ProgressType getProgressType() { return mProgressType; } /** * 设置进度监听。 * * @param mCountdownProgressListener 监听器。 */ public void setCountdownProgressListener(int what, OnCountdownProgressListener mCountdownProgressListener) { this.listenerWhat = what; this.mCountdownProgressListener = mCountdownProgressListener; } /** * 开始。 */ public void start() { stop(); post(progressChangeTask); } /** * 重新开始。 */ public void reStart() { resetProgress(); start(); } /** * 停止。 */ public void stop() { removeCallbacks(progressChangeTask); } @Override protected void onDraw(Canvas canvas) { // 获取view的边界 getDrawingRect(bounds); int size = bounds.height() > bounds.width() ? bounds.width() : bounds.height(); float outerRadius = size / 2; // 画内部背景 int circleColor = inCircleColors.getColorForState(getDrawableState(), 0); mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(circleColor); canvas.drawCircle(bounds.centerX(), bounds.centerY(), outerRadius - outLineWidth, mPaint); // 画边框圆 mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(outLineWidth); mPaint.setColor(outLineColor); canvas.drawCircle(bounds.centerX(), bounds.centerY(), outerRadius - outLineWidth / 2, mPaint); // 画字 Paint paint = getPaint(); paint.setColor(getCurrentTextColor()); paint.setAntiAlias(true); paint.setTextAlign(Paint.Align.CENTER); float textY = bounds.centerX(); float textS = (bounds.bottom + paint.ascent() / 2) - 10; if (!TextUtils.isEmpty(seconds)) canvas.drawText(seconds, bounds.centerX(), textS, paint); canvas.drawText(getText().toString(), bounds.centerX(), textY, paint); // 画进度条 mPaint.setColor(progressLineColor); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(progressLineWidth); mPaint.setStrokeCap(Paint.Cap.ROUND); int deleteWidth = progressLineWidth + outLineWidth; mArcRect.set(bounds.left + deleteWidth / 2, bounds.top + deleteWidth / 2, bounds.right - deleteWidth / 2, bounds.bottom - deleteWidth / 2); canvas.drawArc(mArcRect, 270, 360 * progress / 100, false, mPaint); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int lineWidth = 4 * (outLineWidth + progressLineWidth); int width = getMeasuredWidth(); int height = getMeasuredHeight(); int size = (width > height ? width : height) + lineWidth; setMeasuredDimension(size, size); } @Override protected void drawableStateChanged() { super.drawableStateChanged(); validateCircleColor(); } /** * 进度更新task。 */ private Runnable progressChangeTask = new Runnable() { @Override public void run() { removeCallbacks(this); switch (mProgressType) { case COUNT: progress += 1; break; } if (progress >= 0 && progress <= 100) { if (mCountdownProgressListener != null) mCountdownProgressListener.onProgress(listenerWhat, progress); invalidate(); postDelayed(progressChangeTask, timeMillis / 100); } else progress = validateProgress(progress); } }; /** * 进度条类型。 */ public enum ProgressType { /** * 顺数进度条,从0-100; */ COUNT, } /** * 进度监听。 */ public interface OnCountdownProgressListener { /** * 进度通知。 * * @param progress 进度值。 */ void onProgress(int what, int progress); } } attrs.xml: <?xml version="1.0" encoding="utf-8"?> <resources> <!-- 欢迎页跳过按钮样式 --> <declare-styleable name="CircleTextProgressbar"> <attr name="in_circle_color" format="color" /> <attr name="cenerTextSie" format="dimension"></attr> <attr name="secondsTextSize" format="dimension"></attr> <attr name="secondsText" format="string"></attr> </declare-styleable> </resources> StartPageActivity.java: package com.demo.startpageskiptimerdemo.activity; import android.content.Intent; import android.graphics.Color; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import com.bumptech.glide.Glide; import com.bumptech.glide.signature.StringSignature; import com.demo.startpageskiptimerdemo.R; import com.demo.startpageskiptimerdemo.widget.CircleTextProgressbar; import java.util.Timer; import java.util.TimerTask; /** * 启动页面 * * @author chenke * @time 2017/12/7 10:13 * @mail [email protected] */ public class StartPageActivity extends AppCompatActivity implements View.OnTouchListener { private final static String TAG = "StartPageActivity"; CircleTextProgressbar mTvSkip; ImageView mStartPageImag; LinearLayout skipLayout; RelativeLayout welBgRlay; // 倒计时timer private Timer timer; // 启动页图片地址 private String imgUrl = "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1851053687,4000575540&fm=27&gp=0.jpg"; private int waitTime = 5;// 时长5秒 Handler mHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message message) { switch (message.what) { case 1: gotoHomeActivity(); break; } return false; } }); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_start_page); init(); } private void init() { mTvSkip = (CircleTextProgressbar) findViewById(R.id.tv_red_skip); mStartPageImag = (ImageView) findViewById(R.id.star_page_icon); skipLayout = (LinearLayout) findViewById(R.id.skip_layout); welBgRlay = (RelativeLayout) findViewById(R.id.start_goadvert_lay); mTvSkip.setOutLineColor(Color.TRANSPARENT); mTvSkip.setInCircleColor(Color.parseColor("#AAC6C6C6")); mTvSkip.setProgressColor(Color.WHITE); mTvSkip.setProgressLineWidth(5); // 开始时计 mCountDowntimer(); mTvSkip.reStart(); // 设置skipLayout浮在整个页面的最上层 welBgRlay.bringChildToFront(skipLayout); mTvSkip.setOnTouchListener(this); mStartPageImag.setOnTouchListener(this); // 加载图片 if (!TextUtils.isEmpty(imgUrl)) { Glide.with(this).load(imgUrl).signature(new StringSignature("1")).into (mStartPageImag); } } @Override public boolean onTouch(View view, MotionEvent motionEvent) { if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { if (null != timer) { timer.cancel(); timer = null; } switch (view.getId()) { case R.id.star_page_icon: // 广告 //********** 跳转网页 (进入启动页面广告详情)*********** break; case R.id.tv_red_skip: // 跳转计时view if (null != timer) { timer.cancel(); timer = null; } mHandler.sendEmptyMessage(1); return true; } } return false; } /** * 进入首页 */ public void gotoHomeActivity() { Intent homeIntent = new Intent(); homeIntent.setClass(this, MainActivity.class); startActivity(homeIntent); finish(); } /** * 计时 */ private void mCountDowntimer() { timer = new Timer(); mTvSkip.setSeconds(waitTime + "s"); timer.schedule(task, 1000, 1000); } /** * 计时线程 */ TimerTask task = new TimerTask() { @Override public void run() { runOnUiThread(new Runnable() { // UI thread @Override public void run() { waitTime--; mTvSkip.setSeconds(waitTime + "s"); if (waitTime <= 0) { if (null != timer) { timer.cancel(); timer = null; } mHandler.sendEmptyMessage(1); } } }); } }; } activity_start_page.xml: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/start_goadvert_lay" android:layout_width="match_parent" android:layout_height="match_parent" android: <ImageView android:id="@+id/star_page_icon" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:scaleType="fitXY" /> <LinearLayout android:id="@+id/skip_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:gravity="center" android:orientation="horizontal" android:paddingRight="10dp" android:paddingTop="10dp" android:visibility="visible"> <com.demo.startpageskiptimerdemo.widget.CircleTextProgressbar android:id="@+id/tv_red_skip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="跳过" android:textColor="@android:color/white" android:textSize="10dp" /> </LinearLayout> </RelativeLayout> styles.xml: <resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> <!--启动页面跳过按钮自定义style--> <style name="CustomProgressStyle" parent="@android:style/Widget.ProgressBar.Large"> <item name="android:minWidth">35dip</item> <item name="android:maxWidth">35dip</item> <item name="android:minHeight">35dip</item> <item name="android:maxHeight">35dip</item> </style> </resources> AndroidManifest.xml中添加请求网络权限: <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> build.gradle中dependencies添加: // 异步加载图片 compile 'com.github.bumptech.glide:glide:3.7.0' compile 'com.android.support:support-v4:23.3.0'
描述 android计步的实现,自定义的一个弧形进度条,记步通过手机的传感来实现,也就是说不支持传感的机子(应该很老的了吧)就没有效果。看看效果图: 这里写图片描述这里写图片描述 自定义View public class StepView extends View { /** * 圆弧的宽度 */ private float borderWidth = dipToPx(10); /** * 画步数的数值的字体大小 */ private float numberTextSize = 0; /** * 步数 */ private String stepNumber = "0"; /** * 开始绘制圆弧的角度 */ private float startAngle = 125; /** * 终点对应的角度和起始点对应的角度的夹角 */ private float angleLength = 290; /** * 所要绘制的当前步数的蓝色圆弧终点到起点的夹角 */ private float currentAngleLength = 0; /** * 动画时长 */ private int animationLength = 3000; /** * 当前运动类型 */ private String type = "Riding"; /** * 当前活跃等级 */ private String level = "等级:轻度活跃"; /** * 步数上方文字 */ private String today = "今日步数"; /** * 单位km是否显示 */ private String unit = "Km"; public StepView(Context context) { super(context); } public StepView(Context context, AttributeSet attrs) { super(context, attrs); } public StepView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); /**中心点的x坐标*/ float centerX = (getWidth()) / 2; /**指定圆弧的外轮廓矩形区域*/ RectF rectF = new RectF(0 + borderWidth, borderWidth, 2 * centerX - borderWidth, 2 * centerX - borderWidth); /**【第一步】绘制整体的灰色圆弧*/ drawArcYellow(canvas, rectF); /**【第二步】绘制当前进度的蓝色圆弧*/ drawArcRed(canvas, rectF); /**【第三步】绘制当前进度的白色数字*/ drawTextNumber(canvas, centerX); /**【第四步】绘制"本次步数"的灰色文字*/ drawTextStepString(canvas, centerX); /**【第五步】绘制当前记步类型*/ drawTextType(canvas, centerX); /**【第六步】绘制当前等级类型*/ drawTextLevel(canvas, centerX); /**【第七步】绘制骑行距离单位*/ drawTextUnit(canvas, centerX); } /** * 1.绘制总步数的灰色圆弧 * * @param canvas 画笔 * @param rectF 参考的矩形 */ private void drawArcYellow(Canvas canvas, RectF rectF) { Paint paint = new Paint(); /** 默认画笔颜色,灰色 */ paint.setColor(getResources().getColor(R.color.near_black)); /** 结合处为圆弧*/ paint.setStrokeJoin(Paint.Join.MITER); /** 设置画笔的样式 Paint.Cap.Round ,Cap.SQUARE等分别为圆形、方形*/ paint.setStrokeCap(Paint.Cap.BUTT); /** 设置画笔的填充样式 Paint.Style.FILL :填充内部;Paint.Style.FILL_AND_STROKE :填充内部和描边; Paint.Style.STROKE :仅描边*/ paint.setStyle(Paint.Style.STROKE); float[] floats = {4,16,4,16}; paint.setPathEffect(new DashPathEffect(floats, 0)); /**抗锯齿功能*/ paint.setAntiAlias(true); /**设置画笔宽度*/ paint.setStrokeWidth(borderWidth); /**绘制圆弧的方法 * drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//画弧, 参数一是RectF对象,一个矩形区域椭圆形的界限用于定义在形状、大小、电弧, 参数二是起始角(度)在电弧的开始,圆弧起始角度,单位为度。 参数三圆弧扫过的角度,顺时针方向,单位为度,从右中间开始为零度。 参数四是如果这是true(真)的话,在绘制圆弧时将圆心包括在内,通常用来绘制扇形;如果它是false(假)这将是一个弧线, 参数五是Paint对象; */ canvas.drawArc(rectF, startAngle, angleLength, false, paint); } /** * 2.绘制当前步数的蓝色圆弧 */ private void drawArcRed(Canvas canvas, RectF rectF) { Paint paintCurrent = new Paint(); paintCurrent.setStrokeJoin(Paint.Join.MITER); paintCurrent.setStrokeCap(Paint.Cap.BUTT);//圆角弧度 paintCurrent.setStyle(Paint.Style.STROKE);//设置填充样式 paintCurrent.setAntiAlias(true);//抗锯齿功能 paintCurrent.setStrokeWidth(borderWidth);//设置画笔宽度 paintCurrent.setColor(getResources().getColor(R.color.colorPrimary));//设置画笔颜色 float[] floats = {4,16,4,16}; paintCurrent.setPathEffect(new DashPathEffect(floats, 0)); canvas.drawArc(rectF, startAngle, currentAngleLength, false, paintCurrent); } /** * 3.圆环中心的步数 */ private void drawTextNumber(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true);//抗锯齿功能 vTextPaint.setTextSize(numberTextSize); Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL); vTextPaint.setTypeface(font);//字体风格 vTextPaint.setColor(getResources().getColor(R.color.white)); Rect bounds_Number = new Rect(); vTextPaint.getTextBounds(stepNumber, 0, stepNumber.length(), bounds_Number); canvas.drawText(stepNumber, centerX, getHeight() / 2 + bounds_Number.height() / 2, vTextPaint); } /** * 4.圆环中心[本次步数]的文字 */ private void drawTextStepString(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextSize(dipToPx(16)); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true);//抗锯齿功能 vTextPaint.setColor(getResources().getColor(R.color.gray)); Rect bounds = new Rect(); vTextPaint.getTextBounds(today, 0, today.length(), bounds); canvas.drawText(today, centerX, getHeight() / 2 + bounds.height() - 2 * getFontHeight(numberTextSize), vTextPaint); } /** * 5.圆环中下[Walking]等文字 */ private void drawTextType(Canvas canvas, float centerX) { Paint mTypePaint = new Paint(); mTypePaint.setTextSize(dipToPx(22)); mTypePaint.setTextAlign(Paint.Align.CENTER); mTypePaint.setAntiAlias(true); mTypePaint.setColor(getResources().getColor(R.color.text_blue)); Rect bounds = new Rect(); mTypePaint.getTextBounds(type, 0, type.length(), bounds); canvas.drawText(type, centerX, getHeight() / 2 + 2 * bounds.height() + getFontHeight(numberTextSize), mTypePaint); } /** * 6.绘制圆环下方等级 */ private void drawTextLevel(Canvas canvas, float centerX) { Paint mLevelPaint = new Paint(); mLevelPaint.setTextSize(dipToPx(12)); mLevelPaint.setTextAlign(Paint.Align.CENTER); mLevelPaint.setAntiAlias(true); mLevelPaint.setColor(getResources().getColor(R.color.input_hint_gray)); Rect bounds = new Rect(); mLevelPaint.getTextBounds(level, 0, level.length(), bounds); canvas.drawText(level, centerX, getHeight() / 2 + 2 * bounds.height() + 2 * getFontHeight(numberTextSize), mLevelPaint); } /** * 7.绘制骑行单位km */ private void drawTextUnit(Canvas canvas, float centerX) { Paint mUnitPaint = new Paint(); mUnitPaint.setTextSize(dipToPx(16)); mUnitPaint.setTextAlign(Paint.Align.CENTER); mUnitPaint.setAntiAlias(true); mUnitPaint.setColor(getResources().getColor(R.color.input_hint_gray)); Rect bounds = new Rect(); mUnitPaint.getTextBounds(unit, 0, unit.length(), bounds); canvas.drawText(unit, centerX+ stepNumber.length()*80, getHeight() / 2 + bounds.height() * 3 / 2, mUnitPaint); } /** * 获取当前步数的数字的高度 * * @param fontSize 字体大小 * @return 字体高度 */ public int getFontHeight(float fontSize) { Paint paint = new Paint(); paint.setTextSize(fontSize); Rect bounds_Number = new Rect(); paint.getTextBounds(stepNumber, 0, stepNumber.length(), bounds_Number); return bounds_Number.height(); } /** * dip 转换成px * * @param dip * @return */ private int dipToPx(float dip) { float density = getContext().getResources().getDisplayMetrics().density; return (int) (dip * density + 0.5f * (dip >= 0 ? 1 : -1)); } /** * 所走的步数进度 * @param totalStepNum 设置的步数 * @param currentCounts 所走步数 */ public void setCurrentCount(int totalStepNum, int currentCounts) { /**如果当前走的步数超过总步数则圆弧还是270度,不能成为园*/ if (currentCounts > totalStepNum) { currentCounts = totalStepNum; } /**上次所走步数占用总共步数的百分比*/ float scalePrevious = (float) Integer.valueOf(stepNumber) / totalStepNum; /**换算成弧度最后要到达的角度的长度-->弧长*/ float previousAngleLength = scalePrevious * angleLength; /**所走步数占用总共步数的百分比*/ float scale = (float) currentCounts / totalStepNum; /**换算成弧度最后要到达的角度的长度-->弧长*/ float currentAngleLength = scale * angleLength; /**开始执行动画*/ setAnimation(previousAngleLength, currentAngleLength, animationLength); stepNumber = String.valueOf(currentCounts); setTextSize(currentCounts); } /** * 设置各个参数 */ public void setParams(String today, String unit, String type, String level) { this.today = today; this.unit = unit; this.type = type; this.level = level; } /** * 为进度设置动画 * ValueAnimator是整个属性动画机制当中最核心的一个类,属性动画的运行机制是通过不断地对值进行操作来实现的, * 而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。 * 它的内部使用一种时间循环的机制来计算值与值之间的动画过渡, * 我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长, * 那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。 * * @param start 初始值 * @param current 结束值 * @param length 动画时长 */ private void setAnimation(float start, float current, int length) { ValueAnimator progressAnimator = ValueAnimator.ofFloat(start, current); progressAnimator.setDuration(length); progressAnimator.setTarget(currentAngleLength); progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { /**每次在初始值和结束值之间产生的一个平滑过渡的值,逐步去更新进度*/ currentAngleLength = (float) animation.getAnimatedValue(); invalidate(); } }); progressAnimator.start(); } /** * 设置文本大小,防止步数特别大之后放不下,将字体大小动态设置 * * @param num */ public void setTextSize(int num) { String s = String.valueOf(num); int length = s.length(); if (length 4 && length 6 && length 8) { numberTextSize = dipToPx(25); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 整个View的代码逻辑还是比较清晰的,自定义的view会首先调用onDraw()方法,获取了整个布局的中心和轮廓,然后开始七步分别绘制控件,这就是大家可以发挥的部分了,想怎么设计怎么设计。 第一步着重看一下,这个虚线的实现: float[] floats = {4,16,4,16}; paint.setPathEffect(new DashPathEffect(floats, 0)); 1 2 floats的四个参数意思是{画宽度,间隔宽度,画宽度,间隔宽度},这里的floats是数组也就是说你可以把每一个宽度和间隔都写出来,当然如果一样的话你可以只列出两个,系统会自动识别来延续后面的宽度和间隔。 因为注释很清楚,其他的这里就不详述了,想改啥基本都能看明白。 记步服务 public class StepService extends Service implements SensorEventListener { private String TAG = "StepService"; /** * 默认为10秒进行一次存储 */ private static int duration = 10 * 1000; /** * 传感管理对象 */ private SensorManager sensorManager; /** * 保存记步计时 */ private TimeCount time; /** * 当前所走的步数 */ private int CURRENT_STEP; /** * 计步传感类型 Sensor.TYPE_STEP_COUNTER或者Sensor.TYPE_STEP_DETECTOR */ private static int stepSensorType = -1; /** * 每次第一次启动记步服务时是否从系统中获取了已有的步数记录 */ private boolean hasRecord = false; /** * 系统中获取到的已有的步数 */ private int hasStepCount = 0; /** * 上一次的步数 */ private int previousStepCount = 0; /** * IBinder对象,向Activity传递数据的桥梁 */ private StepBinder stepBinder = new StepBinder(); @Override public void onCreate() { super.onCreate(); Log.d(TAG, "onCreate()"); new Thread(new Runnable() { public void run() { startStepDetector(); } }).start(); startTimeCount(); } /** * 开始保存记步数据 */ private void startTimeCount() { if (time == null) { time = new TimeCount(duration, 1000); } time.start(); } /** * UI监听器对象 */ private UpdateUiCallBack mCallback; /** * 注册UI更新监听 * * @param paramICallback */ public void registerCallback(UpdateUiCallBack paramICallback) { this.mCallback = paramICallback; } @Override public IBinder onBind(Intent intent) { return stepBinder; } /** * 向Activity传递数据的纽带 */ public class StepBinder extends Binder { /** * 获取当前service对象 * * @return StepService */ public StepService getService() { return StepService.this; } } /** * 获取当前步数 * * @return */ public int getStepCount() { return CURRENT_STEP; } @Override public void onStart(Intent intent, int startId) { super.onStart(intent, startId); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY; } /** * 获取传感实例 */ private void startStepDetector() { if (sensorManager != null) { sensorManager = null; } // 获取传感管理的实例 sensorManager = (SensorManager) this .getSystemService(SENSOR_SERVICE); //android4.4以后可以使用计步传感 addCountStepListener(); } /** * 添加传感监听 * 1. TYPE_STEP_COUNTER API的解释说返回从开机被激活后统计的步数,当重启手机后该数据归零, * 该传感是一个硬件传感所以它是低功耗的。 * 为了能持续的计步,请不要反注册事件,就算手机处于休眠状态它依然会计步。 * 当激活的时候依然会上报步数。该sensor适合在长时间的计步需求。 * * 2.TYPE_STEP_DETECTOR翻译过来就是走路检测, * API文档也确实是这样说的,该sensor只用来监监测走步,每次返回数字1.0。 * 如果需要长事件的计步请使用TYPE_STEP_COUNTER。 */ private void addCountStepListener() { Sensor countSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER); Sensor detectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR); if (countSensor != null) { stepSensorType = Sensor.TYPE_STEP_COUNTER; Log.v(TAG, "Sensor.TYPE_STEP_COUNTER"); sensorManager.registerListener(StepService.this, countSensor, SensorManager.SENSOR_DELAY_NORMAL); } else if (detectorSensor != null) { stepSensorType = Sensor.TYPE_STEP_DETECTOR; Log.v(TAG, "Sensor.TYPE_STEP_DETECTOR"); sensorManager.registerListener(StepService.this, detectorSensor, SensorManager.SENSOR_DELAY_NORMAL); } } /** * 传感监听回调 * @param event */ @Override public void onSensorChanged(SensorEvent event) { if (stepSensorType == Sensor.TYPE_STEP_COUNTER) { //获取当前传感返回的临时步数 int tempStep = (int) event.values[0]; //首次如果没有获取手机系统中已有的步数则获取一次系统中APP还未开始记步的步数 if (!hasRecord) { hasRecord = true; hasStepCount = tempStep; } else { //获取APP打开到现在的总步数=本次系统回调的总步数-APP打开之前已有的步数 int thisStepCount = tempStep - hasStepCount; //本次有效步数=(APP打开后所记录的总步数-上一次APP打开后所记录的总步数) int thisStep = thisStepCount - previousStepCount; //总步数=现有的步数+本次有效步数 CURRENT_STEP += (thisStep); //记录最后一次APP打开到现在的总步数 previousStepCount = thisStepCount; } } else if (stepSensorType == Sensor.TYPE_STEP_DETECTOR) { if (event.values[0] == 1.0) { CURRENT_STEP++; } } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } /** * 保存记步数据 */ class TimeCount extends CountDownTimer { public TimeCount(long millisInFuture, long countDownInterval) { super(millisInFuture, countDownInterval); } @Override public void onFinish() { // 如果计时正常结束,则开始计步 time.cancel(); mCallback.updateUi(CURRENT_STEP); startTimeCount(); } @Override public void onTick(long millisUntilFinished) { } } @Override public void onDestroy() { super.onDestroy(); //取消前台进程 stopForeground(true); } @Override public boolean onUnbind(Intent intent) { return super.onUnbind(intent); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 因为记步是在后台进行的,开启之后我们可以干其他事情,所以采用服务的方式,而我们需要获取记步的数据,所以要通过绑定的方式来注册服务,这样才能获得通信用的connection。逻辑思路是,通过计步来获取步数,然后设置监听器来监听步数的改变,如果步数改变更新步数的变量,然后开启一个计时来定时去记录,设置回调参数来返回步数。回调接口只有一个方法: public interface UpdateUiCallBack { /** * 更新UI步数 * * @param stepCount 步数 */ void updateUi(int stepCount); } 1 2 3 4 5 6 7 8 当然别忘了在AndroidManifest.xml中注册Service: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 还有记步需要用的权限: 1 2 3 调用MainActivity public class MainActivity extends AppCompatActivity { private StepView stepView; private Button button; private boolean isBind = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initData(); } private void initView() { stepView = (StepView) findViewById(R.id.step_walk_arv); button = (Button) findViewById(R.id.begin_btn); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { begin(); } }); } private void initData() { stepView.setParams("今日步数", "", "Walking", "等级:轻度活跃"); stepView.setCurrentCount(1000,0); } private void begin() { if (isBind == false){ //开启记步 Intent intent = new Intent(this, StepService.class); isBind = bindService(intent, conn, Context.BIND_AUTO_CREATE); startService(intent); button.setText("正在记步"); } } /** * 用于查询应用服务(application Service)的状态的一种interface, * 更详细的信息可以参考Service 和 context.bindService()中的描述, * 和许多来自系统的回调方式一样,ServiceConnection的方法都是进程的主线程中调用的。 */ ServiceConnection conn = new ServiceConnection() { /** * 在建立起于Service的连接时会调用该方法,目前Android是通过IBind机制实现与服务的连接。 * @param name 实际所连接到的Service组件名称 * @param service 服务的通信信道的IBind,可以通过Service访问对应服务 */ @Override public void onServiceConnected(ComponentName name, IBinder service) { StepService stepService = ((StepService.StepBinder) service).getService(); //设置初始化数据 stepView.setCurrentCount(1000, stepService.getStepCount()); //设置步数监听回调 stepService.registerCallback(new UpdateUiCallBack() { @Override public void updateUi(int stepCount) { stepView.setCurrentCount(1000, stepCount); } }); } /** * 当与Service之间的连接丢失的时候会调用该方法, * 这种情况经常发生在Service所在的进程崩溃或者被Kill的时候调用, * 此方法不会移除与Service的连接,当服务重新启动的时候仍然会调用 onServiceConnected()。 * @param name 丢失连接的组件名称 */ @Override public void onServiceDisconnected(ComponentName name) { } }; //服务解绑 @Override public void onDestroy() { super.onDestroy(); if (isBind) { unbindService(conn); isBind = false; } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 调用也很简单,首先在布局文件中引用StepView,然后初始化,设置圆弧里面的参数,设置总步数和当前步数(开始当然为0): stepView.setParams("今日步数", "", "Walking", "等级:轻度活跃"); stepView.setCurrentCount(1000,0); 1 2 其中还设置了一个boolean值isBind区分是否已经启动服务并绑定到了activity上,以便在onDestroy()方法是解除绑定。 整个计步的实现还是相对简单的,之前还想过要在圆弧圈外面画一个手指来指向当前的进度,不过暂时还没想通怎么实现,有兴趣的小伙伴研究之后告诉一声。
矩阵控制设计方案 目录 一、总体功能 4 1.主要功能模块: 4 2.功能框图: 5 二、中心处理模块 5 1.主要功能如下: 5 2.处理流程: 7 3.流程图: 8 三、键盘模块 8 1.基本流程如下: 9 2.流程图: 9 四、矩阵处理模块: 10 1主要功能如下: 10 2.基本流程如下: 11 3.流程图: 12 五、界面模块 12 5.1系统总体界面 12 5.2配置主页面 13 5.3自定义设置 14 5.3.1镜头组设置 14 5.3.2镜头组管理 15 5.3.3预案设置 16 5.4系统设置 17 5.4.1通道检测 17 5.4.2远程通道状态 17 5.4.3 矩阵类型 18 5.4.3 通道配置 19 5.4.3 用户管理 20 六、中心服务模块 21 1.接收中心服务模块基本流程: 21 2.流程图为: 22 3.将命令发向中心服务基本流程 23 4.流程图为: 23 七、数据库模块 23 1.[Admin]:管理员表 23 2.[CamGroup]:镜头组表 23 3.[CamList]:镜头列表 24 4.[ComInfo]:串口信息表 24 5.[Department]部门信息表 25 6.[LocalCam]本机镜头逻辑编号表 25 7.[MonCam]本地监视与镜头的对应表 25 8.[SwitchPlan]s 25 八、英飞拓矩阵模块 26 1.基本流程: 26 2.流程图: 27 一、总体功能 1.主要功能模块: 1.中心处理模块:用来联系各个模块,主要负责各个模块之间的互相通讯 和简单的逻辑判断。 2.键盘模块:矩阵控制接收键盘的指令,解析指令信息,并交给中心处理 模块进行处理,并且接收中心处理模块的反馈信息,将信息发向键盘在键盘 上显示。 3.矩阵模块:接收中心处理模块的指令并执行,将执行结果返回中心处理 模块。 4.中心服务模块:与中心服务交互,负责登录和接收中心服务的信 息,并交给中心处理模块处理,并负责将本地切换和控制远程镜头资源的命 令发给中心服务。 5.界面模块:接收界面的指令,并交给中心处理模块处理,并且将中心处 理模块产生的执行信息显示在界面上。 6.英飞拓矩阵模块:处理从中心服务接收到的远程命令并处理。 2.功能框图: 二、中心处理模块 中心处理模块与界面模块、键盘模块、矩阵模块和中心服务模块交互。 作为一个模块间的交互处理中心,对所有模块的传来的请求命令进行判断分 析,然后做出相应的处理。 1.主要功能如下: 读取配置信息:读取本地矩阵的基本配置信息,如矩阵类型等。 初始化功能:注册界面模块、键盘模块、矩阵模块和中心服务模块四 个模块的回调函数。 接收控制命令功能:接收来自界面处理、键盘处理、矩阵处理和CCS处理 四个模块的请求命令。 判断处理功能:对所有的模块的请求命令、结果回复进行判断处理。 2.具体判断逻辑如下: 键盘模块: 登录类型:将登录信息交给界面处理模块。 控制类型:包括监视的切换、翻页,镜头的切换、翻页、控 制、宏指令、辅助位、预置位。Pelco基本模式下:判断镜头 本地和远程。本地镜头交给矩阵处理模块处理,远程镜头交给 CCS处理模块处理。NW1联网模式下:不作判断,直接交给矩阵 处理模块处理,若不成功(可能是远程镜头或NW1原因)则交 给CCS处理模块处理。 矩阵模块: 登录结果类型:将登录的结果返回给界面处理模块。 控制回复类型:将控制结果返回给键盘处理模块和界面处理模 块。 报警类型:将报警开始 、报警结束转发给键盘,其他的处理保留。 矩阵状态类型:将矩阵状态返回给界面处理模块。检测矩阵状 态,矩阵掉线重新登录。结果返回给界面处理模块。 中心服务模块: 登录CCS结果类型:将登录结果返回给界面处理模块。 远程控制回复类型:将控制结果返回给键盘处理模块和界面处 理模块。 远程控制类型:将控制交给矩阵处理模块。 释放中继线:交给矩阵处理。 下载信息: 界面模块: 启动类型:启动全部的模块,建立各个模块之间通讯。 控制类型:与键盘模块的处理方式相同。 2.处理流程: 中心处理模块是位于整个软件的中心位置,它负责所有的信息交互和分发 ,主要的流程如下: 1.中心处理模块初始化键盘模块、矩阵模块和ccs模块。并且在各个模块 内注册回调函数。 2.中心处理模块时刻监听各个模块产生信息,当中心处理模块接收到键盘 发送的信息后,对信息进行类型解析,如果是键盘登陆结果或者是键盘掉线 等信息则将信息发送给界面模块供显示。如果是切换控制等指令,则将信息 发送给矩阵模块经行处理。 3.中心处理模块接收到矩阵模块的信息,并进行类型分析,如果是反馈给 键盘的信息,则讲给键盘处理,如果是需要反馈给中心服务的则交给中心 服务模块处理,如果
Servlet过滤监听器Java Web开发中的两个重要组件,可以在请求到达Servlet之前或者之后对请求和响应进行拦截、处理和修改,从而实现一些自定义的功能。 下面是Servlet过滤监听器的配置及应用: 1. 过滤的配置和应用: (1)在web.xml文件中配置过滤: ```xml <filter> <filter-name>MyFilter</filter-name> <filter-class>com.example.MyFilter</filter-class> </filter> <filter-mapping> <filter-name>MyFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ``` (2)编写过滤类: ```java public class MyFilter implements Filter { @Override public void init(FilterConfig config) throws ServletException { // 过滤初始化代码 } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 过滤逻辑代码 chain.doFilter(request, response); } @Override public void destroy() { // 过滤销毁代码 } } ``` (3)应用过滤: 过滤可以应用于所有的Servlet请求,或者只应用于特定的URL模式。在上面的配置中,我们将过滤应用于所有的URL模式。 2. 监听器的配置和应用: (1)在web.xml文件中配置监听器: ```xml <listener> <listener-class>com.example.MyListener</listener-class> </listener> ``` (2)编写监听器类: ```java public class MyListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent event) { // 应用初始化代码 } @Override public void contextDestroyed(ServletContextEvent event) { // 应用销毁代码 } } ``` (3)应用监听器监听器可以监听应用程序的生命周期事件,比如应用程序的初始化、销毁等事件。在上面的配置中,我们将监听器应用于应用程序的初始化和销毁事件。 以上就是Servlet过滤监听器的配置及应用的基本介绍。它们可以为我们提供很多灵活的机制来扩展和定制我们的Web应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值