简体   繁体   English

定时器从服务类调用并连接到EEG耳机时出错

[英]Timer Error when called from a Service class and is connected to an EEG headset

I have a problem with retrieving the correct values from my program. 从程序中检索正确的值时遇到问题。 I am currently using the startService in order to start a Timer from a service class and be able to close it from my mainActivity class. 我目前正在使用startService来从服务类启动一个Timer,并能够从我的mainActivity类中关闭它。 The example that i am using activates the timer within the class and seems to be working just fine but the problem is i cant close it from my mainActivity class. 我正在使用的示例激活类中的计时器,似乎工作正常,但问题是我无法从我的mainActivity类关闭它。

PS. PS。 I am using the EPOC+ EEG headset for my program. 我正在为我的程序使用EPOC + EEG耳机。

This is my Activity Training Class 这是我的活动培训班

import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

public class ActivityTraining extends Activity implements EngineInterface {

EngineConnector engineConnector;

Spinner spinAction;
Button btnTrain, btnClear;
ProgressBar progressBarTime,progressPower;
AdapterSpinner spinAdapter;
ImageView imgBox;
ArrayList<DataSpinner> model = new ArrayList<DataSpinner>();
int indexAction, _currentAction,userId=0,count=0;

Timer timer;
TimerTask timerTask;

float _currentPower = 0;
float startLeft = -1;
float startRight = 0;
float widthScreen = 0;

boolean isTraining =false;
ArrayList<Song> songList;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_trainning);
    engineConnector = EngineConnector.shareInstance();
    engineConnector.delegate = this;
    init();
    songList = (ArrayList<Song>) getIntent()
            .getSerializableExtra(MusicPhoneUtils.SONG_LIST_INTENT);
    Log.d("ActivityTraining", "GOT SONG COUNT = " + songList.size());

}

public void init() {
    spinAction=(Spinner)findViewById(R.id.spinnerAction);
    btnTrain=(Button)findViewById(R.id.btstartTraing);
    btnClear=(Button)findViewById(R.id.btClearData);
    btnClear.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (indexAction){
                case 0:
                    engineConnector.trainningClear(IEmoStateDLL.IEE_MentalCommandAction_t.MC_NEUTRAL.ToInt());
                    break;
                case 1:
                    engineConnector.trainningClear(IEmoStateDLL.IEE_MentalCommandAction_t.MC_PUSH.ToInt());
                    break;
                case 2:
                    engineConnector.trainningClear(IEmoStateDLL.IEE_MentalCommandAction_t.MC_PULL.ToInt());
                    break;
                case 3:
                    engineConnector.trainningClear(IEmoStateDLL.IEE_MentalCommandAction_t.MC_LEFT.ToInt());
                    break;
                case 4:
                    engineConnector.trainningClear(IEmoStateDLL.IEE_MentalCommandAction_t.MC_RIGHT.ToInt());
                    break;
                default:
                    break;
            }
        }
    });

    progressBarTime=(ProgressBar)findViewById(R.id.progressBarTime);
    progressBarTime.setVisibility(View.INVISIBLE);
    progressPower=(ProgressBar)findViewById(R.id.ProgressBarpower);
    imgBox = (ImageView)findViewById(R.id.imgBox);

    setDataSpinner();
    spinAction.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
            indexAction = arg2;
        }
        public void onNothingSelected(AdapterView<?> arg0) {
            //TODO Auto-genereted method stub
        }
    });

Here is were i am calling the the service class to start 这是我打电话给服务类开始

    Intent strtService = new Intent().setClass(getApplicationContext(), StartEndEpocService.class);
    startService(strtService);

And here is the were the original timer is located 这是原来的计时器所在

    Timer timeListenAction = new Timer();
    timeListenAction.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            handlerUpdateUI.sendEmptyMessage(1);
        }
    }, 0, 20);

}

The connected method is being called from the Service class to pass the value to the handlerUpdateUI 从Service类调用connected方法将值传递给handlerUpdateUI

public void connect() {
    handlerUpdateUI.sendEmptyMessage(1);
}


