导入闭包与权限申明

导入闭包

其中包括
1.新大陆闭包:用于连接新大陆云平台,通过底层硬件设备获取数据,并上传至云平台,移动端端通过此闭包,连接云平台,实时获取数据
2.Google推出的MaterialDesign API
3.MPAndroidChar:绘制折线图等

implementation project(path: ':nlecloud-sdk')
    implementation 'com.google.android.material:material:1.1.0-alpha09'
    implementation 'com.getbase:floatingactionbutton:1.10.1'
    implementation 'com.google.android.material:material:1.0.0'
    implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'

申明权限

因为要与获取云平台数据,所有申明网络权限

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
 <uses-permission android:name="android.permission.INTERNET" />
 <uses-permission android:name="android.permission.VIBRATE" />

网络安全问题

问题描述

Google表示,为保证用户数据和设备的安全,针对下一代 Android 系统(Android P) 的应用程序,将要求默认使用加密连接,这意味着 Android P 将禁止 App 使用所有未加密的连接,因此运行 Android P 系统的安卓设备无论是接收或者发送流量,未来都不能明码传输,需要使用下一代(Transport Layer Security)传输层安全协议,而 Android Nougat 和 Oreo 则不受影响。

解决方案

在Android Studio,res目录下创建一个xml包,再在xml包内创建一个network_security_config.xml文件(文件名自定义)
res->xml->network_security_config.xml
代码如下:

<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

然后在清单文件中引用

 android:networkSecurityConfig="@xml/network_security_config"

Activity

WelComeActvity

效果图

描述

右上角按钮数字从5开始倒计时,采用Handler异步通信实现,到0时,自动跳转到登录界面,代码如下:

Handler handler = new Handler(  ){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage( msg );
            if (msg.what == 0 && Flag) {
                int Count = CountDown();
                btn_Skip.setText( "跳过 " + Count );
                handler.sendEmptyMessageDelayed( 0,1000 );
            }
        }
    };

代码

代码中Flag用于Handler倒计时未结束,点击按钮进行跳转,异步通信未结束,防止再次渲染

**
 * Author:FranzLiszt
 * Completion time:9-20*/

public class WelComeActivity extends AppCompatActivity {
    private Button btn_Skip,GetInto;
    private int TotalNumber = 5;
    /*用于点击跳过或者进入应用按钮之后,界面发生跳转,但线程并未停止,时间到达,仍会重新渲染一次,
    使用此标志,用来控制不执行异步介绍的信息,从此达到中断的效果*/
    private boolean Flag = true;
    Handler handler = new Handler(  ){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage( msg );
            if (msg.what == 0 && Flag) {
                int Count = CountDown();
                btn_Skip.setText( "跳过 " + Count );
                handler.sendEmptyMessageDelayed( 0,1000 );
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate( savedInstanceState );
        if (Build.VERSION.SDK_INT >= 21) {
            View decorView = getWindow().getDecorView();
            decorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE );
            getWindow().setStatusBarColor( Color.TRANSPARENT );
        }
        setContentView( R.layout.activity_wel_come );
        InitView();
    }
    /*5s之后自动跳转*/
    private void InitView(){
        btn_Skip = findViewById( R.id.btn_Skip );
        GetInto = findViewById( R.id.GetInto);
        handler.sendEmptyMessageDelayed( 0,1000 );
    }
    private int CountDown(){
        if (TotalNumber -- == 1){
            ReturnActivity(LoginActivity.class);
        }
        return TotalNumber;
    }

    public void Skip(View view) {
        Flag = false;
        ReturnActivity(LoginActivity.class);
    }

    public void GetIntoApp(View view) {
        Flag = false;
        ReturnActivity(LoginActivity.class);
    }
    private void ReturnActivity(Class Activity){
        startActivity( new Intent( WelComeActivity.this,Activity ) );
    }
}

LoginActivity

效果图

描述

UI部分采用Google的MD组件库,此处省略,代码部分,主要获取用户输入的账户、密码传输给云平台进行匹配,如果密码正确,服务器会返回一个AccessToken(访问令牌)JSON数据,然后我们进行反序列化,使用此令牌进行后续操作

代码

