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 .
Related
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();
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();
}
});
If I have this background worker file in my android application and it gets data from my database how can I pass the string 'result' to another class?
The background worker connects to my server and then using php it connects to a database.
public class BackgroundWorker extends AsyncTask<String,Void,String> {
Context context;
AlertDialog alertDialog;
BackgroundWorker (Context ctx) {
context = ctx;
}
#Override
public String doInBackground(String... params) {
String type = params[0];
String specials_url = "";
if(type.equals("venue click")) {
try {
//String user_name = params[1];
URL url = new URL(specials_url);
HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
httpURLConnection.setDoInput(true);
OutputStream outputStream = httpURLConnection.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
// String post_data = URLEncoder.encode("user_name","UTF-8")+"="+URLEncoder.encode(user_name,"UTF-8");
// bufferedWriter.write(post_data);
bufferedWriter.flush();
bufferedWriter.close();
outputStream.close();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"iso-8859-1"));
String result="";
String line="";
while((line = bufferedReader.readLine())!= null) {
result += line;
}
bufferedReader.close();
inputStream.close();
httpURLConnection.disconnect();
return result;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPreExecute() {
alertDialog = new AlertDialog.Builder(context).create();
alertDialog.setTitle("Info");
}
#Override
protected void onPostExecute(String result) {
alertDialog.setMessage(result);
alertDialog.show();
// String temp = "login success";
// if (result.equals(temp)) {
// Intent intent = new Intent(context, Register.class);
// context.startActivity(intent);
// }
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}
You need a listener. This will allow you to notify back when the AsyncTask is done.
Define the listener by creating an interface, like this:
public interface IListener
{
void onCompletedTask(String result);
}
On the task store a reference to the listener.
private IListener mListener;
// Pass the reference to the constructor.
public BackgroundWorker(IListener listener)
{
mListener = listener;
}
Then you notify the listener like this.
#Override
protected void onPostExecute(String result)
{
mListener.onCompletedTask(result);
}
Best way to get a callback from background thread is to use interfaces as a callback from AsyncTask for example:
create an interface that can be called in onPostExecute()
public interface ResponseCallback {
void onRespond(String result);
}
and before calling asynckTask define it like this:
ResponseCallback cpk = new ResponseCallback() {
#Override
public void onRespond(String result) {
//code to be done after calling it from onPostExecute
}
};
and pass cpk to the constructor of of the asynckTask and call it in onPostExecute like that:
if(cpk!=null){
cpk.onRespond(result);
}
of course you can modify the signature of the interface to what ever you want.
I am having trouble with my code where i have my Activity which i use to call google api's and retrieve jsons, deserialize them and use it's Polylines to draw on the map.
The problem is that getMapAsync() which sends the callback for onMapReady() (which is used to create the map) is executed immediately after executing my Async Tasks which retrieves necessary data to create the map.
How can i make this happen without stopping the UI thread? I tried doing this calling .execute.get() which freeze the UI thread. But if i do that, i won't be able to use ProgressDialog to inform the users about the delay for fetching data from the servers, which they will be exposed to a frozen UI until the task is complete. How can i do this?
public class RouteAssistantActivity extends Activity implements OnMapReadyCallback{
public GoogleMapsDirectionsResponse dirRes;
public GoogleMapsDistanceResponse disRes;
public String jsonString;
private String mapsAPIKey;
private String directionsBaseURL;
private String distanceBaseURL;
MapFragment mapFragment;
private ProgressDialog progress;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ra_route_assisstant);
mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.ra_map);
progress = new ProgressDialog(RouteAssistantActivity.this);
progress.setTitle("Please Wait");
progress.setMessage("Retrieving Data from the Server");
progress.setIndeterminate(true);
try {
ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
if (appInfo.metaData != null) {
mapsAPIKey = appInfo.metaData.getString("com.google.android.maps.v2.API_KEY");
directionsBaseURL = appInfo.metaData.getString("com.google.android.maps.directions.baseURL");
distanceBaseURL = appInfo.metaData.getString("com.google.android.maps.distance.baseURL");
}
} catch (PackageManager.NameNotFoundException e) {
Log.e("Meta Error", "Meta Data not found. Please check the Manifest and the Meta Data Package Names");
e.printStackTrace();
}
//Test
String directionsURL = directionsBaseURL+"origin=6.948109,79.858191&destination=6.910176,79.894347&key="+mapsAPIKey;
String distanceURL = distanceBaseURL+"units=metric&origins=6.948109,79.858191&destinations=6.910176,79.894347&key="+mapsAPIKey;
Log.e("CA Debug","URL : " + directionsURL);
Log.e("CA Debug","URL : " + distanceURL);
new configurationSyncTask().execute(distanceURL,"distance");
new configurationSyncTask().execute(directionsURL, "direction");
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
LatLng rajagiriya = new LatLng(6.910176, 79.894347);
String points = dirRes.getRoutes().get(0).getOverviewPolyline();
List<LatLng> list = PolyUtil.decode(points);
googleMap.setMyLocationEnabled(true);
googleMap.getUiSettings().setRotateGesturesEnabled(true);
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(rajagiriya, 13));
googleMap.addMarker(new MarkerOptions()
.title("Rajagiriya")
.snippet("My Place")
.position(rajagiriya));
googleMap.addPolyline(new PolylineOptions()
.geodesic(false)
.addAll(list)
.color(Color.RED)
.width(25));
}
private class configurationSyncTask extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
progress.show();
}
#Override
protected String doInBackground(String... params) {
String url = params[0];
String type = params[1];
Log.d("CA Debug", getClass().getSimpleName() + " --> Real URL : " + url);
Log.d("CA Debug", getClass().getSimpleName() + " --> doInBackground requesting content");
jsonString = requestContent(url);
// if the output is null, stop the current task
if (jsonString == null) {
Log.d("CA Debug", getClass().getSimpleName() + " --> Stopping Async Task");
this.cancel(true);
Log.d("CA Debug", getClass().getSimpleName() + " --> Async Task Stopped");
}
return type;
}
#Override
protected void onPostExecute(String types) {
if (types.equalsIgnoreCase("distance")) {
disRes = GMapsDistanceResponseJSONDeserializer.deserialize(jsonString);
} if (types.equalsIgnoreCase("directions")) {
dirRes = GMapsDirectionsResponseJSONDeserializer.deserialize(jsonString);
}
progress.dismiss();
}
}
public String requestContent(String url) {
Log.d("CA Debug",getClass().getSimpleName()+" --> URL : "+url);
try {
URL urlObj = new URL(url);
HttpsURLConnection con = (HttpsURLConnection) urlObj.openConnection();
con.setChunkedStreamingMode(0);
con.setRequestMethod("GET");
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null,null, new SecureRandom());
con.setSSLSocketFactory(sc.getSocketFactory());
InputStream clientResponse;
String jsonString;
int status = con.getResponseCode();
if(status >= HttpURLConnection.HTTP_BAD_REQUEST){
Log.d("CA Debug", getClass().getSimpleName()+" --> Bad Request");
jsonString = null;
} else {
Log.d("CA Debug", getClass().getSimpleName()+" --> converting Stream To String");
clientResponse = con.getInputStream();
jsonString = convertStreamToString(clientResponse);
}
Log.d("CA Debug", getClass().getSimpleName()+" --> JSON STRING : " + jsonString);
return jsonString;
} catch (IOException | NoSuchAlgorithmException | KeyManagementException e) {
Log.d("CA Debug", getClass().getSimpleName()+" --> Error when creating an Input Stream");
e.printStackTrace();
}
return null;
}
public String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
} finally {
try {
is.close();
} catch (IOException e) {
}
}
return sb.toString();
}
}
Quick and somewhat dirty solution would be to execute both AsyncTasks on a single AsyncTask and then on its onPostExecute code invoke getMapAsync. this way you will be sure your tasks finished before you dealing with map's readyness.
Firstly, run tasks after onMapReady because you will get rid of
concern of ready map.
Your async tasks are not parallel, they working on background but second one will be executed after first one completed, check this link
Move some parts of onMapReady to onPostExecute, something like below
Move
#Override
protected void onPostExecute(String types) {
if (types.equalsIgnoreCase("distance")) {
disRes = GMapsDistanceResponseJSONDeserializer.deserialize(jsonString);
}if (types.equalsIgnoreCase("directions")) {
dirRes = GMapsDirectionsResponseJSONDeserializer.deserialize(jsonString);
String points = dirRes.getRoutes().get(0).getOverviewPolyline();
List<LatLng> list = PolyUtil.decode(points);
googleMap.addPolyline(new PolylineOptions()
.geodesic(false)
.addAll(list)
.color(Color.RED)
.width(25)
);
}
}
AsyncTask.SERIAL_EXECUTOR is used to force AsyncTask to execute in Serial Fashion.
More over for your case a little trick will do the job.
Create call back for same AsyncTask and pass different parameters to differentiate the functions.
Now in the second call back initiate mapFragment.getMapAsync(this);
public class MainFragment ...
{
DataDownloader dataDownloader;
int processCount=1;
void initiateProcessFirst(){
new DataDownloader(this,processCount ).execute();
}
public void initiateSecondProcess(){
processCount++;
new DataDownloader(this,processCount ).execute();
}
public void secondProcessCompleted(){
mapFragment.getMapAsync(this);
}
}
AsyncTask Logic goes like the below
public class DataDownloader extends AsyncTask<Void,Void,Boolean> {
MainFragment context;
int processCount;
public DataDownloader(MainFragment context ,int processCount){
this.context=context;
this.processCount=processCount;
}
#Override
protected Boolean doInBackground(Void... params) {
boolean status=false;
// Do logic according to the Process Count
return status;
}
#Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
if(processCount==1)
context.initiateSecondProcess();
else
context.secondProcessCompleted();
}
}
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.