я получаю сообщение «Только исходный поток, создавший иерархию представлений, может касаться своих представлений». после второго запуска

#android #multithreading #android-listview

#Android #многопоточность #android-listview

Вопрос:

у меня очень серьезная проблема, я прочитал весь пост о многопоточности в Android, но по-прежнему появляется ошибка famuse. но я вошел после второго запуска того же потока для exmaple «thGetDevice» из исходного кода;

надеюсь, вы сможете мне помочь .. спасибо..

Я получаю /** определение переменной*/ Флажок cbBlueTooth; Адаптер BluetoothAdapter mBluetoothAdapter; AlertDialog.Диалоговое окно Builder; ArrayAdapter mArrayAdapter; ListView MainListView; ProgressBar prProgressbar; Thread thGetDevices; Thread thClearDevices; Handler обработчик;

 /** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    /* Initial Handler */
    handler=new Handler() {
        @SuppressWarnings("unchecked")
        @Override
        public void handleMessage(final Message msg) {

                /******************************
                 * 
                 * this line cuse to the trouble
                 */

                BlueQuickActivity.this.runOnUiThread(new Runnable() {

                    public void run() {
                        // TODO Auto-generated method stub
                        prProgressbar.incrementProgressBy(msg.arg1);
                        mArrayAdapter = (ArrayAdapter<String>)msg.obj;
                        mArrayAdapter.notifyDataSetInvalidated();
                        mArrayAdapter.notifyDataSetChanged();
                        prProgressbar.setVisibility(ProgressBar.INVISIBLE);
                        setListAdapter(mArrayAdapter);
                    }
                });
        }
      };


    /* Set Finalization true */
   // System.runFinalizersOnExit(true);
    setContentView(R.layout.main);


    /* ListView Definition */
    TextView tvHeader = new TextView(this);
    MainListView =  this.getListView();
    MainListView.addHeaderView(tvHeader);
    mArrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
    //mArrayAdapter.setNotifyOnChange(true);
    prProgressbar = (ProgressBar)findViewById(R.id.progressBar1);
    prProgressbar.setVisibility(ProgressBar.INVISIBLE);


    /* Get Bluetooth driver */
    cbBlueTooth = (CheckBox)findViewById(R.id.cbTurnBlueTooth);
    dialog = new AlertDialog.Builder(this);

    /* initializing Bluetooth adapter **/
    mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
    if (mBluetoothAdapter == null) {
        // Device does not support Bluetooth
        /*ShowNotifMessage("Sorry..", "You Don't have Bluetooth Driver");
        try {
            Thread.sleep(3000);
            android.os.Process.killProcess(android.os.Process.myPid());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }*/

    }

    // Initial the thGetDeviceThread and thClearDevices
    //initGetDevicesThread();
    //initClearDevicesThread();

    /*Listener for Checkbox*/
    cbBlueTooth.setOnCheckedChangeListener(new OnCheckedChangeListener() {

        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            // TODO Auto-generated method stub

             if (isChecked amp;amp; !mBluetoothAdapter.isEnabled()) {
                 prProgressbar.setVisibility(ProgressBar.VISIBLE);
                 buttonView.setEnabled(false);
                 BluetoothAdapter.getDefaultAdapter().enable();
                 initGetDevicesThread();
                 buttonView.setEnabled(true);
                }
             else if (!isChecked amp;amp; mBluetoothAdapter.isEnabled()) {
                 prProgressbar.setVisibility(ProgressBar.VISIBLE);
                 buttonView.setEnabled(false);
                 BluetoothAdapter.getDefaultAdapter().disable();
                 initClearDevicesThread();  
                 buttonView.setEnabled(true);
                }
             else
             {
                 prProgressbar.setVisibility(ProgressBar.VISIBLE);
                 buttonView.setEnabled(false);
                 BluetoothAdapter.getDefaultAdapter().enable();
                 initGetDevicesThread();
                 buttonView.setEnabled(true);
             }
        }
    });
}

/** Gets all paird devices and put them in the Listview */
private void initGetDevicesThread()
{
 thGetDevices = new Thread(new Runnable() {

        public void run() {
            Message msg = handler.obtainMessage();
            msg.what = 1;
            msg.obj = getDeviceList();
            handler.sendMessage(msg);
        }

    });

 (thGetDevices).start();

}

/** clear all paird devices and put them in the Listview */
private void initClearDevicesThread()
{
 thClearDevices = new Thread(new Runnable() {

        public void run() {
            Message msg = handler.obtainMessage();
            msg.what = 2;
            msg.obj = clearListOfDevices();
            handler.sendMessage(msg);
        }

    });

 (thClearDevices).start();

}

public ArrayAdapter<String> getDeviceList()
{
    while(BluetoothAdapter.getDefaultAdapter().getState() != BluetoothAdapter.STATE_ON);
    Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();

    // If there are paired devices
    if (pairedDevices.size() > 0) {
        // Loop through paired devices
        for (BluetoothDevice device : pairedDevices) {
            // Add the name and address to an array adapter to show in a ListView
            mArrayAdapter.add(device.getName());
        }
    }

    return mArrayAdapter;
}

private ArrayAdapter<String> clearListOfDevices()
{
    while(BluetoothAdapter.getDefaultAdapter().getState() != BluetoothAdapter.STATE_OFF);
    mArrayAdapter = new ArrayAdapter<String>(MainListView.getContext(), android.R.layout.simple_list_item_1);
    return mArrayAdapter;
}



//** */
private void ShowNotifMessage(String strTitle,String strMsg)
{
    dialog.setTitle(strTitle);
    dialog.setMessage(strMsg);
    dialog.show();
}
  

}

Ответ №1:

Вы не можете обновить пользовательский интерфейс из потока, отличного от пользовательского интерфейса. Для этого вы должны использовать runOnUiThread() . Поместите свой код для обновления пользовательского интерфейса внутри runOnUiThread() .

 Activity_name.this.runOnUiThread(new Runnable() {

            public void run() {
                prProgressbar.incrementProgressBy(msg.arg1);
        mArrayAdapter = (ArrayAdapter<String>)msg.obj;
        mArrayAdapter.notifyDataSetInvalidated();
        mArrayAdapter.notifyDataSetChanged();
        prProgressbar.setVisibility(ProgressBar.INVISIBLE);
        setListAdapter(mArrayAdapter);
    }
        });
  

Комментарии:

1. обработчик, предполагающий отправить сообщение в UIThread, запускает очередь.

2. да, но вы пытаетесь обновить пользовательский интерфейс из потока, отличного от пользовательского интерфейса, установив адаптер для List setListAdapter(mArrayAdapter); . Это можно сделать только из потока пользовательского интерфейса. Итак, для этого вам нужно поместить эту часть внутрь runOnUiThread().

3. не работает… ‘code’ BlueQuickActivity.this.runOnUiThread(new Runnable() { public void run() { // Автоматически сгенерированная заглушка метода TODO setListAdapter(mArrayAdapter); } });’code’ спасибо любым способом

4. с какой проблемой вы сталкиваетесь?

5. 11-12 14:36:07.205: E/AndroidRuntime (21408): android.view.ViewRoot$CalledFromWrongThreadException: Только исходный поток, создавший иерархию представлений, может касаться своих представлений. но только во второй раз, когда вызывается thead…

Ответ №2:

Попробуйте использовать обработчик, подобный приведенному ниже

 Handler viewUpdateHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case 1:
                ~~~~your code~~~
                break;
            }
        }
    };
  

Комментарии:

1. объявите его как int msgToSend = 1;