获取AccessToken之后,通过SharedPreferences封装类SP进行保存(SP封装类在另一篇博文中有详细解锁,此处省略

https://editor.csdn.net/md/?articleId=120434977

public class LoginActivity extends AppCompatActivity {
    private EditText mUserName,mPassWord;
    private String AccessToken = "";
    private SP sp;
    private NetWorkBusiness business;
    private Context context = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate( savedInstanceState );
        if (Build.VERSION.SDK_INT >= 21) {
            View decorView = getWindow().getDecorView();
            decorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE );
            getWindow().setStatusBarColor( Color.TRANSPARENT );
        }
        setContentView( R.layout.activity_login );
        InitView();
    }
    private void InitView(){
        mUserName = findViewById( R.id.username );
        mPassWord = findViewById( R.id.password );
        if (context == null){
            context = LoginActivity.this;
        }
    }
    private void LoginMethod(){
        String UserName = mUserName.getText().toString().trim();
        String PassWord = mPassWord.getText().toString().trim();
        if (TextUtils.isEmpty( UserName )){
            Toast.makeText( context,"UserName cannot be empty",Toast.LENGTH_SHORT ).show();
            return;
        }
        if (TextUtils.isEmpty( PassWord )){
            Toast.makeText( context,"PassWord cannot be empty",Toast.LENGTH_SHORT ).show();
            return;
        }
        business = new NetWorkBusiness( AccessToken, Param.URL );
        business.signIn( new SignIn( UserName, PassWord ), new NCallBack<BaseResponseEntity<User>>(getApplicationContext()) {
            @Override
            protected void onResponse(BaseResponseEntity<User> response) {

            }

            @Override
            public void onResponse(Call<BaseResponseEntity<User>> call, Response<BaseResponseEntity<User>> response) {
                super.onResponse( call, response );
                BaseResponseEntity<User> body = response.body();
                if (body != null && body.getStatus() == 0){
                    sp = new SP( context );
                    AccessToken = body.getResultObj().getAccessToken();
                    /*将AccessToken存入sp*/
                    sp.PutData( context,"AccessToken",AccessToken );
                    ReturnActivity(MainActivity.class);
                    Toast.makeText( context,"Login Success",Toast.LENGTH_SHORT ).show();
                }else {
                    Toast.makeText( context,"Login Fail",Toast.LENGTH_SHORT ).show();
                }
            }

            @Override
            public void onFailure(Call<BaseResponseEntity<User>> call, Throwable t) {
                super.onFailure( call, t );
                Toast.makeText( context,"Exception",Toast.LENGTH_SHORT ).show();
            }
        } );
    }
    /*标题栏返回按钮*/
    public  void Exit(View view){
        ReturnActivity(WelComeActivity.class);
    }
    /*登录按钮*/
    public  void Login(View view){
        LoginMethod();
    }
    private void ReturnActivity(Class Activity){
        startActivity( new Intent( context,Activity ) );
    }
}

MainActivity

效果图

描述

顶部两个圆形进度条会根据传入的数据,发生相对应变化
样式变化规则如下:

  • 设置最多排队20个人,超过20人会实时显示,但不会联动触发样式效果
  • 10人及以下外圆弧与文字为绿色
  • 11-20人外圆弧与文字为紫色
  • 大于20及,外圆弧与文字为红色
    中间输入框为语音模块,输入的字符串,会通过云平台传入底层设备,底层设备会相对应语音播报相关内容
    点击取消排队之后,所有功能置灰,不起作用,唯有排队按钮可以使用,反之,排队中,其余按钮均可使用,唯独排队按钮不可使用

代码

/**
 * Author:FranzLiszt
 * Function:排队叫号
 * Tips:设置最多排队20个人,超过20人会实时显示,但不会联动触发样式效果
 * 10人及以下外圆弧与文字为绿色
 * 11-20人外圆弧与文字为紫色
 * 大于20及,外圆弧与文字为红色
 * 硬件没有限制,软件限制人数*/
/**
 * 核心思想:
 * 取号:获取一个号码,开始排队
 * 叫号:当前方排队人数小于3时,系统提示请前往现场办理业务,无需进行排队,所有功能置灰*/
