This is driving me crazy. I was forced by android to create a thread so that it did not lock the main thread. Now I want to get that data back to the ListView Adapter that I created. I googled the error but it is not clear how to adapt this code. Thanks to any help you can give
public class Detail extends AppCompatActivity
{
ListView list;
ListViewAdapter listviewadapter;
List<CData> lstData = new ArrayList<CData>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listview_main);
list = (ListView) findViewById(R.id.listview);
listviewadapter = new ListViewAdapter(this, R.layout.listview_item, lstData);
list.setAdapter(listviewadapter);
// these work
CData d1 = new CData("test1", "data1", "a");
lstData.add(d1);
CData d2 = new CData("test2", "data2", "a");
lstData.add(d2);
Thread thread = new Thread(new Runnable(){
#Override
public void run(){
try {
URL url = new URL("http://testserver.com/getdata.php");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
InputStream inStream = null;
inStream = connection.getInputStream();
BufferedReader bReader = new BufferedReader(new InputStreamReader(inStream));
String temp, response = "";
while ((temp = bReader.readLine()) != null) {
response += temp;
}
// this is not working
CData d4 = new CData("test3", response, "a");
lstData.add(d4);
listviewadapter.notifyDataSetChanged();
// this prints out to the log window
System.out.println("---------------yesss--------" + response);
// this does not work
listviewadapter.notifyDataSetChanged();
// this does not work either
listviewadapter.clear();
listviewadapter.addAll(lstData);
listviewadapter.notifyDataSetChanged();
}
catch(Exception ex)
{
System.out.println("generic ex" + ex.toString());
}
}
});
thread.start();
CData d3 = new CData("test4", "data4", "a");
lstData.add(d3);
Error
CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
First of all don't use threads for network request.
Either use AsyncTask or Http libraries like Retrofit or volley etc libraries. Because they provide batter implementation of Http web request and handling mechanism.
From your code this can be solution
runOnUiThread(new Runnable() {
#Override
public void run() {
//UI updates
// this does not work either
listviewadapter.clear();
listviewadapter.addAll(lstData);
listviewadapter.notifyDataSetChanged();
}
});
Make your d4 variable global.
After your catch statement :-
runOnUiThread(new Runnable() {
#Override
public void run() {
lstData.add(d4);
listviewadapter.clear();
listviewadapter.addAll(lstData);
listviewadapter.notifyDataSetChanged();
}
}
you should update UI on UI thread like this
runOnUiThread(new Runnable() {
#Override
public void run() {
//stuff that updates ui
listviewadapter.clear();
listviewadapter.addAll(lstData);
listviewadapter.notifyDataSetChanged();
}
});
Related
I have two arrays (groupIDs, groupNames) I need to fill with variables received from certain URLs which is done inside a subclass extending AsyncTask as otherwise, it results in a NetworkOnMainThreadException error. Problem is I need to make sure those two arrays are filled before initRecyclerView(); is called in UI thread.
How can I make sure my code waits for async to finish before executing initRecyclerView();?
public class GroupPage extends AppCompatActivity {
private static final String TAG = "RecycleViewAdapter";
private ArrayList<Integer> groupIDs = new ArrayList<>();
private ArrayList<String> groupNames = new ArrayList<>();
private class groupPageConnect extends AsyncTask {
#Override
protected Object doInBackground(Object... arg0) {
try{
System.out.println("Testing 1 - Send Http GET request");
getGroups();
} catch (Exception e) {
System.err.println("Oops!");
e.printStackTrace();
}
return null;
}
}
private void getGroups() throws Exception{
String url = "http://obsco.me/obsco/api/v1.0/users/12345671";
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", "Mozilla/5.0");
int responseCode = con.getResponseCode();
System.out.println("Response Code for IDs: " + responseCode);
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
JSONObject reader = new JSONObject(response.toString());
JSONArray allContainingArray = reader.getJSONArray("users");
JSONObject userJSON = (JSONObject) allContainingArray.get(0);
JSONArray temp = userJSON.getJSONArray("groups");
Log.d(TAG, "initializing");
for (int x = 0; x < temp.length(); x++){
//System.out.println(temp.getJSONObject(x).getInt("id"));
groupIDs.add(temp.getJSONObject(x).getInt("id"));
System.out.println(groupIDs.size() );
System.out.println(groupIDs.get(x));
//groupNames.add("Dummy");
url = "http://obsco.me/obsco/api/v1.0/groupname/" + groupIDs.get(x);
System.out.println("ar1");
obj = new URL(url);
System.out.println("ar2");
con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", "Mozilla/5.0");
responseCode = con.getResponseCode();
System.out.println("Response Code for IDs: " + responseCode);
in = new BufferedReader(new InputStreamReader(con.getInputStream()));
response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
reader = new JSONObject(response.toString());
System.out.println(reader.getString("name"));
groupNames.add(reader.getString("name"));
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_group_page);
Log.d(TAG, "started");
try {
groupPageInit();
} catch (Exception e) {
e.printStackTrace();
}
}
private void groupPageInit() throws Exception{
new groupPageConnect().execute();
initRecyclerView();
}
private void initRecyclerView(){
Log.d(TAG, "initializingRecyclerView");
RecyclerView recyclerView = findViewById(R.id.recycler_view);
RecyclerViewAdapter adapter = new RecyclerViewAdapter( this, groupIDs, groupNames);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager( new LinearLayoutManager( this));
}
}
After getGroups() you can use runOnUiThread().
Example:
getGroups();
runOnUiThread(new Runnable() {
#Override
public void run() {
// Logic that you want to execute on main thread
initRecyclerView();
}
});
Call initRecyclerView() method on onPostExecute(result)method. An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 4 steps, called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.onPostExecute(Result) invoked on the UI thread after the background computation finishes.
private class groupPageConnect extends AsyncTask<Object,void,String> {
#Override
protected Object doInBackground(Object... arg0) {
//put your code here
}
#Override
protected void onPostExecute(String result) {
//call what you want to update
initRecyclerView();
// dismiss progress dialog here
// into onPostExecute() but that is upto you
}
#Override
protected void onPreExecute() {
// start progress dialog here
}
#Override
protected void onProgressUpdate(Void... values) {
// progress update here}
}
}
You can override onPostExecute.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.task goes through 4 steps
Please pay attention that loading of data from network through AsyncTask may be cause of memory leaks .
So I have been trying to fetch JSON objects in my Django REST Framework API. The algorithm for this called within the onPostExecute of my AsyncTask but it seems that it is not being called as when I debug it doesn't go there. Nothing fatal seems to be appearing in my logcat except that there is nothing in my array that should contain data from the DRF API.
I have two activities that calls my AsyncTask from my WSAdapter class. One is for logging in and the other is for listing all posts once logged in.
The logging in works just fine but listing the posts doesn't.
My code is below:
Posts.java
public class Posts extends AppCompatActivity {
TextView postsSect;
Button postsDoneBtn;
WSAdapter.SendAPIRequests PostsHelper;
StringBuilder postsBuffer = new StringBuilder();
#Override
protected void onResume(){
super.onResume();
PostsDetails postDetailsHelper = new PostsDetails();
postDetailsHelper.ListPosts();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_posts);
PostsDetails postDetailsHelper = new PostsDetails();
postsDoneBtn = (Button) findViewById(R.id.PostsDoneButton);
postDetailsHelper.callPostDetails("192.168.0.18:8000/api");
postDetailsHelper.ListPosts();
postDetailsHelper.postDetailsCalled('n');
postsDoneBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(Posts.this, MainActivity.class));
}
});
}
public class PostsDetails {
//String post_title, post_content;
ArrayList<Integer> post_id = new ArrayList<Integer>();
ArrayList<String> post_title = new ArrayList<String>();
ArrayList<String> post_content = new ArrayList<String>();
boolean isPDCalled;
// sets if Post details are called
boolean postDetailsCalled(char called) {
if (called == 'y'){
return true;
}
return false;
}
// checks if postsDetails functions are called for AsyncTask
boolean getIsPDCalled(){
return isPDCalled;
}
// calls the execute for AsyncTask
private void callPostDetails(String theurl){
PostsHelper = new WSAdapter.SendAPIRequests();
// sets if post details are called
postDetailsCalled('y');
// executes AsyncTask
PostsHelper.execute(theurl);
}
// sets values for the posts arrays
public void setPost(int p_id, String p_title, String p_content) {
post_id.add(p_id);
post_title.add(p_title);
post_content.add(p_content);
}
// Lists the posts from the database
public void ListPosts() {
/////////// add functionality if a post was deleted and was clicked
postsSect = (TextView) findViewById(R.id.PostsSection);
postsSect.setText(post_title.get(post_title.size()) + "\n");
for (int i = post_id.size() - 1; i > 0; i--)
{
postsSect.append(post_title.get(i));
}
}
}
}
WSAdapter.java
public class WSAdapter extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
static public class SendAPIRequests extends AsyncTask<String, String, String> {
// Add a pre-execute thing
#Override
protected String doInBackground(String... params) {
Log.e("TAG", params[0]);
Log.e("TAG", params[1]);
String data = "";
HttpURLConnection httpURLConnection = null;
try {
// Sets up connection to the URL (params[0] from .execute in "login")
httpURLConnection = (HttpURLConnection) new URL(params[0]).openConnection();
// Sets the request method for the URL
httpURLConnection.setRequestMethod("POST");
// Tells the URL that I am sending a POST request body
httpURLConnection.setDoOutput(true);
// To write primitive Java data types to an output stream in a portable way
DataOutputStream wr = new DataOutputStream(httpURLConnection.getOutputStream());
// Writes out a byte to the underlying output stream of the data posted from .execute function
wr.writeBytes("postData=" + params[1]);
// Flushes the postData to the output stream
wr.flush();
wr.close();
// Representing the input stream
InputStream in = httpURLConnection.getInputStream();
// Preparing input stream bytes to be decoded to charset
InputStreamReader inputStreamReader = new InputStreamReader(in);
StringBuilder dataBuffer = new StringBuilder();
// Translates input stream bytes to charset
int inputStreamData = inputStreamReader.read();
while (inputStreamData != -1) {
char current = (char) inputStreamData;
inputStreamData = inputStreamReader.read();
// concatenates data characters from input stream
dataBuffer.append(current);
}
data = dataBuffer.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
// Disconnects socket after using
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
Log.e("TAG", data);
return data;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// expecting a response code fro my server upon receiving the POST data
Log.e("TAG", result);
Posts.PostsDetails postsHelper = new Posts().new PostsDetails();
// For posts
try {
if (postsHelper.getIsPDCalled()){
JSONObject pJObj = new JSONObject(result);
JSONArray pJObjArray = pJObj.getJSONArray("posts");
for (int i = 0; i < pJObjArray.length(); i++) {
JSONObject pJObj_data = pJObjArray.getJSONObject(i);
postsHelper.setPost(pJObj_data.getInt("id"), "post_title", "post_content");
}
}
} catch (JSONException e) {
//Toast.makeText(JSonActivity.this, e.toString(), Toast.LENGTH_LONG).show();
Log.d("Json","Exception = "+e.toString());
}
}
}
}
Login.java
public class Login extends AppCompatActivity {
Button LoginButton;
EditText uUserName, uPassWord;
WSAdapter.SendAPIRequests AuthHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
//SetupHomeBtn = (ImageButton) findViewById(R.id.SetupHomeBtn);
LoginButton = (Button) findViewById(R.id.LoginButton);
uUserName = (EditText) findViewById(R.id.LoginUserBox);
uPassWord = (EditText) findViewById(R.id.LoginPassBox);
//AuthHelper = new WSAdapter().new SendDeviceDetails();
// Moves user to the main page after validation
LoginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// gets the username and password from the EditText
String strUserName = uUserName.getText().toString();
String strPassWord = uPassWord.getText().toString();
// API url duh
String APIUrl = "http://192.168.0.18:8000/token-auth/";
// If the user is authenticated, then transfer to the MainActivity page
if (APIAuthentication(strUserName, strPassWord, APIUrl)){
startActivity(new Intent(Login.this, Posts.class));
}
}
});
}
private boolean APIAuthentication(String un, String pw, String url){
// when it wasn't static -> AuthHelper = new WSAdapter().new SendAPIRequests();
AuthHelper = new WSAdapter.SendAPIRequests();
JSONObject postData = new JSONObject();
try {
// Attempt to input info to the Django API
postData.put("username", un);
postData.put("password", pw);
// Putting the data to be posted in the Django API
AuthHelper.execute(url, postData.toString());
return true;
} catch (JSONException e) {
e.printStackTrace();
}
return false;
}
}
I was expecting my onPostExecute to be called and store data for my posts arrays.
Okay this is a nice example of async tasks. The problem here is when you call an async task then the code below will continue to execute even when the async task hasn't finished. So what happens in your case:
You fetch the posts and then ask to display them on the exact moment that the async function is still getting the posts. So of course the List is empty.
You can fix this by using the await keyword. This keyword stops the rest of your code from executing until that line has been executed. So change:
postDetailsHelper.callPostDetails("192.168.0.18:8000/api");
to:
await postDetailsHelper.callPostDetails("192.168.0.18:8000/api");
Now the reason that the login does work is because you call that function within the if statement. If you would store the return value of that function in a boolean first then it wouldn't work either.
I'm making app which get server data from mvc spring server.
If client login success in main Activity, app try to get data from server, and use list view show data in next activity.
It works clear in first login, but when I turn back on main Activity, and try login again, next activity doesn't show anything.
I used logs to find problem and I found that when client login again, next activity's onCreate() and onResume() works too fast. My app uses thread and get data from server, logs says after onCreate and onResume works and my thread get data from server.
So this is my problem
1 App uses thread to get data from server
2 First try works but after thread is too late than onResume and onCreate in activity
3 should I have to make thread more fast? or use flags or something make onCreate and onResume works after thread works end? or does my code have problems?
This is my activity which show data from server
public class ServerListActivity extends AppCompatActivity {
public static ArrayList<ServerListItem> serverListItemArrayList;
public static ArrayList<ServerListItem> scrollEventServerListItemList;
public TextView serverListInfoTextView;
private ProgressBar progressBar;
private boolean lockListView;
private boolean isThisLastItemVisibleFlag;
private ServerListViewAdapter serverListViewAdapter;
private int currentPageNum;
public Handler msgHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
lockListView = false; // scroll event
currentPageNum = 0; // scroll event
isThisLastItemVisibleFlag = false; // scroll event
scrollEventServerListItemList = new ArrayList<>();
serverListItemArrayList = new ArrayList<>();
msgHandler = new Handler();
super.onCreate(savedInstanceState);
ServerListManager serverListManager = new ServerListManager(msgHandler);
serverListManager.getServerList();
setContentView(R.layout.activity_server_list);
ImageButton turnBackBtn = findViewById(R.id.turn_back_btn);
serverListInfoTextView = findViewById(R.id.server_list_Info);
ListView serverListView = findViewById(R.id.server_list_view);
progressBar = findViewById(R.id.progressBar);
serverListViewAdapter = new ServerListViewAdapter(scrollEventServerListItemList, R.layout.server_list_item, getApplicationContext());
serverListView.setAdapter(serverListViewAdapter);
progressBar.setVisibility(View.GONE);
serverListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);
System.out.println(serverListItemArrayList.size());
setServerListInfo(serverListItemArrayList);
and this is my thread
public class ServerListManager {
private final static int SERVER_PROBLEM = 666;
private Handler handler;
public ServerListManager(Handler handler) {
this.handler = handler;
}
public void getServerList() {
new Thread(new Runnable() {
#Override
public void run() {
HttpURLConnection connection = null;
StringBuilder stringBuffer = new StringBuilder();
try {
URL url = new URL("my ip and blah balh");
connection = (HttpURLConnection) url.openConnection();
} catch (IOException e) {
e.printStackTrace();
}
if (connection != null) {
connection.setConnectTimeout(5000);
connection.setUseCaches(false);
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
String line = bufferedReader.readLine();
if (!"".equals(line)) {
stringBuffer.append(line);
Log.i("ServerListManager", stringBuffer.toString());
}
setServerListItem(stringBuffer.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
private void setServerListItem(String dataFromServer) {
Log.i("ServerListManager", "setServerListItem() works ");
ArrayList<ServerListItem> serverListItems = new ArrayList<>();
JsonParser jsonParser = new JsonParser();
JsonObject jsonObjectFirst = (JsonObject) jsonParser.parse(dataFromServer);
if (!String.valueOf(jsonObjectFirst.get("status")).equals("\"200\"")) {
Message message = new Message();
message.what = SERVER_PROBLEM;
handler.sendMessage(message);
} else {
String serverListJsonVersion = String.valueOf(jsonObjectFirst.get("serverModelList"));
JsonArray jsonArray = (JsonArray) jsonParser.parse(serverListJsonVersion);
Gson gson = new Gson();
for (JsonElement jsonElement : jsonArray) {
ServerListItem serverListItem = gson.fromJson(jsonElement, ServerListItem.class);
serverListItems.add(serverListItem);
}
ServerListActivity.serverListItemArrayList = serverListItems;
}
}
You can try using AsyncTask
private class AsyncCaller extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
//this method will be running on UI thread
//can call progress bar here to show loading process
}
#Override
protected Void doInBackground(Void... params) {
//this method will be running on background thread
//so don't update UI from here
//do your long running http tasks here,
//you don't want to pass argument and you
//can access the parent class' variable url over here
// call your server data here
serverListManager.getServerList();
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
//this method will be running on UI thread
//Show the result obtained from doInBackground
//this executed after doInBackground so after you get data from doInBackground
//you can set your adapter here
}
}
Then you can execute AsyncTask like this
new AsyncCaller().execute();
I am getting this exception
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Below is the code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_page2);
lv = (ListView) findViewById(R.id.list_view);
btnNew = (Button)findViewById(R.id.btnAddNew);
btnNew.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent moveToNewUser = new Intent(getApplication(),ExecutiveInfo2.class);
moveToNewUser.putExtra("ClickType","1");
startActivity(moveToNewUser);
}
});
new Connection2().execute();
// Listview Data
}
private class Connection2 extends AsyncTask {
#Override
protected Object doInBackground(Object... arg0) {
test2();
return null;
}
#Override
protected void onPostExecute(Object s) {
super.onPostExecute(s);
}
}
public void test2() {
HttpURLConnection connection = null;
try {
sharedpreferences = getSharedPreferences("MyPrefs", this.MODE_PRIVATE);
String storedUUID = sharedpreferences.getString("UUID", "");
String url2= "http://crm.xqicai.com/sales/getExecutiveInfo?UUID="+storedUUID;
//String url = "http://crm.xqicai.com/sales/login";
URL postUrl = new URL(url2);
connection = (HttpURLConnection) postUrl.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("GET");
connection.setUseCaches(false);
connection.setInstanceFollowRedirects(true);
connection.setRequestProperty("Content-Type", "application/json");
connection.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));// 设置编ç �,å�¦åˆ™ä¸æ–‡ä¹±ç �
while (true) {
String str = reader.readLine();
if (str == null) {
break;
}
System.out.println(str);
JSONObject mainObject = new JSONObject(str);
Status = mainObject.getString("status");
int j=0;
if(Status.equals("0"))
{
JSONObject uniObject = mainObject.getJSONObject("data");
JSONArray a = uniObject.getJSONArray("data");
for (int i = 0; i < a.length(); i++) {
JSONObject json_obj = a.getJSONObject(i);
String demo = json_obj.getString("realName");
fetchedNames[j]= demo;
j++;
}
// Adding items to listview
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, fetchedNames);
lv.setAdapter(adapter);
}
else
{
JSONObject mainObject2 = new JSONObject(str);
errorMsg = mainObject2.getString("msg");
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), errorMsg, Toast.LENGTH_SHORT).show();
}
});
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
I'm only a beginner, so please forgive me for asking possibly a stupid question.
What line is giving the error? The problem is that you update a view created in the main thread, in your AsyncTask (a different thread). You should update this view in the onPostExecute of your AsyncTask (this is done in your main thread). I don't see immediately where you update the view.
EDIT:
Your problem should be solved if you put these two lines
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, fetchedNames);
lv.setAdapter(adapter);
below this line:
lv = (ListView) findViewById(R.id.list_view);
or in the:
protected void onPostExecute(Object s)
Test that:
ListView lv...
lv.post(new Runnable() {
#Override
public void run() {
//Update UI;
lv.setAdapter(...);
}
})
you can try use Handler with sendEmptyMessage() inside asynctask to pass by exception.
ex.
Handler mHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message inputMessage) {
// Adding items to listview
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, fetchedNames);
lv.setAdapter(adapter);
}
});
note for code bellow:
//call mHandler.sendEmpyMessage() in asynctask:
if(Status.equals("0"))
{
JSONObject uniObject = mainObject.getJSONObject("data");
JSONArray a = uniObject.getJSONArray("data");
for (int i = 0; i < a.length(); i++) {
JSONObject json_obj = a.getJSONObject(i);
String demo = json_obj.getString("realName");
fetchedNames[j]= demo;
j++;
}
// Adding items to listview
mHandler.sendEmpyMessage(0); //0 or any number is identify code from you want use to check with every action
I have a little issue about a little thing I don't understand.
It's just a simple request: how do I display an xml I just got in a thread?
There is my method postData to get the xml, I make it display in a log.v as you can see below in the code, but I can't display it to a TextView out of the thread.
public class RecupXml_Activity extends Activity {
TextView campagne;
String user = "toto";
String password = "tata";
String theCampagneXml;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);
campagne = (TextView) findViewById(R.id.campagneTest);
postData(user, password);
}
public void postData(final String login, final String password) {
Thread background = new Thread(new Runnable() {
URL url;
String buffer;
String theCampagneXml = null;
#Override
public void run() {
try {
URLConnection urlConnection;
String body = "login=" + URLEncoder.encode(login, "UTF-8") + "&password=" + URLEncoder.encode(password, "UTF-8");
url = new URL("http://3pi.tf/apps/sms/");
urlConnection = url.openConnection();
((HttpURLConnection) urlConnection).setRequestMethod("POST");
urlConnection.setDoOutput(true);
urlConnection.setDoInput(true);
urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
urlConnection.setRequestProperty("Content-Length", "" + body.length());
OutputStreamWriter writer = null;
BufferedReader reader = null;
writer = new OutputStreamWriter(urlConnection.getOutputStream());
writer.write(body);
writer.flush();
reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
while ((buffer = reader.readLine()) != null) {
theCampagneXml = buffer;
}
Log.v("test", "xml = " + theCampagneXml);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
} catch (IOException e) {
// TODO Auto-generated catch block
}
campagne.post(new Runnable() {
#Override
public void run() {
campagne.setText("salut voici ta campagne : " + theCampagneXml);
}
});
}
});
background.start();
}
}
It appears in my Log but not in the TextView:/ I have a white empty Activity.
The problem is that you call postData() on UI-tread, meaning that the method also returns theCampagneXml on UI-thread, while your network operation goes on a worker thread. The following code with some changes and additions fixes the problem:
public class MainActivity extends Activity {
TextView campagne;
String user = "toto";
String password = "tata";
String theCampagneXml; // new
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
campagne = (TextView) findViewById(R.id.text);
postData(user, password); // new
}
public void postData(final String login, final String password) { // note: the return type has been changed
Thread background = new Thread(new Runnable() {
URL url;
String buffer;
String theCampagneXml = null; // new
#Override
public void run() {
try {
// no changes here but declaring `theCampagneXml` as class member
}
campagne.post(new Runnable() {
#Override
public void run() {
campagne.setText("hello, here is your XML : "+ theCampagneXml);
}
});
}
});
background.start();
}
}
Once the network operation is done and theCampagneXml is initialized, use post() for the TextView campagne that runs on UI-thread.
Additional info can be found in Processes and Threads.