Handler handlerUpdateUI = new Handler(){
    public void handleMessage(Message msg) {
        switch (msg.what){
            case 0:
                count++;
                int trainninTime = (int)MentalCommandDetection.IEE_MentalCommandGetTrainingTime(userId)[1]/1000;
                if(trainninTime>0){
                    progressBarTime.setProgress(count/trainninTime);
                }
                if (progressBarTime.getProgress()>=100){
                    timerTask.cancel();
                    timer.cancel();
                }
                break;
            case 1:
                changePages();
            default:
                break;
        }
    };

};

public void startTrainingMentalcommand(IEmoStateDLL.IEE_MentalCommandAction_t MentalCommandAction) {
    isTraining = engineConnector.startTrainingMetalcommand(isTraining, MentalCommandAction);
    btnTrain.setText((isTraining) ? "Abort Trainning" : "Train");
}

public void setDataSpinner(){
    model.clear();
    DataSpinner data = new DataSpinner();
    data.setTvName("Neutral");
    data.setChecked(engineConnector.checkTrained(IEmoStateDLL.IEE_MentalCommandAction_t.MC_NEUTRAL.ToInt()));
    model.add(data);

    data = new DataSpinner();
    data.setTvName("Push");
    data.setChecked(engineConnector.checkTrained(IEmoStateDLL.IEE_MentalCommandAction_t.MC_PUSH.ToInt()));
    model.add(data);

    data = new DataSpinner();
    data.setTvName("Pull");
    data.setChecked(engineConnector.checkTrained(IEmoStateDLL.IEE_MentalCommandAction_t.MC_PULL.ToInt()));
    model.add(data);

    data=new DataSpinner();
    data.setTvName("Left");
    data.setChecked(engineConnector.checkTrained(IEmoStateDLL.IEE_MentalCommandAction_t.MC_LEFT.ToInt()));
    model.add(data);

    data=new DataSpinner();
    data.setTvName("Right");
    data.setChecked(engineConnector.checkTrained(IEmoStateDLL.IEE_MentalCommandAction_t.MC_RIGHT.ToInt()));
    model.add(data);

    spinAdapter = new AdapterSpinner(this, R.layout.row, model);
    spinAdapter.setDropDownViewResource(R.layout.support_simple_spinner_dropdown_item);
    spinAction.setAdapter(spinAdapter);
}

@Override
public boolean onCreateOptionMenu(Menu menu){
    getMenuInflater().inflate(R.menu.activity_trainning, menu);
    return true;
}

public void TimerTask(){
    count = 0;
    timerTask = new TimerTask() {
        @Override
        public void run() {
            handlerUpdateUI.sendEmptyMessage(0);
        }
    };
}

