主頁 > 移動端開發 > 基于nlecloud(新大陸)實作智能排隊機——Android端

基于nlecloud(新大陸)實作智能排隊機——Android端

2021-09-24 11:08:53 移動端開發

智能排隊機

  • 匯入閉包與權限申明
    • 匯入閉包
    • 申明權限
    • 網路安全問題
      • 問題描述
      • 解決方案
  • Activity
    • WelComeActvity
      • 效果圖
      • 描述
      • 代碼
    • LoginActivity
      • 效果圖
      • 描述
      • 代碼
    • MainActivity
      • 效果圖
      • 描述
      • 代碼
    • HistoricalDataActivity
      • 效果圖
      • 描述
      • 代碼
    • 后臺資料
  • 總結

匯入閉包與權限申明

匯入閉包

其中包括
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();
    }
}

后臺資料

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

總結

路漫漫其修遠兮,吾將上下而求索

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/302531.html

標籤:其他

上一篇:分析服務助力產品運營

下一篇:Android編程權威指南第3版 2.7 挑戰練習:為 TextView 添加監聽器

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more