public class MainActivity extends AppCompatActivity {
    /*圆形进度条上方提示文字
    * 作用:跟随进度条外圆弧颜色的变化而变化*/
    private TextView Text_CurrentPeople,Text_CurrentTime;
    /*圆形进度条
    * 作用:外圆弧跟随排队人数与剩余时间的变化而变化*/
    private ProgressBarView CurrentPeople,CurrentTime;
    /*需要输入的内容*/
    private EditText InputMessage;
    /*按键*/
    private Button SendMessage,ReadProgress,ReadRecord,LineUp,CancelLineUp;
    private RelativeLayout TipLayout;
    private TextView TipText,btn_Agree,pop_TipText,pop_TipAgree;
    private SP sp;
    private String AccessToken = "";
    private NetWorkBusiness business;
    private Context context = null;
    /*用来判断是否取消排队,中断线程*/
    private boolean Flag = true;
    /*用来装载获取服务器的排队人数*/
    private int mCurrentNumber;
    /*用来装载获取服务器的等候时间
    * 时间 = 人数 * 5
    * 基数自定义*/
    private int mCurrentWaitTime;
    /*用来判断是否正在排队,如果正在排队,排队按钮无法点击*/
    private boolean EnableFlag = false;
    private Thread thread;
    private boolean DialogFlag = true;
    private PopupWindow mPopupWindow,mPopupWindow_2;
    private View TipView,TipView_2;
    private static final int COMPLETE = 2;
    private static final int START = 1;
    private static final int STOP = 0;
    Handler handler = new Handler(  ){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage( msg );
            switch (msg.what){
                case COMPLETE:
                    CompleteQueuing();
                    break;
                case START:
                    GetAndSet();
                    break;
                case STOP:
                    clearStyle();
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate( savedInstanceState );
        if (Build.VERSION.SDK_INT >= 21) {
            View decorView = getWindow().getDecorView();
            decorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE );
            getWindow().setStatusBarColor( Color.TRANSPARENT );
        }
        setContentView( R.layout.activity_main );
        InitView();
        GetSpValue();
        Listener();
        GetCurrentPeople();
        InitPopWidows();
    }
    /**
     * Name:InitView
    * Function:初始化控件*/
    private void InitView(){
        Text_CurrentPeople = findViewById( R.id.Text_CurrentPeople );
        Text_CurrentTime = findViewById( R.id.Text_CurrentTime );
        InputMessage = findViewById( R.id.InputMessage );
        SendMessage = findViewById( R.id.SendMessage );
        ReadProgress = findViewById( R.id.ReadProgress );
        ReadRecord = findViewById( R.id.ReadRecord );
        LineUp = findViewById( R.id.btn_LineUp );
        CancelLineUp = findViewById( R.id.btn_CancelLineUp );
        CurrentPeople = findViewById( R.id.CurrentPeople );
        CurrentTime = findViewById( R.id.CurrentTime );
        TipLayout = findViewById( R.id.TipLayout );
        TipText = findViewById( R.id.TipText );
        if (context == null){
            context = MainActivity.this;
        }
        LineUp.setBackgroundResource( R.drawable.btn_notenable );
        LineUp.setEnabled( false );
    }
    /**
     * Name:GetSpValue
     * Function:获取AccessToken
     * 实例化NetWorkBusiness对象*/
    private void GetSpValue(){
        sp = new SP( context );
        AccessToken = (String) sp.GetData( context,"AccessToken","" );
        business = new NetWorkBusiness( AccessToken, Param.URL );
    }
    private void GetCurrentPeople(){
        thread = new Thread(  ){
            @Override
            public void run() {
                super.run();
                while (true) {
                    while (Flag) {
                        try {
                            Thread.sleep( 3000 );
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        Message message = new Message();
                        message.what = START;
                        handler.sendMessage( message );
                    }
                }
            }
        };
        thread.start();
    }
    private void GetAndSet(){
        business.getSensors( Param.DEVICEID, Param.QUEUENUMBER, new NCallBack<BaseResponseEntity<List<SensorInfo>>>(context) {
            @Override
            protected void onResponse(BaseResponseEntity<List<SensorInfo>> response) {

            }

            @Override
            public void onResponse(Call<BaseResponseEntity<List<SensorInfo>>> call, Response<BaseResponseEntity<List<SensorInfo>>> response) {
                super.onResponse( call, response );
                BaseResponseEntity<List<SensorInfo>> body = response.body();
                if (body!=null && body.getStatus() == 0){
                    mCurrentNumber = Integer.parseInt( body.getResultObj().get( 0 ).getValue() );
                    mCurrentWaitTime = mCurrentNumber * 5;
                    sp.PutData( context,"CurrentNumber",mCurrentNumber );
                    sp.PutData( context,"CurrentWaitTime",mCurrentWaitTime );
                }
            }
        } );
        runOnUiThread( ()->{
            if (mCurrentNumber >= 20){
                /*人数大于20,红色*/
                setRed();
                DialogFlag = true;
                DisplayLayout_Queuing();
            }else if (mCurrentNumber < 20 && mCurrentNumber > 10 ){
                /*人数10-20,紫色*/
                setViolet();
                DialogFlag = true;
                DisplayLayout_Queuing();
            }else if (mCurrentNumber <= 10 && mCurrentNumber > 3){
                /*人数小于10,绿色*/
                setGreen();
                DialogFlag = true;
                DisplayLayout_Queuing();
            }else if (mCurrentNumber <=3 && mCurrentNumber > 0){
                if (DialogFlag){
                Flag = false;
                Message message = new Message();
                message.what = COMPLETE;
                handler.sendMessage( message );
                }
            }
        } );
    }
    private void Control(String DeviceID,String Tag,Object value){
        business.control( DeviceID, Tag, value, new NCallBack<BaseResponseEntity>(getApplicationContext()) {
            @Override
            protected void onResponse(BaseResponseEntity response) {

            }

            @Override
            public void onResponse(Call<BaseResponseEntity> call, Response<BaseResponseEntity> response) {
                super.onResponse( call, response );
               BaseResponseEntity<User> body = response.body();
               if (body == null && body.getStatus() != 0){
                   Toast.makeText( context,"请求失败",Toast.LENGTH_SHORT ).show();
               }
            }

            @Override
            public void onFailure(Call<BaseResponseEntity> call, Throwable t) {
                super.onFailure( call, t );
                Toast.makeText( context,"异常",Toast.LENGTH_SHORT ).show();
            }
        } );
    }
    private void SendVoiceMessage(){
        String Message = InputMessage.getText().toString().trim();
        Control( Param.DEVICEID,Param.VOIVE,Message );
    }
    private void InitPopWidows(){
        TipView = LayoutInflater.from( context ).inflate( R.layout.pop_item,null );
        btn_Agree = TipView.findViewById( R.id.btn_Agree );
        mPopupWindow = new PopupWindow( TipView, ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT );
        mPopupWindow.setFocusable( true ); //获取焦点
        mPopupWindow.setBackgroundDrawable( new BitmapDrawable() );
        mPopupWindow.setOutsideTouchable( true ); //点击外面地方,取消
        mPopupWindow.setTouchable( true ); //允许点击
        mPopupWindow.setAnimationStyle( R.style.PopupWindow ); //设置动画
        btn_Agree.setOnClickListener( new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //EnableFlag = true;
                setGrey();
                setStyleInvalid();
                setButtonNotEnabled();
                /*手机震动*/
                Vibrator vibrator = (Vibrator) getSystemService( Service.VIBRATOR_SERVICE);
                vibrator.vibrate(100);
                mPopupWindow.dismiss();
            }
        } );

        TipView_2 = LayoutInflater.from( context ).inflate( R.layout.tip_pop_item,null );
        pop_TipText = TipView_2.findViewById( R.id.pop_TipsText );
        pop_TipAgree = TipView_2.findViewById( R.id.pop_TipAgree );
        mPopupWindow_2 = new PopupWindow( TipView_2, ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT );
        mPopupWindow_2.setFocusable( true ); //获取焦点
        mPopupWindow_2.setBackgroundDrawable( new BitmapDrawable() );
        mPopupWindow_2.setOutsideTouchable( true ); //点击外面地方,取消
        mPopupWindow_2.setTouchable( true ); //允许点击
        mPopupWindow_2.setAnimationStyle( R.style.PopupWindow ); //设置动画
        pop_TipAgree.setOnClickListener( new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mPopupWindow_2.dismiss();
            }
        } );
    }
    private void DisPlayPopWindows(){
        mPopupWindow.showAtLocation( TipView, Gravity.CENTER,0,0 );
    }
    private void ShowPopWindows(){
        pop_TipText.setText( "目前前方剩余"+mCurrentNumber+"人,需要等候"+mCurrentWaitTime+"min" );
        mPopupWindow_2.showAtLocation( TipView_2,Gravity.CENTER,0,0 );
    }
    private void DisplayLayout_Queuing(){
        TipLayout.setVisibility( View.VISIBLE );
        TipText.setText( "当前正在排队中,请文明排队" );
    }
    private void DisplayLayout_CancelQueuing(){
        TipLayout.setVisibility( View.VISIBLE );
        TipText.setText( "当前号码已作废,请重新排队" );
    }
    private void DisplayLayout_CallNumber(){
        TipLayout.setVisibility( View.VISIBLE );
        TipText.setText( "排队完成,请前往现场办理业务" );
    }
    private void CompleteQueuing(){
        /*人数小于3,给予提示*/
         DisplayLayout_CallNumber();
         DisPlayPopWindows();
    }
    private void setRed(){
        Text_CurrentPeople.setTextColor( getResources().getColor( R.color.colorRed ) );
        Text_CurrentTime.setTextColor( getResources().getColor( R.color.colorRed ) );
        Text_CurrentPeople.setText( mCurrentNumber+getResources().getString( R.string.Tips_2 ) );
        Text_CurrentTime.setText( mCurrentWaitTime+"Min" );
        CurrentPeople.setProgress( 100 );
        CurrentPeople.setCircleColor( getResources().getColor( R.color.colorRed ) );
        CurrentPeople.setContent( "拥挤" );
        CurrentTime.setProgress( 100 );
        CurrentTime.setCircleColor( getResources().getColor( R.color.colorRed ) );
        CurrentTime.setContent( "时间长" );
    }
    private void setViolet(){
        Text_CurrentPeople.setTextColor( getResources().getColor( R.color.colorViolet ) );
        Text_CurrentTime.setTextColor( getResources().getColor( R.color.colorViolet ) );
        Text_CurrentPeople.setText( mCurrentNumber+getResources().getString( R.string.Tips_2 ) );
        Text_CurrentTime.setText( mCurrentWaitTime+"Min" );
        CurrentPeople.setProgress( mCurrentWaitTime );
        CurrentPeople.setCircleColor( getResources().getColor( R.color.colorViolet ) );
        CurrentPeople.setContent( "正常" );
        CurrentTime.setProgress( mCurrentWaitTime );
        CurrentTime.setCircleColor( getResources().getColor( R.color.colorViolet ) );
        CurrentTime.setContent( "时间中" );
    }
    private void setGreen(){
            Text_CurrentPeople.setTextColor( getResources().getColor( R.color.colorGreen ) );
            Text_CurrentTime.setTextColor( getResources().getColor( R.color.colorGreen ) );
            Text_CurrentPeople.setText( mCurrentNumber+getResources().getString( R.string.Tips_2 ) );
            Text_CurrentTime.setText( mCurrentWaitTime+"Min" );
            CurrentPeople.setProgress( mCurrentWaitTime );
            CurrentPeople.setCircleColor( getResources().getColor( R.color.colorGreen ) );
            CurrentPeople.setContent( "畅通" );
            CurrentTime.setProgress( mCurrentWaitTime );
            CurrentTime.setCircleColor( getResources().getColor( R.color.colorGreen ) );
            CurrentTime.setContent( "时间短" );
    }
    private void setGrey(){
            Text_CurrentPeople.setTextColor( getResources().getColor( R.color.colorGrey ) );
            Text_CurrentTime.setTextColor( getResources().getColor( R.color.colorGrey ) );
            Text_CurrentPeople.setText( "0"+getResources().getString( R.string.Tips_2 ) );
            Text_CurrentTime.setText( "0 Min" );
            CurrentPeople.setProgress( 0 );
            CurrentPeople.setCircleColor( getResources().getColor( R.color.colorGrey ) );
            CurrentPeople.setContent( "无" );
            CurrentTime.setProgress( 0 );
            CurrentTime.setCircleColor( getResources().getColor( R.color.colorGrey ) );
            CurrentTime.setContent( "无" );
    }
    /*按钮不能点击*/
    private void setButtonNotEnabled(){
        SendMessage.setEnabled( false );
        ReadProgress.setEnabled( false );
        ReadRecord.setEnabled( false );
        CancelLineUp.setEnabled( false );
        InputMessage.setEnabled( false );
        LineUp.setEnabled( true );
        InputMessage.setText( "" );
    }
    /*样式灰色*/
    private void setStyleInvalid(){
        SendMessage.setBackgroundResource( R.drawable.btn_notenable );
        ReadProgress.setBackgroundResource( R.drawable.btn_notenable );
        ReadRecord.setBackgroundResource( R.drawable.btn_notenable );
        CancelLineUp.setBackgroundResource( R.drawable.btn_notenable );
        LineUp.setBackgroundResource( R.drawable.btn_login );
    }
    /*样式恢复正常*/
    private void setNormalStyle(){
        SendMessage.setBackgroundResource( R.drawable.btn_login );
        ReadProgress.setBackgroundResource( R.drawable.btn_login );
        ReadRecord.setBackgroundResource( R.drawable.btn_login );
        CancelLineUp.setBackgroundResource( R.drawable.btn_login );
        LineUp.setBackgroundResource( R.drawable.btn_notenable );
    }
    /*按钮允许点击*/
    private void setButtonEnabled(){
        SendMessage.setEnabled( true );
        ReadProgress.setEnabled( true );
        ReadRecord.setEnabled( true );
        CancelLineUp.setEnabled( true );
        InputMessage.setEnabled( true );
        LineUp.setEnabled( false );
    }
    private void NormalStyle(){
        DialogFlag = false;
        Flag = true;
        setNormalStyle();
        setButtonEnabled();
        Message message = new Message();
        message.what = START;
        handler.sendMessage( message );
    }
    /*排队取消状态
    * 所有控件置灰*/
    private void clearStyle(){
        Flag = false;
        DisplayLayout_CancelQueuing();
        setGrey();
        setButtonNotEnabled();
        setStyleInvalid();
    }
    private void StopThread(){
        Flag = false;
        try {
            thread.join( 1000 );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Message message = new Message();
        message.what = STOP;
        handler.sendMessage( message );
    }
    /*返回按钮*/
    public void Exit(View view){
      ReturnActivity( LoginActivity.class );
    }
    private void ReturnActivity(Class Activity){
        startActivity( new Intent( context,Activity ) );
    }

    private void Listener(){
        OnClick onClick = new OnClick();
        SendMessage.setOnClickListener( onClick );
        ReadRecord.setOnClickListener( onClick );
        ReadProgress.setOnClickListener( onClick );
        LineUp.setOnClickListener( onClick );
        CancelLineUp.setOnClickListener( onClick );
    }
    class OnClick implements View.OnClickListener{

        @Override
        public void onClick(View v) {
            switch (v.getId()){
                case R.id.SendMessage:
                    SendVoiceMessage();
                    break;
                case R.id.btn_LineUp:
                        NormalStyle();
                    break;
                case R.id.btn_CancelLineUp:
                    StopThread();
                    break;
                case R.id.ReadProgress:
                    ShowPopWindows();
                    break;
                case R.id.ReadRecord:
                    ReturnActivity( HistoricalDataActivity.class );
                    break;
            }
        }
    }
}

HistoricalDataActivity

效果图

描述

通过在子线程实时获取数据,然后通过runOnUiThread跳转到主线程,实时更新UI,具体使用此处省略,代码基本每句都有注释

代码

public class HistoricalDataActivity extends AppCompatActivity {
    private LineChart LineChart;
    private String[] mDate;
    private LineData mLineData; // 线集合,所有折线以数组的形式存到此集合中
    private LineDataSet mDataSet; // 点集合,即一条折线
    private List<Entry> mEntries; // Entry为某条折线上的一个点,其List封装于LineDataSet中
    private Timer mTimer; // 定时器,动态获取数据
    private NetWorkBusiness mNetWorkBusiness;
    private String mAccessToken;
    private SP sp;
    private Context context = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate( savedInstanceState );
        if (Build.VERSION.SDK_INT >= 21) {
            View decorView = getWindow().getDecorView();
            decorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE );
            getWindow().setStatusBarColor( Color.TRANSPARENT );
        }
        setContentView( R.layout.activity_historical_data );
        InitView();
        InitLineChart();
    }
    private void InitView(){
        LineChart = findViewById( R.id.LineChart );
        if (context == null){
            context = HistoricalDataActivity.this;
        }
        sp = new SP( context );
        mAccessToken = (String) sp.GetData( context,"AccessToken","" );
        mNetWorkBusiness = new NetWorkBusiness( mAccessToken, Param.URL );
    }
    public void Exit(View view){
        startActivity( new Intent( context,MainActivity.class ) );
    }

    private void InitLineChart(){
        LineChart.getDescription().setText("时间");//设置图表的描述文字,会显示在图表的右下角。
        LineChart.getLegend().setEnabled(false);
        LineChart.setTouchEnabled(true);//启用/禁用与图表的所有可能的触摸交互。
        LineChart.setDragEnabled(true);//启用/禁用拖动(平移)图表。
        LineChart.setScaleEnabled(true);//启用/禁用缩放图表上的两个轴。
        LineChart.setDrawGridBackground(true);//如果启用,chart绘图区后面的背景矩形将绘制。
        LineChart.setPinchZoom(false);//如果设置为true,没缩放功能。如果false,x轴和y轴可分别放大。
        LineChart.setBackgroundColor(getResources().getColor( R.color.colorWhite ));//设置背景颜色,将覆盖整个图表视图。此外,背景颜色可以在布局文件.xml中进行设置。
        LineChart.setBorderColor( getResources().getColor( R.color.colorBlue_1 ) );//设置chart边框线的颜色
        LineChart.setBorderWidth( 1 );//setBorderWidth(float width):设置chart边界线的宽度,单位dp。
        LineChart.getAxisRight().setEnabled(false);// 禁止绘制右坐标轴
        /*X轴数据*/
        XAxis xAxis = LineChart.getXAxis();
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        xAxis.setDrawGridLines(false);//设置为true,则绘制网格线。
        xAxis.setLabelCount(5,false); // force:false,仅建议刻度线标签的数量为10
        xAxis.setTextSize(5);
        xAxis.setGridColor( getResources().getColor( R.color.colorViolet) );
        xAxis.setValueFormatter( new ValueFormatter() {
            @Override
            public String getFormattedValue(float value) {
                return mDate[(int) value];
            }
        } );
        /*Y轴数据*/
        YAxis yAxis = LineChart.getAxisLeft();
        yAxis.setAxisMinimum(0f); // 设置y轴的坐标最小值为0(人数不小于0)
        yAxis.setGranularity(1f); // 设置y轴的坐标之间的最小间隔为1(单位:人)
        yAxis.setLabelCount(10, false); // force:false,仅建议刻度线标签的数量为12
        yAxis.setGridColor(getResources().getColor( R.color.colorViolet));

        mEntries = new ArrayList<Entry>();
        mDataSet = new LineDataSet(mEntries, "排队人数");
        mDataSet.setDrawCircles(true); // 禁止绘制折线圆点
        mDataSet.setHighlightEnabled(true); // 禁止高亮选中点
        mDataSet.setColor(getResources().getColor( R.color.colorBlue_1)); // 折线颜色
        mDataSet.setValueFormatter(new ValueFormatter() {
            @Override
            public String getFormattedValue(float value) {
                return  "";
            }
        });
        mLineData = new LineData(mDataSet);
        LineChart.setData(mLineData);
        LineChart.invalidate(); // 更新视图

        mTimer = new Timer(  );
        mTimer.schedule( new TimerTask() {
            @Override
            public void run() {
                mNetWorkBusiness.getSensorData( Param.DEVICEID, Param.QUEUENUMBER, "1", "1", null, null, "ASC", "10", "1", new NCallBack<BaseResponseEntity<SensorDataPageDTO>>(context) {
                    @Override
                    protected void onResponse(BaseResponseEntity<SensorDataPageDTO> response) {

                    }

                    @Override
                    public void onResponse(Call<BaseResponseEntity<SensorDataPageDTO>> call, Response<BaseResponseEntity<SensorDataPageDTO>> response) {
                        super.onResponse( call, response );
                       List<SensorDataPageDTO.DataPoint> body = response.body().getResultObj().DataPoints;
                       if (body == null){
                           return;
                       }else {
                           List<SensorDataPageDTO.VR> list = body.get(0).PointDTO;
                           SensorDataPageDTO.VR[] array = new SensorDataPageDTO.VR[list.size()];
                           list.toArray(array);
                           mDataSet.clear();
                           mDate = new String[array.length];
                           // = 0;
                           for (int idx = 0; idx < array.length; idx++) {
                               mDate[idx] = array[idx].RecordTime;
                               mDataSet.addEntry(new Entry((float) idx, Float.parseFloat(array[idx].Value)));
                           }
                           runOnUiThread( ()->{
                               // 通知LinData数据已发生变更,以重新计算绘制参数
                               LineChart.getLineData().notifyDataChanged();
                               // 让ChartLine知道其基础数据已更改,并执行所有必要的计算。每次动态更改数据时,若不调用此方法可能导致崩溃或意外行为。
                               LineChart.notifyDataSetChanged();
                               LineChart.invalidate();
                           } );
                       }
                    }
                } );

            }
        },100,2000 );
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mTimer.cancel();
    }
}

后台数据

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结

路漫漫其修远兮,吾将上下而求索

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