private void changePages() {
    //currentAction(_currentAction, _currentPower);
    float power = _currentPower;
Log.e("ActivityTraining", "current_action: " + _currentAction);  
Log.e("ActivityTraining", "power: " + power);

    if ((_currentAction == IEmoStateDLL.IEE_MentalCommandAction_t.MC_PUSH.ToInt() && power > 0)) {
        Log.e("ActivityTraining", "current_action: " + _currentAction);
        Log.e("ActivityTraining", "power: " + power);
        Intent MC_RIGHT = new Intent().setClass(getApplicationContext(), FragmentBondActivity.class);
        MC_RIGHT.putExtra(MusicPhoneUtils.SONG_LIST_INTENT, songList);
        MC_RIGHT.putExtra(MusicPhoneUtils.START_AUTO_PLAY_INTENT, false);
        MC_RIGHT.putExtra(MusicPhoneUtils.LAST_SONG_USER_PLAYED_INTENT,
                getIntent().getSerializableExtra(MusicPhoneUtils.LAST_SONG_USER_PLAYED_INTENT));
        MC_RIGHT.putExtra("target", "play");
        startActivity(MC_RIGHT);
    }

    if (((_currentAction == IEmoStateDLL.IEE_MentalCommandAction_t.MC_LEFT.ToInt())) && power > 0) {
        Log.e("ActivityTraining", "current_action: " + _currentAction);
        Log.e("ActivityTraining", "power: " + power);
        Intent MC_LEFT = new Intent().setClass(getApplicationContext(),FragmentBondActivity.class);
        MC_LEFT.putExtra(MusicPhoneUtils.SONG_LIST_INTENT, songList);
        MC_LEFT.putExtra("target", "songList");
        startActivity(MC_LEFT);
    }

    if(((_currentAction == IEmoStateDLL.IEE_MentalCommandAction_t.MC_RIGHT.ToInt())) && power > 0) {
        Log.e("ActivityTraining", "current_action: " + _currentAction);
        Log.e("ActivityTraining", "power: " + power);
        Intent MC_RIGHT = new Intent().setClass(getApplicationContext(), SettingsActivity.class);
        startActivity(MC_RIGHT);

    }

    if(((_currentAction == IEmoStateDLL.IEE_MentalCommandAction_t.MC_PULL.ToInt())) && power > 0) {
        Log.e("ActivityTraining", "current_action: " + _currentAction);
        Log.e("ActivityTraining", "power: " + power);
        Intent MC_PULL = new Intent().setClass(getApplicationContext(), MainActivity.class);
        MC_PULL.putExtra(MusicPhoneUtils.SONG_LIST_INTENT, songList);
        MC_PULL.putExtra("target", "songList");
        startActivity(MC_PULL);

    }
}

public void enableClick() {
    btnClear.setClickable(true);
    spinAction.setClickable(true);
}

@Override
public void userAdd(int userId) {
    // TODO Auto-generated method stub
    this.userId=userId;
}

@Override
public void userRemoved() {
    // TODO Auto-generated method stub
}

@Override
public void trainStarted() {
    // TODO Auto-generated method stub
    progressBarTime.setVisibility(View.VISIBLE);
    btnClear.setClickable(false);
    spinAction.setClickable(false);
    timer = new Timer();
    TimerTask();
    timer.schedule(timerTask , 0, 10);
}

@Override
public void trainSucceed() {
    // TODO Auto-generated method stub
    progressBarTime.setVisibility(View.VISIBLE);
    btnTrain.setText("Train");
    enableClick();
    AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
            ActivityTraining.this);
    // set title
    alertDialogBuilder.setTitle("Training Succeeded");
    // set dialog message
    alertDialogBuilder
            .setMessage("Training is successful. Accept this training?")
            .setCancelable(false)
            .setIcon(R.drawable.ic_launcher)
            .setPositiveButton("Yes",
                    new DialogInterface.OnClickListener() {
                        public void onClick(
                                DialogInterface dialog,int which) {
                            engineConnector.setTrainControl(MentalCommandDetection.IEE_MentalCommandTrainingControl_t.MC_ACCEPT.getType());
                        }
                    })
            .setNegativeButton("No",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            engineConnector.setTrainControl(MentalCommandDetection.IEE_MentalCommandTrainingControl_t.MC_REJECT.getType());
                        }
                    });

    AlertDialog alertDialog = alertDialogBuilder.create();
    alertDialog.show();
}

@Override
public  void trainFailed(){
    progressBarTime.setVisibility(View.INVISIBLE);
    btnTrain.setText("Train");
    enableClick();
    AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
            ActivityTraining.this);
    // set title
    alertDialogBuilder.setTitle("Training Failed");
    // set dialog message
    alertDialogBuilder
            .setMessage("Signal is noisy. Can't training")
            .setCancelable(false)
            .setIcon(R.drawable.ic_launcher)
            .setPositiveButton("OK",
                    new DialogInterface.OnClickListener() {
                        public void onClick(
                                DialogInterface dialog, int which) {

                        }
                    });

    AlertDialog alertDialog = alertDialogBuilder.create();
    alertDialog.show();
    isTraining = false;
}

@Override
public void trainCompleted() {
    // TODO Auto-generated method stub
    DataSpinner data=model.get(indexAction);
    data.setChecked(true);
    model.set(indexAction, data);
    spinAdapter.notifyDataSetChanged();
    isTraining = false;
}

