The way the app behaves when I try to run it is black screen -> back to main activity.
Here's my code:
public class ResultsActivity extends AppCompatActivity {
final TextView textView = findViewById(R.id.textView);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_results);
new NetworkTask().execute();
}
public void backToMain(View v) {
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
private class NetworkTask extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
final String image = getExternalCacheDir() + "/image.jpeg";
File file = new File(image);
try {
final MediaType MEDIA_TYPE_JPEG = MediaType.parse("image/jpeg");
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("images", "image.jpeg",
RequestBody.create(file, MEDIA_TYPE_JPEG))
.addFormDataPart("organs", "leaf")
.build();
Request request = new Request.Builder()
.url("insert url here")
.post(requestBody)
.build();
OkHttpClient client = new OkHttpClient();
Response response = client.newCall(request).execute();
String result = response.body().string();
return result;
} catch(IOException e) {
e.printStackTrace();
return "error";
}
}
#Override
protected void onPostExecute(String result) {
if(result.equals("error")) {
textView.setText("error");
} else {
textView.setText(result);
}
}
}
I am fairly certain that the post request works just fine because I have tested it using:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
So, maybe the issue lies with the way I put it in AsyncTask.
As Carl says, I put this line of code on doInBackground method. My problem has been solved.
#Override
protected String doInBackground(String... params) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
//...
}
Using AsyncTask is necessary in some cases such as sending a queue of images.
Related
I'm writing a simple Android app to get a JSON array into RecyclerView with AsyncTask. I know that I can use libraries as Retrofit or OKHTTP, but this time I tried to write the connection IO from scratch. The connection succeeded and data has been parsed and added to ArrayList. I do all of these in doInBackground(), and in onPostExecute() I just call notifyDataSetChanged() to the adapter, but it didn't work. I tried several ways such as move setAdapter() to onPostExecute(), or move all the AsyncTask to Adapter class and they didn't help anything. Can someone tell me what I miss, if I cannot fix it in 2 or 3 days, I think I will use Retrofit instead.
This is my Main class, I think the bug is only here, but if you need to see my adapter please leave a comment, thanks a lot.
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
ProgressDialog progressDialog;
String apiUrl;
Gson gson;
List<User> userList;
UserAdapter userAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recycle_view);
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
apiUrl = "https://lebavui.github.io/jsons/users.json";
gson = new Gson();
userList = new ArrayList<>();
userAdapter = new UserAdapter(userList, MainActivity.this);
recyclerView.setAdapter(userAdapter);
DataGetter dataGetter = new DataGetter();
dataGetter.execute();
}
private class DataGetter extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage("Loading...");
progressDialog.setCancelable(false);
progressDialog.show();
}
#Override
protected Void doInBackground(Void... voids) {
StringBuilder response = new StringBuilder();
URL url;
HttpsURLConnection urlConnection = null;
try {
url = new URL(apiUrl);
urlConnection = (HttpsURLConnection) url.openConnection();
InputStream is = urlConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
int data = isr.read();
while (data != -1) {
response.append((char) data);
data = isr.read();
}
JSONArray jsonArray = new JSONArray(response.toString());
for (int i = 0; i < jsonArray.length(); i++) {
userList.add(gson.fromJson(jsonArray.getJSONObject(i).toString(), User.class));
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return null;
}
#SuppressLint("NotifyDataSetChanged")
#Override
protected void onPostExecute(Void unused) {
super.onPostExecute(unused);
progressDialog.dismiss();
userAdapter.notifyDataSetChanged();
}
}
}
As mentioned in comments you should be using something other than depreciated classes. Below is an example of using runnable, simply add your parser and adapter
This should be moved to android view model.
public class MainActivity extends AppCompatActivity {
private final String LOG_TAG = MainActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.v(LOG_TAG, "on Create");
String apiUrl = "https://lebavui.github.io/jsons/users.json";
getUsers(apiUrl);
}
//return interface
public interface Completion{
void onCompletion(List<String> list);
}
//calls a function which call Completion.onCompletion interface off of main thread
public void getUsers(String apiUrl){
getAsyncData(apiUrl, this::setListDataOnMain);
}
//bring back to main thread
//This should be in Android View model for application context instead of this.getMainLooper
private void setListDataOnMain(List<String> list){
Handler mainHandler = new Handler(this.getMainLooper());
Runnable myRunnable = () -> {
//Set local object "list" to your global variable
//Then notify adapter change
//only logging here as example
Log.v(LOG_TAG, "List: " + list);
};
mainHandler.post(myRunnable);
}
//make async
public void getAsyncData(String apiUrl, Completion completion) {
Runnable runnable = () -> {
List<String> userList = makeRequest(apiUrl);
completion.onCompletion(userList);
};
Thread thread = new Thread(runnable);
thread.start();
}
//This is not async calling this func from main thread will crash
public List<String> makeRequest(String apiUrl ) {
List<String> userList = new ArrayList<>();
StringBuilder response = new StringBuilder();
URL url;
HttpsURLConnection urlConnection = null;
try {
url = new URL(apiUrl);
urlConnection = (HttpsURLConnection) url.openConnection();
InputStream is = urlConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
int data = isr.read();
while (data != -1) {
response.append((char) data);
data = isr.read();
}
JSONArray jsonArray = new JSONArray(response.toString());
for (int i = 0; i < jsonArray.length(); i++) {
//your json parsing here
userList.add(String.valueOf(i));
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return userList;
}
}
I think the DataGetter class need to executed first than you can set adapter
i test this code and it works
#SuppressLint("NotifyDataSetChanged")
#Override
protected void onPostExecute(Void unused) {
super.onPostExecute(unused);
progressDialog.dismiss();
userAdapter = new UserAdapter(userList, MainActivity.this);
recyclerView.setAdapter(userAdapter);
}
This is the code I am Using.
public class MainActivity extends AppCompatActivity {
public ArrayList<String> ImageUrls = new ArrayList<>();
public ArrayList<String> ImageNames = new ArrayList<>();
public ArrayList<String> ImageDesc = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initImages();
}
private void initImages(){
final OkHttpClient client = new OkHttpClient();
final Request request = new Request.Builder()
.url("http://url.in/wp-json/wp/v2/posts?_embed")
.build();
#SuppressLint("StaticFieldLeak") AsyncTask<Void, Void, String> asyncTask = new AsyncTask<Void, Void, String>() {
private static final String TAG = "SlideFragment";
#Override
protected String doInBackground(Void... params) {
try {
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) {
Log.d(TAG, "doInBackground: REsponse Un Successfull - 56");
return null;
}
String Data = response.body().string();
response.body().close();
return Data;
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "doInBackground: Exceptione on line63");
return null;
}
}
#Override
protected void onPostExecute(String Data) {
super.onPostExecute(Data);
if (Data != null) {
Log.d(TAG, "onPostExecute: line72");
try {
JSONArray json = new JSONArray(Data);
for (int i = 0; i < json.length(); i++) {
JSONObject post = json.getJSONObject(i);
String title = post.getJSONObject("title").getString("rendered");
String description = post.getJSONObject("content").getString("rendered");
String imgURL = post.getJSONObject("_embedded").getJSONArray("wp:featuredmedia").getJSONObject(0).getJSONObject("media_details").getString("file");
String imagUrl = "http://url.in/wp-content/uploads/" + imgURL;
ImageNames.add(title);
ImageDesc.add(description);
ImageUrls.add(imagUrl);
Log.d(TAG, "onPostExecute: " + ImageNames);
}
}catch(JSONException j){
j.printStackTrace();
Log.d(TAG, "onPostExecute: on line 121");
}
}
}
};
asyncTask.execute();
initRecycler();
}
private void initRecycler(){
RecyclerViewPager mRecyclerView = (RecyclerViewPager) findViewById(R.id.list);
// setLayoutManager like normal RecyclerView, you do not need to change any thing.
LinearLayoutManager layout = new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false);
mRecyclerView.setLayoutManager(layout);
//set adapter
//You just need to implement ViewPageAdapter by yourself like a normal RecyclerView.Adpater.
RecyclerViewAdapter adapter = new RecyclerViewAdapter(ImageUrls, ImageNames, ImageDesc, this);
mRecyclerView.setAdapter(adapter);
}
}
I have run the same code with local data i..e the ArrayList with hardcoded data. It works. But If I try with API data It shows Nothing. I have checked the ArrayList with logging. It is fine.
I don't know where I am Wrong.
UPDATE
Thanks to #sonhnLab. In the code I have removed initRecycler(); from initImages(); and added to onPostExecute();. That worked.
Due to the asynchronous nature of Asynctask, the following line: "initRecycler();" doesn't necessarily gets called after completion of the network request hence no content. Remember, any task that depends on the asynchronous response needs to be implemented inside response method, in this case inside onPostExecute().
With the Help of sonhnlab I have successfully got the desired output.
I have made this initRecycler(); call into onPostExecute() call. so when the information is ready from the API call it initiates the Recycler.
I have Updating the Code in the question.
You should call initRecyler() onPostExecute when async task is completed
I'm working on a basic android app that makes a POST with HttpURLConnection. I want to return the response Message from my Web API.
My MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView mTextView = findViewById(R.id.textView);
AsyncExample asyncExample = new AsyncExample();
asyncExample.execute();
mTextView.setText(asyncExample.getResponseMsg());
}
}
My AsyncExample.java
class AsyncExample extends AsyncTask<Void, Void, Void> {
private HttpURLConnection con;
private String responseMsg;
protected void onPreExecute() {
responseMsg = "empty message";
}
#Override
protected Void doInBackground(Void... params) {
String urlParameters = "param1=data1";
byte[] postData = urlParameters.getBytes(Charset.forName("UTF-8"));
int postDataLength = postData.length;
String request = "http://192.168.1.30:6262";
URL url = null;
try {
url = new URL(request);
con = (HttpURLConnection) url.openConnection();
con.setDoOutput(true);
con.setInstanceFollowRedirects(false);
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
con.setRequestProperty("charset", "utf-8");
con.setRequestProperty("Content-Length", Integer.toString(postDataLength));
responseMsg = con.getResponseMessage();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public String getResponseMsg() {
return responseMsg;
}
}
After running the app, i get empty message in my TextView. Why it is not getting updated my doInBackground? Even if con.getResponseMessage() is null, it should be updated?
The problem is that your AsyncTask is executed asynchronously, while you try to retrieve the value immediately. You need to implement this a little bit differently. Either leverage the API of AsyncTask, sine it posts callbacks for your on the UI thread. You can update your TextView directly in your AsyncTask
class MyAwesomeAsyncTask extends AsyncTask<Void, Void, String> {
#Override
protected void onPreExecute() {
myTextView.setText("progress started");
}
#Override
protected String doInBackground(final Void... voids) {
String s = amazingCallToBackend();
return s;
}
#Override
protected void onPostExecute(final String s) {
myTextView.setText(s);
}
}
Or if you just want the value, you can pass a Callback to your async task that will deliver the value to you, something like that
interface Callback {
void onValueReceived(String value);
void onFailure();
}
class MyAwesomeAsyncTask extends AsyncTask<Void, Void, String> {
private Callback callback;
MyAwesomeAsyncTask(final Callback callback) {
this.callback = callback;
}
#Override
protected String doInBackground(final Void... voids) {
String s = amazingCallToBackend();
return s;
}
#Override
protected void onPostExecute(final String s) {
callback.onValueReceived(s);
}
}
Here's how you create it
Callback callback = new Callback() {
#Override
public void onValueReceived(final String value) {
}
#Override
public void onFailure() {
}
};
new MyAwesomeAsyncTask(callback).execute();
However, be careful because if for some reason your activity/fragment is gone/finished before your AsyncTask is done, this can cause memory leaks.
A quick Google search will tell you all you want about AsyncTask leaking memory :)
Your doInBackground method take time to execute. you are immediately calling mTextView.setText(asyncExample.getResponseMsg()); but asynctask has been not been finished yet. You need to wait until your doInBackground finish and then call that setText you can do it in onPostExecute method.
AsyncTask has 3 default method
1. On preexecute
2. Do in background
3. On post execute
post execute:
The response got from the doinbackground is in the post execute.
Here we can process the result . use the runnable method to update text view ui
Override the onPostExecute() Method to return the text. In the Main Activity create a method to update the TextView after completing the execution of the Async Task. It is coming blank as because the Main Thread is not paused its executing and setting the text View but the Async task has not yet finished executing and hence the String is empty. So wait for the Async Task to finish before setting the text view.
String str_result= new RunInBackGround().execute().get();
Refer to this for more information.
You can do it in a number of ways. I'd try to suggest you a way that would require negligible amount of changes to your existing code.
Declare the mTextView as a Global variable, Override onPostExecute() method inside your AsyncExample and update mTextView inside that onPostExecute() method with the value passed to it by the doInBackground() method [here, notice that responseMsg is returned at the end of doInBackground() ground which is caught as a String value (result) by the onPostExecute() method]. However, I also think that its a good idea to Override your onPreExecute() method.
In order to do so, your MainActivity.java should be as follows:
public class MainActivity extends AppCompatActivity {
TextView mTextView; //declare mTextView outside the onCreate() method as a Global String variable.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = findViewById(R.id.textView);
AsyncExample asyncExample = new AsyncExample();
asyncExample.execute();
}
}
Please make your asynctask an inner-class of the same activity and edit it as follows:
class AsyncExample extends AsyncTask<Void, Void, Void> {
private HttpURLConnection con;
private String responseMsg;
#Override // Its a good practice to Override the onPreExecute() method.
protected void onPreExecute() {
responseMsg = "empty message";
}
#Override
protected String doInBackground(String... params) {
String urlParameters = "param1=data1";
byte[] postData = urlParameters.getBytes(Charset.forName("UTF-8"));
int postDataLength = postData.length;
String request = "http://192.168.1.30:6262";
URL url = null;
try {
url = new URL(request);
con = (HttpURLConnection) url.openConnection();
con.setDoOutput(true);
con.setInstanceFollowRedirects(false);
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
con.setRequestProperty("charset", "utf-8");
con.setRequestProperty("Content-Length", Integer.toString(postDataLength));
responseMsg = con.getResponseMessage();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return responseMsg; //return the value of responseMsg
}
#Override //override onPostExecute() method
protected void onPostExecute(String result) { //receive the value to be set to mTextView which is returned by the doInBackground() method.
mTextView.setText(result);
}
}
Try to do like this
MainActivity
public class MainActivity extends AppCompatActivity {
TextView mTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = findViewById(R.id.textView);
AsyncExample asyncExample = new AsyncExample(this,mTextView);
asyncExample.execute();
}
}
AsyncTask
class AsyncExample extends AsyncTask<Void, Void, Void> {
private HttpURLConnection con;
private String responseMsg;
private MainActivity mContext;
TextView mTextView;
public AsyncExample (MainActivity context, TextView textView) {
mContext = context;
mTextView = textView;
}
protected void onPreExecute() {
responseMsg = "empty message";
}
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
#Override
protected Void doInBackground(Void... params) {
String urlParameters = "param1=data1";
byte[] postData = urlParameters.getBytes(StandardCharsets.UTF_8);
int postDataLength = postData.length;
String request = "http://192.168.1.30:6262";
URL url = null;
try {
url = new URL(request);
con = (HttpURLConnection) url.openConnection();
con.setDoOutput(true);
con.setInstanceFollowRedirects(false);
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
con.setRequestProperty("charset", "utf-8");
con.setRequestProperty("Content-Length", Integer.toString(postDataLength));
responseMsg = con.getResponseMessage();
mContext.runOnUiThread(new Runnable() {
#Override
public void run() {
mTextView.setText(responseMsg);
}
});
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public String getResponseMsg() {
return responseMsg;
}
}
I am currently trying to make an android app that basically downloads strings from a url. But I want to make it object oriented. My mainActivity gets string from webService which downloads string when button is clicked. But I am not good at interfaces and callbacks. What should I do to make this code run?
public class MainActivity extends Activity implements WebServiceInterface{
private TextView textView;
private Button readWebPage;
private WebService service;
private WebServiceInterface webServiceInterface;
private String response;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.TextView01);
readWebPage = (Button) findViewById(R.id.readWebpage);
service = new WebService();
readWebPage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
service.execute(new String[]{"http://google.com/"});
onSuccess(response);
}
});
}
#Override
public void onSuccess(String response) {
textView.setText(Html.fromHtml(response));
}
#Override
public void onFail(Exception ex) {
textView.setText(ex.getLocalizedMessage());
}
}
public class WebService extends AsyncTask<String, Void, String> {
private WebServiceInterface webServiceInterface;
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(
new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
webServiceInterface.onSuccess(response);
} catch (Exception e) {
e.printStackTrace();
webServiceInterface.onFail(e);
}
}
return response;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
}
public interface WebServiceInterface {
void onSuccess(String response);
void onFail(Exception ex);
}
you need to create one public method for set webServiceInterface in WebService class like
public setWebServiceInterface (WebServiceInterface listener)
{
this.webServiceInterface =listener;
}
in MainActivity activity call this method and pass argument this
service.setWebServiceInterface (this);
in WebService class in onPostExecute Method call
webServiceInterface.onSuccess(s);
Add WebService (WebServiceInterface webServiceInterface) in your AsyncTask as a constructor.
service = new WebService(new WebServiceInterface (){
void onSuccess(String response){
//do your stuff
}
void onFail(Exception ex){
//do your stuff
}
});
and in your asynctask
public class WebService extends AsyncTask<String, Void, String> {
public WebService (WebServiceInterface webServiceInterface){
this.webinterface= webServiceInterface;
}
private WebServiceInterface webinterface;
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(
new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
webinterface.onSuccess(response);
} catch (Exception e) {
e.printStackTrace();
webinterface.onFail(e);
}
}
return response;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
}
I have found the problem, it is because of runOnUiThread is missing.
I have an android activity that executes an Asynchronous Okhttp call, when the activity is loaded ( called from the onStart method as getActiveRequests()).
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button btLogout;
UserLocalStore userLocalStore;
String username;
String userEmail;
String recentAppName;
String recentRequestTime;
String isExpired;
TelephonyManager telephonyManager;
OkHttpClient client;
TextView tvRecentAppName, tvRecentRequestTime, tvIsExpired;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
userLocalStore = new UserLocalStore(this);
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
TextView tvUserName = (TextView) findViewById(R.id.userName);
TextView tvUserEmail = (TextView) findViewById(R.id.userEmail);
tvRecentAppName = (TextView) findViewById(R.id.recentAppName);
tvRecentRequestTime = (TextView) findViewById(R.id.recentRequestTime);
tvIsExpired = (TextView) findViewById(R.id.isExpired);
client = new OkHttpClient();
username = userLocalStore.getLoggedInUser().name;
userEmail = userLocalStore.getLoggedInUser().email;
tvUserEmail.setText(userEmail);
tvUserName.setText(username);
btLogout = (Button) findViewById(R.id.btLogout);
btLogout.setOnClickListener(this);
}
#Override
protected void onStart() {
super.onStart();
if(authenticateUser() == true){
getActiveRequests();
}else{
startActivity(new Intent(this, LoginActivity.class));
}
}
What I want to do Is update the UI once the Http call has been made using the SetText methods. Here is my call, implemented in the GetActiveRequests() method.
client.newCall(request)
.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
String hello = "failed call";
}
#Override
public void onResponse(Call call, Response response) throws IOException {
final String responseData = response.body().string();
if (responseData != null) {
Gson gson = new Gson();
JsonElement element = gson.fromJson(responseData, JsonElement.class);
JsonObject jsonObject = element.getAsJsonObject();
final AccessRequest request = gson.fromJson(jsonObject, AccessRequest.class);
recentAppName = request.AppName.toString();
recentRequestTime = request.RequestTime.toString();
if (request.IsExpired)
isExpired = "Has Expired";
else isExpired = "Active";
tvRecentAppName.setText(recentAppName);
tvRecentRequestTime.setText(recentRequestTime);
tvIsExpired.setText(isExpired);
}
}
});
The problem I am having is that when the debugger reaches the SetText lines of code, it is causing the app to crash and close. I am at a loss as to how I can solve this but I assume it has something to with the Okhttp Async call not being able to update the UI, as my setText methods are working fine in onCreate().
That's because views' updates can only be done on UI thread and OkHttp's onResponse runs on background thread. Try to run that on main thread like this:
#Override
public void onResponse(Call call, Response response) throws IOException {
final String responseData = response.body().string();
if (responseData != null) {
Gson gson = new Gson();
JsonElement element = gson.fromJson(responseData, JsonElement.class);
JsonObject jsonObject = element.getAsJsonObject();
final AccessRequest request = gson.fromJson(jsonObject, AccessRequest.class);
recentAppName = request.AppName.toString();
recentRequestTime = request.RequestTime.toString();
if (request.IsExpired)
isExpired = "Has Expired";
else isExpired = "Active";
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
//Handle UI here
tvRecentAppName.setText(recentAppName);
tvRecentRequestTime.setText(recentRequestTime);
tvIsExpired.setText(isExpired);
}
});
}
}
Similarly if you have update any views on onFailure, do it on UI thread.