1

I get some error. I really couldn't solve it today :( I get error after set ID data to lblID in FillData() method. It sets ID data properly but lblTitle and lblPrice always returns error like "Only the original thread that created a view hierarchy can touch its views" and program stops running.

Note : This is not my original code. I just minimized it to be more understandable and of course it gives same error like below code. Anyway in FillData() method i get data from wcf service and it returns data properly. i tried runonuithread but it didn't make any sense. Also if i write the code outside of the thread it doesn't fill the controls. Because it's originally gets the data from wcf service.

public class MainActivity extends AppCompatActivity {
LinearLayout lytData;
TextView lblTitle, lblID, lblPrice;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main); 

    lytData = (TextView)findViewById(R.id.lytNewData);
    lblID = (TextView)findViewById(R.id.lblID);
    lblTitle = (TextView)findViewById(R.id.lblTitle); 
    lblPrice = (TextView)findViewById(R.id.lblPrice); 
    new Thread() {
        public void run() {
            FillData();
        }
    }.start();

    lytData.setOnTouchListener(new OnCustomTouchListener (context) {
        @Override
        public void ToLeft() {
            new Thread() {
                public void run() {
                    FillData();
                }
            }.start();
        }

        @Override
        public void ToRight() {
            new Thread() {
                public void run() {
                    FillData();
                }
            }.start();
        }
    });
}

void FillData() {
   lblID.setText("aaa");
   lblTitle.setText("aaa");
   lblPrice.setText("aaa");
}
Levi Moreira
  • 11,917
  • 4
  • 32
  • 46
thrashead
  • 337
  • 1
  • 3
  • 16
  • If you need to change the UI in anyways from a Thread, you should use runonuithread() and perform your change inside the runnable you pass to it, i'll let you search for examples there is plenty of them on google. – N.K May 02 '18 at 14:45

1 Answers1

1

The problem is you're trying to update the UI in another thread, but the UI can only be updated in the UI thread. If you're simply updated the UI as your code is showing then you should remove the calls from FillData from the secondary thread, use a secondary thread if you're doing heavy loading inside FillData() otherwise you're better off updating the UI directly in the UI thread: So instead of doing this:

   new Thread() {
      public void run() {
         FillData();
         pd.cancel();
      }
    }.start();

Just simply call FillData(); outside the new thread.

You can also call runOnUiThread to bring the update to the ui thread:

getActivity().runOnUiThread(new Runnable() {
    public void run() {
        FillData();
    }
});

If your code inside FillData is mixed with heavy load code, then you can bring the runOnUiThread method to inside the FillData and move only the UI update code to runOnUiThread.

If you still want to keep your code the way it is you can "post" changes from your secondary thread like this:

viewElement.post(new Runnable() {
        public void run() {
            //update UI
        }
    });
}

viewElement is any UI element that extends from View.

Levi Moreira
  • 11,917
  • 4
  • 32
  • 46
  • downvoter please be constructive to the community and explain why you've downvoted – Levi Moreira May 02 '18 at 14:47
  • I first downvoted because your answer was "do your modification out of your thread" wich is useless, if the OP is doing that in a thread he must have reasons to do so, then you added the runonuithread() solution, wich is for me the good one so i removed my vote. – N.K May 02 '18 at 14:51
  • If you check the OP FillData(); method there's no reason for them to be doing that in another thread, they might have a reason of course, but from what they've posted that reason isn't clear therefore we can advise them to what would be the best approach. – Levi Moreira May 02 '18 at 14:53
  • It's not your job to extrapolate on what he may or may not need as it's not the question asked here, you can suggest of course, but this was also not a suggestion the way you wrote it, i won't go further as i believe you got my point and arguing on that is useless anyway. – N.K May 02 '18 at 14:56
  • yeah, I could argue more, but nah ;) – Levi Moreira May 02 '18 at 15:04
  • This is not my original code. I just minimized it to be more understandable and of course it gives same error like above example. Anyway in FillData() method i get data from wcf service and it returns data properly. i tried runonuithread but it didn't make any sense. Also if i write the code outside of the thread it doesn't fill the controls. Because it's originally gets the data from wcf service. – thrashead May 02 '18 at 15:16
  • 1
    Awwww I get it. Then you should put inside on runOnUiThread only the code that updates the UI or use the "post" approach. Sorry, I thought you only had the UI update code – Levi Moreira May 02 '18 at 15:18
  • i couldn't solve the problem but i added following codes after super.onCreate(savedInstanceState); step in onCreate method and now everything works fine. StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); – thrashead May 08 '18 at 12:02