@Override
public void trainRejected() {
    // TODO Auto-generated method stub
    DataSpinner data=model.get(indexAction);
    data.setChecked(false);
    model.set(indexAction, data);
    spinAdapter.notifyDataSetChanged();
    enableClick();
    isTraining = false;
}

@Override
public void trainErased() {
    // TODO Auto-generated method stub
    new AlertDialog.Builder(this)
            .setTitle("Training Erased")
            .setMessage("")
            .setPositiveButton(android.R.string.yes, new    DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                }
            })
            .setIcon(android.R.drawable.ic_dialog_alert)
            .show();
    DataSpinner data=model.get(indexAction);
    data.setChecked(false);
    model.set(indexAction, data);
    spinAdapter.notifyDataSetChanged();
    enableClick();
    isTraining = false;
}

@Override
public void trainReset() {
    // TODO Auto-generated method stub
    if(timer!=null){
        timer.cancel();
        timerTask.cancel();
    }
    isTraining = false;
    progressBarTime.setVisibility(View.VISIBLE);
    progressBarTime.setProgress(0);
    enableClick();
};

Here is were the problem starts. 这是问题的开始。 When i calling the timer from the service class the values of _currentAction and _currentPower don't get updated into the class. 当我从服务类调用计时器时,_currentAction和_currentPower的值不会更新到类中。 The normal values after the EEG headset is connected should be as follows: _currentAction = 1 _currentPower = 0.0 Moreover it does not update the values in the class and it keeps returning the values of _currentAction = 0 and _currentPower = 0.0 Although that is normal because those are the values that the variable were declared in the beginning of the class. 连接EEG耳机后的正常值应如下所示:_currentAction = 1 _currentPower = 0.0此外,它不会更新类中的值,并且它会继续返回_currentAction = 0和_currentPower = 0.0的值虽然这是正常的,因为那些是在类的开头声明变量的值。

When i am using the Timer within the ActivityTraining class the values get updated just fine. 当我在ActivityTraining类中使用Timer时,值会更新得很好。

@Override
public void currentAction(int typeAction, float power) {
    // TODO Auto-generated method stub
    progressPower.setProgress((int)(power*100));
    _currentAction = typeAction;
    _currentPower  = power;
}

public void TrainingHomePage(View v) {
    Intent goingB = new Intent(this, MainActivity.class);
    setResult(RESULT_OK, goingB);
    finish();
}
}

This is my Service Class 这是我的服务类

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;

import com.example.assiotiscy.headshake.MentalCommand.ActivityTraining;

import java.util.Timer;
import java.util.TimerTask;


public class StartEndEpocService extends Service {

ActivityTraining activityTraining = new ActivityTraining();
Timer timeListenAction;

@Override
public void onCreate() {
    super.onCreate();
    //Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    thread();

}

private void thread () {
    timeListenAction =new Timer();
    timeListenAction.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run () {

                activityTraining.connect();

        }
    },0,20);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Toast.makeText(this, "Service Started...", Toast.LENGTH_SHORT).show();
    return START_NOT_STICKY;
}

@Override
public IBinder onBind(Intent intent) {
    // We don't provide binding, so return null
    return null;
}

@Override
public void onDestroy() {

    Toast.makeText(this, "Service Stopped...", Toast.LENGTH_SHORT).show();

    if (timeListenAction != null){
        timeListenAction.cancel();
        timeListenAction.purge();
    }
}
}

/ Finally this is my EngineConnector Class. / 最后这是我的EngineConnector类。 / /

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.emotiv.insight.IEdk;
import com.emotiv.insight.IEdkErrorCode;
import com.emotiv.insight.IEmoStateDLL;
import com.emotiv.insight.IEmoStateDLL.IEE_MentalCommandAction_t;
import com.emotiv.insight.MentalCommandDetection;
import com.emotiv.insight.MentalCommandDetection.IEE_MentalCommandTrainingControl_t;

import java.util.Timer;
import java.util.TimerTask;

