I am trying to scroll to a substring in a string of 1000 lines. I notice a lag in the scroll and UI thread. So I thought to use a AsyncTask but as its executed I get the text but not scroll. Here is my code
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
SharedPreferences score = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
int chapter_number_bookmark = score.getInt("chapter_number", 89);
int verse_number_bookmark = score.getInt("verse_number", 1);
GoToFunction(chapter_number_bookmark,verse_number_bookmark);
return "Executed";
}
#Override
protected void onPostExecute(String result) {
Toast.makeText(getApplicationContext(), "Executed", Toast.LENGTH_SHORT).show();
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {}
}
The GoToFunction
public void GoToFunction(int chapter, int verse)
{
int scroll_amt;
final TextView shw = (TextView) findViewById(R.id.textViewTab);
SharedPreferences score = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
int chapter_number = chapter;
int verse_number = verse;
String verse_number_str = Integer.toString(verse_number);
SQLiteDatabase as = openOrCreateDatabase("/"+Environment.getExternalStorageDirectory().getPath()+"/tamil/verse", MODE_PRIVATE, null);
Cursor a = as.rawQuery("select * from verse"+chapter_number, null);
a.moveToFirst();
strTitle = a.getString(a.getColumnIndex("title"));
final String strContent_book = a.getString(a.getColumnIndex("content"));
int number = a.getInt(a.getColumnIndex("dialogues"));
tab.setText("\n\n "+strAthi+strTitle+"\n\n "+strVasa+number+"\n\n "+strContent_book);
final int offset_dot = strContent_book.indexOf(verse_number_str_dot);
final int offset_comma = strContent_book.indexOf(verse_number_str_comma);
a.close();
as.close();
if(offset_comma!=-1||offset_dot!=-1)
{
if(offset_comma==-1||(offset_dot<offset_comma))
{
try
{
Toast.makeText(getApplicationContext(), "Athiyayam : "+ chapter_number +" Verse : "+ verse_number, Toast.LENGTH_LONG).show();
**scroll(offset_dot); //Scroll function**
}
catch(Exception e)
{
Log.e("Scroll_comma", "Exception", e);
}
}
else
{
try
{
Toast.makeText(getApplicationContext(), "Athiyayam : "+ chapter_number +" Verse :"+ verse_number, Toast.LENGTH_LONG).show();
scroll(offset_comma);
}
catch(Exception e)
{
Log.e("Scroll", "Exception", e);
}
}
}
else
{
Toast.makeText(getApplicationContext(), "Not found", Toast.LENGTH_LONG).show();
}
}
Scroll Function
public void scroll(final int a)
{
final TextView shw = (TextView) findViewById(R.id.textViewTab);
try
{
mScroll.post(new Runnable() {
#Override
public void run() {
int y = shw.getLayout().getLineForOffset(a); // e.g. I want to scroll to line 40
int n = shw.getLayout().getLineTop(y);
mScroll.scrollTo(0, n);
}
});
}
catch(Exception e)
{
Log.e("scroll", "error", e);
}
}
Here I get the text. But the scroll function doesn't get executed. Also I want to do a spinner activity as the bookmark activity starts and finish as it ends which can be done in PreExecute and PostExecute
paste this code to your layout:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<!-- "your layout" -->
</ScrollView>
From your code you try to update main thread from doInBackground.
#Override
protected String doInBackground(String... params) {
....
GoToFunction(chapter_number_bookmark,verse_number_bookmark);
.....
}
You can't do that. I'm sure you get Exception in logcat. If you want to update anyways, do that through Handler
Lets say we have
private TextView m_txtLog;
private ScrollView m_sv;
So to scroll to last line should be something like:
m_sv.post(new Runnable() {
public void run() {
m_sv.scrollTo(0, m_txtLog.getHeight());
}
});
If you run it from Service or AsyncTask use Handler like:
static final int LOG_MSG = 1;
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
String txt;
switch (msg.what) {
case LOG_MSG:
txt = msg.obj.toString();
m_txtLog.append(txt);
m_sv.post(new Runnable() {
public void run() {
m_sv.scrollTo(0, m_txtLog.getHeight());
}
});
break;
default:
super.handleMessage(msg);
}
}
};
And now we can write from AsyncTask:
mHandler.sendMessage(mHandler.obtainMessage(LOG_MSG, "Agent started" + "\n\n"));
As you can see scrollTo wrapped by handler. By this way it will work.
(Tested)
Using asynctask for scrolling is really not necessary in this case. you can simply run the code in the main thread. It will work fine.
because if the user clicks the scrollview while scrolling by asyntask. there will be unexpected behaviour.
And also specify
1. android:hardwareAccelerated="true" in your activity manifest of scrollview
2. In addition to above step - scrollView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
This will use hardware acceleration to your scrollview for smooth scrolling.
Related
Actually what i am trying to do is that call an asyncTask several times inside a loop. So, first time the asyncTask will start immediately and from second time onwards, it will check whether the AsyncTask has been finished-if finished than again call it with different values.
Below is my code for the activity:
In onCreate()
btnUpload.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
count_response = 0;
newUploadWithSeparate();
}
});
The newUploadWithSeparate() method:
private void newUploadWithSeparate()
{
responseString_concat = "";
if(filePath.length > 0)
{
for(int i=0;i<filePath.length;i++)
{
count_response = i;
if(i == 0)
{
uploadAsync.execute(filePath[0]);
mHandler = new Handler() {
#Override public void handleMessage(Message msg) {
String s=(String)msg.obj;
Log.d("logIMEI","\n Response from Asynctask: " + s);
str_response_fromAsync = s;
}
};
}
else
{
uploadAsync.getStatus();
while(uploadAsync.getStatus() == AsyncTask.Status.RUNNING) // this while loop is just to keep the loop value waitining for finishing the asyncTask
{
int rx = 0;
}
if(uploadAsync.getStatus() != AsyncTask.Status.RUNNING)
{
if(uploadAsync.getStatus() == AsyncTask.Status.FINISHED)
{
if(str_response_fromAsync != "" || !str_response_fromAsync.equals("") || !str_response_fromAsync.isEmpty())
{
uploadAsync.execute(filePath[i]);
x = i;
mHandler = new Handler() {
#Override public void handleMessage(Message msg)
{
String s=(String)msg.obj;
Log.d("logIMEI","\n Response from Asynctask_" + x + ": " + s);
str_response_fromAsync = s;
}
};
}
}
}
}
}
}
}
And the asyncTask:
private class UploadFileToServer extends AsyncTask<String, Integer, String>
{
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
#Override
protected String doInBackground(String... params)
{
return uploadFile(params[0]);
}
private String uploadFile(String pr)
{
//inside here calling webservice and getting a response string as result.
MyWebsrvcClass mycls = new MyWebsrvcClass();
return responseString_concat = mycls.Call(xxx,yyy) ;
}
#Override
protected void onPostExecute(String result)
{
Log.d("logIMEI" , "\n count_response : "+ count_response + " fileprath_len : " + filePath.length);
Message msg=new Message();
msg.obj=result.toString();
mHandler.sendMessage(msg);
super.onPostExecute(result);
}
}
Now the problem is that its not working as expected. The first time when value of i is equals 0 than the AsyncTask gets called and after that its not getting called anymore.
Plus, when first time AsyncTask is called- its still not directly entering to onPostExecute(). When the loop ends totally and newUploadWithSeparate() method ends then the onPostExecute() is working.
Any solutions for this or any other way to do this job done for using AsyncTask inside loop?
You cannot call execute() on the same object more than once. So create a new instance of UploadFileToServer for each iteration of the loop.
My program crashs after doInBackground and doesn't come to onPostExecute.
My activity code's related parts are like this:
public static class News {
private String title;
private String content;
private Bitmap image;
public News(String nTitle, String nContent, Bitmap nImage){
title = nTitle;
content = nContent;
image = nImage;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_news);
final AsyncTask task = new DatabaseConnection(this, Method.GET_ALL_NEWS).execute();
try {
task.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public final void fillListView(List<News> news){
recentNews = news;
if(recentNews != null && !recentNews.isEmpty()){
((ListView)findViewById(R.id.lvNews)).setOnItemClickListener(this);
final int size = recentNews.size();
final String newsTitles[] = new String[size];
for(int i=0; i<size; ++i)
newsTitles[i] = recentNews.get(i).title;
((ListView)findViewById(R.id.lvNews)).setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, newsTitles));
}
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final News selectedNews = recentNews.get(position);
startActivity(new Intent(this, ANewsActivity.class)
.putExtra("title", selectedNews.title)
.putExtra("content", selectedNews.content)
.putExtra("image", BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)));
}
My AsyncTask code's related parts are like this:
public DatabaseConnection(Context nContext, Method nMethod){
method = nMethod;
context = nContext;
}
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(context);
progressDialog.setMessage(context.getString(R.string.database_connection_wait_message));
progressDialog.setTitle(R.string.database_connection_wait_title);
progressDialog.show();
}
#SuppressWarnings("incomplete-switch")
#Override
protected Void doInBackground(String... params) {
if(method != Method.NONE){
open();
try{
switch(method){
case GET_ALL_NEWS:
final ResultSet rs = conn.createStatement().executeQuery("select baslik, metin, resim from haberler");
news = new ArrayList<News>();
while(rs.next())
news.add(new News(rs.getString(1), rs.getString(2), BitmapFactory.decodeStream(rs.getBlob(3).getBinaryStream())));
break;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close();
}
}
return null;
}
#SuppressWarnings("incomplete-switch")
#Override
protected void onPostExecute(Void temp) {
if (progressDialog.isShowing()){
progressDialog.dismiss();
switch(method){
case GET_ALL_NEWS:
((NewsActivity)context).fillListView(news);
break;
}
method = Method.NONE;
}
}
I want UI thread waits until database operations finishes.
By the way there is no initialization problem at variables etc and database returns proper infos and my "news" variable is filled normally.
By the way again I realized it is WORKING on PHONE, STUCKS on EMULATOR interestingly (if I remove wait() method and its try-catch block on main thread code).
It's difficult to say what is crashing without the logcat output, but it would most likely be the main thread of the app because of the .wait() method you are calling in onCreate(). Your onCreate() cannot wait - it must initialize and exit, otherwise you are blocking the main thread of your app and defeating the purpose of the AsyncTask.
I am having Pull to Refresh https://github.com/chrisbanes/Android-PullToRefresh as given in this link. Everything works fine. But when my list item finishes, the loading icon and pull to refresh label is still visible. So, how to disable the scrolling when end of list reached?
mainListView.setOnRefreshListener(new OnRefreshListener() {
#Override
public void onRefresh(PullToRefreshBase refreshView) {
String total_bk_count = subCategory .getTotal_Book_Count();
count_of_book = Integer.parseInt(total_bk_count);
listCountt = mainbooksAdpater.getCount();
Log.e("StroreActivity","Total book count---====----====---+"+count_of_book);
Log.e("StroreActivity","list Count---====----====---+"+listCountt);
if(listCountt < count_of_book)
{
int bookCount = Common.getBookCountNumber();
Common.setBookCount(bookCount+1);
String refresh_Pull_Url = Common.getUrlForeCategoryBooks(id, Common.NUMBER_OF_BOOKS_PER_REQUEST);
Log.e("Rathis to Check url", Common.getUrlForeCategoryBooks(id, Common.NUMBER_OF_BOOKS_PER_REQUEST));
PulltoRefreshAsync onCatBooksTaskScroll = new PulltoRefreshAsync(Common.getUrlForeCategoryBooks(id, Common.NUMBER_OF_BOOKS_PER_REQUEST));
onCatBooksTaskScroll.execute();
Log.e("StroreActivity","Total Book count::" + book_count_no);
}
else
{
mainListView.setMode(Mode.DISABLED);
Toast.makeText(getApplicationContext(), "end of list", Toast.LENGTH_SHORT).show();
}
}
});
Asynctask Class:
public class PulltoRefreshAsync extends AsyncTask<Object,Object,Object> {
int refreshCount;
String refresh_URL;
public PulltoRefreshAsync(String url) {
refresh_URL = url;
}
/*
* PulltoRefreshAsync(int i) { refreshCount = i; }
*/
#Override
protected void onPreExecute() {
super.onPreExecute();
Log.e("Checking Purpose", refresh_URL);
}
#Override
protected String doInBackground(Object... arg0) {
JsonParserRefresh jp = new JsonParserRefresh();
Log.e("StroreActivity","Array to String::" + refresh_URL);
String jsonString = jp.getJSONFromURL(refresh_URL);
Log.e("StroreActivity","JsonString::" + jsonString);
jsonParseForCategoryBooksGridScroll(jsonString);
return null;
}
#Override
protected void onPostExecute(Object result) {
super.onPostExecute(result);
/*
* if(mProgressDialog.isShowing()) { mProgressDialog.dismiss(); }
*/
final MainBooksAdapter mainbooksAdpater = new MainBooksAdapter(
StoreActivity.this, R.layout.aa, mainBooksList);
final int old_pos = mainListView.getRefreshableView()
.getFirstVisiblePosition() + 1;
mainListView.setAdapter(mainbooksAdpater);
tvvisiblebookCount.setText("" + mainbooksAdpater.getCount());
/*if(listCountt < count_of_book)
{
mainListView.setMode(Mode.DISABLED);*/
mainListView.post(new Runnable() {
#Override
public void run() {
mainListView.onRefreshComplete();
mainListView.getRefreshableView().setSelection(old_pos);
}
});
//}
mainbooksAdpater.notifyDataSetChanged();
}
}
For other people who might have similat issue:
you don't have to implement it this way
mainListView.post(new Runnable() {
#Override
public void run() {
mainListView.onRefreshComplete();
mainListView.getRefreshableView().setSelection(old_pos);
}
});
instead do just like this :
mainListView.onRefreshComplete();
one more thing I noticed, instead of saving the old pos value to get back to it, why not just use notifyDataSetChanged it leaves the position of the list the way it is, just try not to re-instanciate you list, i.e: mainBooksList = ..., instead try this:
mainBooksList.clear();
mainBooksList.addAll(YOUR DATA);
adapter.notifyDataSetChanged();
voila!
hope this helps someone
I am currently creating a project that needs to have a simple async task to take care of a thread running behind the scenes. The user needs to login. I am using another class called PVAndroid Client that supplies useful methods and has an XML serializer form packets for me. I am completely new to working with threads or doing anything with servers, so this may be completely wrong or somewhat right.
I get the data the user entered: the ip address and port, their username (I split this into first and last name), their region they selected. I encrypt their password, and attempt to connect to the tcp using ip address and port number. I am trying to work in the async task but am kind of confused on what I should do. Can anyone guide me in the right direction and help me out?
Thank you I really appreciate it.
private TcpClient myTcpClient = null;
private UdpClient udpClient;
private static final String USERNAME_SHARED_PREFS = "username";
private static final String PASSWORD_SHARED_PREFS = "password";
private static final String IP_ADDRESS_SHARED_PREFS = "ipAddressPref";
private static final String PORT_SHARED_PREFS = "portNumberPref";
private String encryptedNameLoginActivity, encryptPassLoginActivity;
private EditText userText, passText;
private String getIpAddressSharedPrefs, getPortNumberPrefs;
private String getUserNameValue;
private String getPasswordValue;
private String fName, lName;
private SharedPreferences settings;
private Editor myEditor;
private boolean getCheckedRemember;
private boolean resultCheck = false;
private int portNum;
private Button submitButton;
private String userMACVARIABLE = "";
private String regionSelected, gridSelected;
private Spinner regSpinner, gridSpinner;
PVDCAndroidClient client;
private int userNum;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
client = new PVDCAndroidClient();
}
#Override
protected void onStart() {
super.onStart();
// Take care of getting user's login information:
submitButton = (Button) findViewById(R.id.submitButton);
userText = (EditText) findViewById(R.id.nameTextBox);
passText = (EditText) findViewById(R.id.passwordTextBox);
regSpinner = (Spinner) findViewById(R.id.regionSpinner);
// grid selected as well? sometime?
regSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View v,
int position, long rowId) {
regionSelected = regSpinner.getItemAtPosition(position)
.toString();
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
submitButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
settings = PreferenceManager
.getDefaultSharedPreferences(AndroidClientCompnt.this);
getIpAddressSharedPrefs = settings.getString(
IP_ADDRESS_SHARED_PREFS, "");
portNum = Integer.parseInt(settings.getString(
PORT_SHARED_PREFS, ""));
if (getIpAddressSharedPrefs.length() != 0 && portNum != 0) {
if (userText.length() != 0 && passText.length() != 0) {
try {
try {
// encrypting the user's password.
encryptPassLoginActivity = Secure.encrypt(passText
.toString());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// first connect attempt.
myTcpClient = new TcpClient();
myTcpClient.connect(getIpAddressSharedPrefs,
portNum);
// here is where I want to call Async to do login
// or do whatever else.
UploadTask task = new UploadTask();
task.execute();
} catch (Exception e) {
Toast.makeText(getApplicationContext(),
"Could not connect.", Toast.LENGTH_LONG)
.show();
e.printStackTrace();
}
}
}
}
});
}
private class UploadTask extends AsyncTask<String, Integer, Void>
{
#Override
protected void onPreExecute() {
Toast.makeText(getApplicationContext(), "Loading...",
Toast.LENGTH_LONG).show();
}
#Override
protected Void doInBackground(String... names) {
resultCheck = myTcpClient.connect(getIpAddressSharedPrefs,
portNum);
if (resultCheck == true) {
while (myTcpClient.getUserNum() < 0) {
// num set? session? with proxy server?
}
String[] firstAndLast;
String spcDelmt = " ";
firstAndLast = userText.toString().split(spcDelmt);
fName = firstAndLast[0];
lName = firstAndLast[1];
// set up the tcp client to sent the information to the
// server.
client.login(fName, lName, encryptPassLoginActivity,regionSelected, 128, 128, 20);
} else {
Toast.makeText(getApplicationContext(),
"Connection not successful", Toast.LENGTH_LONG)
.show();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
Toast.makeText(getApplicationContext(), "Connected",
Toast.LENGTH_LONG).show();
}
}
}
First
#Override
protected Void doInBackground(String...params) {
new Thread (new Runnable() {
// ...
}
}
Never do this again. There is no need to create new Thread in doInBackground method which actually running on background Thread. So remove it.
The advice to you is tricky because you need to read about Threads, work with Connection etc. So the best advice to you is to read some tutorials, examples of basic applications and read references. So you can start here:
Android TCP Client and Server Communication Programming–Illustrated with Example
I cannot see, where you are yoursing your Task, but I see that you are doing something weired inside doInBackground()! There is absolutely NO reason, to create your own Thread inside it.
remove that, and you could just use your Task like this:
UploadTask task = new UploadTask();
task.execute("someString", "anotherString", "addAsManyStringsYouNeed");
The docs from AsyncTask are very helpfull, too.
Hi and thank you for looking at my question.
I am an intermediate programmer in C but an Android newbie. I have been trying to get a chat programming working. Assuming everything else in the code below works perfectly. The one question I like to ask is when I try to setText() from a thread running, I get an exception above. I looked at many many websites and here too. Found many things, but I really do not understand. Please explain to me in the most simple way or offer me some simple fix if possible.
Thank you very much!!
public class chatter extends Activity {
private String name = "Unknown User";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final EditText msgToServer = (EditText) findViewById(R.id.msgBox);
final EditText chatFromServer = (EditText) findViewById(R.id.chatBox);
final Button MsgToServer = (Button) findViewById(R.id.sendButton);
Socket socket = null;
String ipAddress = "192.168.1.103";
try {
InetAddress serverAddr = InetAddress.getByName(ipAddress);
Socket socketMain = new Socket(serverAddr, 4444);
socket = socketMain;
} catch (IOException e) {
// TODO Auto-generated catch block
Log.e("TCP", "error", e);
}
final OutMsg outMsg = new OutMsg(socket);
Thread msgSenderThread = new Thread(outMsg);
msgSenderThread.start();
//chatFromServer.post(new InMsg(socket, chatFromServer));
Thread msgReceiverThread = new Thread(new InMsg(socket, chatFromServer));
msgReceiverThread.start();
MsgToServer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String msgToServerString;
msgToServerString = msgToServer.getText().toString();
outMsg.message = name + ": " + msgToServerString;
outMsg.readyToSend = true;
msgToServer.setText("");
}
});
}
public void updateResultsInUi (String msg)
{
final EditText chatFromServer = (EditText) findViewById(R.id.chatBox);
chatFromServer.setText(msg);
}
public class InMsg implements Runnable {
Socket socket;
EditText chatFromServer;
public InMsg(Socket socket, EditText chatFromServer)
{
this.socket = socket;
this.chatFromServer = chatFromServer;
}
public void run(){
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String str = "FIRSTMESSAGEFROMSERVER";
while (true)
{
if (str.equals("FIRSTMESSAGEFROMSERVER"))
str = in.readLine();
else
str = str + "\n" + in.readLine();
Log.e("TCP", "got the message: " + str);
//Here is where went wrong******************
chatFromServer.setText(str);
//******************************************
}
} catch (IOException e) {
// TODO Auto-generated catch block
Log.e("TCP", "error in receiving", e);
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.setNameMenu:
setname();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void populateChatBox (String msgFromS)
{
Log.e("TCP", "going in to popC");
final EditText textNameInput = (EditText) findViewById(R.id.nameBox);
Log.e("TCP", " popC");
textNameInput.setText(msgFromS);
Log.e("TCP", "going out from popC");
}
public void setname()
{
setContentView(R.layout.custom_dialog);
final EditText textNameInput = (EditText) findViewById(R.id.nameBox);
Button submitNameButton = (Button) findViewById(R.id.submitNameButton);
submitNameButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String nameinput = textNameInput.getText().toString();
if (!name.equals(""))
name = nameinput;
setContentView(R.layout.main);
}
});
}
}
In your run() method:
Message msg = new Message();
String textTochange = "text";
msg.obj = textTochange;
mHandler.sendMessage(msg);
Create the mHandler in your UI thread;
Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
String text = (String)msg.obj;
//call setText here
}
};
You are not on the UI thread when setting the text. You need to be on UI if you want to work on UI items. Create a message handler on the UI thread, post your messages to it and call setText from the handler on the UI thread.
you can do this whenever you are in a thread:
msgToServer.post(new Runnable() {
public void run() {
msgToServer.setText("your text here");
}
}
Your problem is that there are certain interactions that you can only do on the UI thread. This is one of them.
Looks like you might want to use AsyncTask
http://developer.android.com/reference/android/os/AsyncTask.html
Basically you could make your Runnable an AsyncTask instead and do the setText in onProgressUpdate, which gets run on the UIThread.
If you would like to use an AsyncTask to run in the background this is how I would do it:
public class UpdateTextProgress_Task extends AsyncTask<Void,String,Void> {
Socket socket;
EditText chatFromServer;
UpdateTextProgress_Task(EditText chatFromServer, Socket socket){
this.socket = socket;
this.chatFromServer = chatFromServer;
}
#Override
protected Void doInBackground(Void... params) {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String str = "FIRSTMESSAGEFROMSERVER";
while(true){
if (str.equals("FIRSTMESSAGEFROMSERVER")){
str = in.readLine();
}
else{
str = str + "\n" + in.readLine();
}
Log.e("TCP", "got the message: " + str);
publishProgress(str); // calls the onProgressUpdate method
}catch (IOException e) {
Log.e("UpdateTextProgress", e.getMessage());
}
return null;
}
#Override
protected void onProgressUpdate(String... progress) {
chatFromServer.setText(progress[0]); //now we are on the UI thread so we can update our EditText
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Log.e("UpdateTextProgress", "Finished");
}
}
To execute the code:
UpdateTextProgress_Task task = new UpdateTextProgress_Task(chatFromServer,socket);
task.execute();