public class EngineConnector {

public static Context context;
public static EngineConnector engineConnectInstance = null;
private Timer timer;
private TimerTask timerTask;

public boolean isConnected = false;
private int state;
private int userId = -1;
private boolean firstActionAdded = false;

public EngineInterface delegate;

public static void setContext(Context context) {
    EngineConnector.context = context;
}

public static EngineConnector shareInstance() {
    if (engineConnectInstance == null) {
        engineConnectInstance = new EngineConnector() {
        };
    }
    return engineConnectInstance;
}

public EngineConnector() {
    connectEngine();
}

private void connectEngine() {
    IEdk.IEE_EngineConnect(EngineConnector.context, "");
    timer = new Timer();
    timerTask();
    timer.schedule(timerTask, 0, 10);
}

Here is the connection of the EEG happens. 这是EEG发生的联系。 Also i have erased some code from this class unnecessary to see. 此外,我已经删除了这个类不必看的代码。

public void timerTask() {
    if (timerTask != null)
        return;
    timerTask = new TimerTask() {

        @Override
        public void run() {
            /*Connect device with Epoc Plus headset*/
            int numberDevice = IEdk.IEE_GetEpocPlusDeviceCount();
            //Log.d("EngineConnector: ", "numberDevice: " + numberDevice);
            if (numberDevice != 0) {
                if (!isConnected)
                    IEdk.IEE_ConnectEpocPlusDevice(0, false);
            }
            /*************************************/
            state = IEdk.IEE_EngineGetNextEvent();
            // Log.d("EngineConnector:- ", "State: " + state);
            if (state == IEdkErrorCode.EDK_OK.ToInt()) {
                int eventType = IEdk.IEE_EmoEngineEventGetType();
                //Log.d("EngineConnector", "eventType: " +eventType);
                switch (eventType) {
                    case TYPE_USER_ADD:
                        Log.e("connect", "User Added");

                        isConnected = true;

                        // TURNING OFF HEADSET WILL RESET ALL ACTIONS EVEN IF IN APP THAT ACTION STILL HAS "V" BESIDE
                        // userId is re-set by IEE_EmoEngineEventGetUserId();
                        userId = IEdk.IEE_EmoEngineEventGetUserId();
                        Log.e("UserID ", "" + userId);
                        hander.sendEmptyMessage(HANDLER_USER_ADD);

                        // This is the issue: by default activated action is Push (set by library so there is nothing we could do in our side
                        // We're going to get around this issue by replace Push with first action that user would choose in enableMentalcommandActions() method
                        long[] activeAction = MentalCommandDetection.IEE_MentalCommandGetActiveActions(userId);
                        Log.e("Default Action list: ", "0x" + Long.toBinaryString(activeAction[1]));
                        break;

                    case TYPE_USER_REMOVE:
                        Log.e("disconnect", "User Removed");
                        isConnected = false;
                        userId = -1;
                        hander.sendEmptyMessage(HANDLER_USER_REMOVE);
                        break;

                    case TYPE_EMOSTATE_UPDATE:
                        if (!isConnected)
                            break;
                        IEdk.IEE_EmoEngineEventGetEmoState();
                        hander.sendMessage(hander
                                .obtainMessage(HANDLER_ACTION_CURRENT));
                        break;

                    case TYPE_METACOMMAND_EVENT:
                        int type = MentalCommandDetection.IEE_MentalCommandEventGetType();
                        if (type == MentalCommandDetection.IEE_MentalCommandEvent_t.IEE_MentalCommandTrainingStarted
                                .getType()) {
                            Log.e("MentalCommand", "training started");
                            hander.sendEmptyMessage(HANDLER_TRAIN_STARTED);
                        } else if (type == MentalCommandDetection.IEE_MentalCommandEvent_t.IEE_MentalCommandTrainingSucceeded
                                .getType()) {
                            Log.e("MentalCommand", "training Succeeded");
                            hander.sendEmptyMessage(HANDLER_TRAIN_SUCCEED);
                        } else if (type == MentalCommandDetection.IEE_MentalCommandEvent_t.IEE_MentalCommandTrainingCompleted
                                .getType()) {
                            Log.e("MentalCommand", "training Completed");
                            hander.sendEmptyMessage(HANDLER_TRAIN_COMPLETED);
                        } else if (type == MentalCommandDetection.IEE_MentalCommandEvent_t.IEE_MentalCommandTrainingDataErased
                                .getType()) {
                            Log.e("MentalCommand", "training erased");
                            hander.sendEmptyMessage(HANDLER_TRAIN_ERASED);

                        } else if (type == MentalCommandDetection.IEE_MentalCommandEvent_t.IEE_MentalCommandTrainingFailed
                                .getType()) {
                            Log.e("MentalCommand", "training failed");
                            hander.sendEmptyMessage(HANDLER_TRAIN_FAILED);

                        } else if (type == MentalCommandDetection.IEE_MentalCommandEvent_t.IEE_MentalCommandTrainingRejected
                                .getType()) {
                            Log.e("MentalCommand", "training rejected");
                            hander.sendEmptyMessage(HANDLER_TRAIN_REJECTED);
                        } else if (type == MentalCommandDetection.IEE_MentalCommandEvent_t.IEE_MentalCommandTrainingReset
                                .getType()) {
                            Log.e("MentalCommand", "training Reset");
                            hander.sendEmptyMessage(HANDLER_TRAINED_RESET);
                        }
                        break;

                    default:
                        break;
                }
            }
        }
    };
}

Handler hander = new Handler() {
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case HANDLER_USER_ADD:
                if (delegate != null)
                    delegate.userAdd(userId);
                break;
            case HANDLER_USER_REMOVE:
                if (delegate != null)
                    delegate.userRemoved();
                break;

In the Handler_ACTION_CURRENT: is were the currentAction method refers from the Activity Training class 在Handler_ACTION_CURRENT中:currentAction方法是从Activity Training类引用的

            case HANDLER_ACTION_CURRENT:
                if (delegate != null)
                    delegate.currentAction(IEmoStateDLL
                            .IS_MentalCommandGetCurrentAction(), IEmoStateDLL
                            .IS_MentalCommandGetCurrentActionPower());
                break;
            case HANDLER_TRAIN_STARTED:
                if (delegate != null)
                    delegate.trainStarted();
                break;
            case HANDLER_TRAIN_SUCCEED:
                if (delegate != null)
                    delegate.trainSucceed();
                break;
            case HANDLER_TRAIN_FAILED:
                if (delegate != null)
                    delegate.trainFailed();
                break;
            case HANDLER_TRAIN_COMPLETED:
                if (delegate != null)
                    delegate.trainCompleted();
                break;
            case HANDLER_TRAIN_ERASED:
                if (delegate != null)
                    delegate.trainErased();
                break;
            case HANDLER_TRAIN_REJECTED:
                if (delegate != null)
                    delegate.trainRejected();
                break;
            case HANDLER_TRAINED_RESET:
                if (delegate != null)
                    delegate.trainReset();
                break;
            default:
                break;
        }
    }
};
}

I would like to know what the problem activating the timer from a service class might be. 我想知道从服务类激活计时器的问题可能是什么。

Thank you in advance 先感谢您

The problem to my Question was that since my ActivityTrainning class was already an activity and i was creating another object of it into the service class (ActivityTrainning activityTrainning = new ActivityTrainning()) then i had 2 different object of ActivityTrainning class. 我的问题的问题是,因为我的ActivityTrainning类已经是一个活动,我正在创建它的另一个对象到服务类(ActivityTrainning activityTrainning = new ActivityTrainning())然后我有两个不同的ActivityTrainning类对象。

A simple/good solution is the following: 一个简单/好的解决方案如下:

Activity A should have a variable 活动A应该有一个变量

static ActivityA activityA;

In onCreate state: 在onCreate状态:

activityA = this;

and add this method: 并添加此方法:

public static ActivityA getInstance(){
    return   activityA;
}

In activity B, call: 在活动B中,致电:

ActivityA.getInstance().myFunction(); //call myFunction using activityA

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM