I'm fighting with this for a week, without luck.
From the begining:
There is an Activity with Navigation Drawer included. This activity has it's own fragments. Fragments have logic to send requests to a weather api and logic to update themselves with given data. At the first run everything seems to work fine! I'm able to send request and fill views with given data (using okHttp).
Everything is starting to collapse after fragments recreations, I'm getting constantly getActivity() to be null ;(
Code Sample below:
Fragments first initialisation:
public abstract class DoubleFragmentActivity extends AppCompatActivity {
protected static final String TOP_FRAGMENT = "TOP_FRAGMENT";
protected static final String BOTTOM_FRAGMENT = "BOTTOM_FRAGMENT";
protected abstract Fragment topFragment();
protected abstract Fragment bottomFragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_container);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.topFragmentContainer, topFragment(), TOP_FRAGMENT)
.add(R.id.bottomFragmentContainer, bottomFragment(), BOTTOM_FRAGMENT)
.commit();
getSupportFragmentManager().executePendingTransactions();
}
}
}
Navigation Drawer:
private void selectDrawerItem(MenuItem menuItem) {
Fragment f;
Fragment f2;
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
switch (menuItem.getItemId()) {
case R.id.forecastFragment:
f = getSupportFragmentManager().findFragmentByTag("TOP_FRAGMENT");
f2 = getSupportFragmentManager().findFragmentByTag("BOTTOM_FRAGMENT");
if (f != mCurrentForecastFragment || f2 != mDailyForecastFragment) {
ft.replace(R.id.topFragmentContainer, new CurrentForecastFragment(), "TOP_FRAGMENT");
ft.replace(R.id.bottomFragmentContainer, new DailyForecastFragment(), "BOTTOM_FRAGMENT");
} else {
}
break;
case R.id.settingsFragment:
mToolbar.setVisibility(View.INVISIBLE);
f = new SettingsFragment();
ft.replace(R.id.topFragmentContainer, f);
break;
case R.id.paymentsFragment:
f = new PaymentsFragment();
ft.replace(R.id.topFragmentContainer, f);
break;
case R.id.aboutFragment:
break;
default:
}
getSupportFragmentManager().executePendingTransactions();
ft.commit();
menuItem.setChecked(true);
setTitle(menuItem.getTitle());
mDrawer.closeDrawers();
}
Fragment`s logic for connecting and fullfilling data:
public void makeConnectionToApi(String lat, String lon) {
mWeatherParams.setLanguage(Locale.getDefault().getLanguage());
Activity a = getActivity();
Uri.Builder currentBuilder = new Uri.Builder();
currentBuilder.scheme("http")
.authority("api.openweathermap.org")
.appendPath("data")
.appendPath("2.5")
.appendPath("weather")
.appendQueryParameter(WeatherConstants.KEY_LATITUDE, lat)
.appendQueryParameter(WeatherConstants.KEY_LONGITUDE, lon)
.appendQueryParameter(WeatherConstants.KEY_UNITS, mUnit)
.appendQueryParameter(WeatherConstants.KEY_LANGUAGE, mWeatherParams.getLanguage())
.appendQueryParameter("APPID", "###");
String currentUrl = currentBuilder.build().toString();
if (mUtility.isNetworkAvalaible()) {
Request requestCurrent = new Request.Builder().url(currentUrl).build();
//FIRST CALL
mCall = client.newCall(requestCurrent);
mCall.enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
Bundle args = new Bundle();
args.putString(TAG, e.toString());
Utility.invokeDialog(TAG, e.toString(), getFragmentManager());
}
#Override
public void onResponse(Response response) throws IOException {
String responseBody = String.valueOf(response.body().string());
try {
mForecast.setCurrent(fetchCurrent(responseBody));
} catch (JSONException e) {
e.printStackTrace();
}
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
fillViewWithValues();
}
});
}
});
} else {
Utility.invokeDialog(TAG, "Check your internet connection!", getFragmentManager());
}
}
private Current fetchCurrent(String responseBody) throws JSONException {
Current current = new Current();
JSONObject jo = new JSONObject(responseBody);
//FETCH WEATHER ARRAY
JSONArray weather = jo.getJSONArray(WeatherConstants.KEY_CURRENT_CONDITIONS_ARRAY);
for (int j = 0; j < weather.length(); j++) {
JSONObject weatherParser = weather.getJSONObject(j);
current.setIcon(weatherParser.getString(WeatherConstants.KEY_ICON_ID));
Log.i(TAG, "Icons ID: " + weatherParser.getString(WeatherConstants.KEY_ICON_ID));
current.setConditions(weatherParser.getString(WeatherConstants.KEY_DESCRIPTION));
}
//FETCH TEMP
JSONObject temp = jo.getJSONObject(WeatherConstants.KEY_MAIN_OBJECT);
current.setDay(temp.getDouble(WeatherConstants.KEY_TEMP));
current.setPressure(temp.getDouble(WeatherConstants.KEY_PRESSURE));
current.setHumidity(temp.getDouble(WeatherConstants.KEY_HUMIDITY));
current.setDayMax(temp.getDouble(WeatherConstants.KEY_TEMP_DAY_MAX));
// FETCH VISIBILITY
if (jo.has(WeatherConstants.KEY_VISIBILITY)) {
current.setVisibility(jo.getInt(WeatherConstants.KEY_VISIBILITY));
}
//FETCH WIND
JSONObject wind = jo.getJSONObject(WeatherConstants.KEY_WIND_OBJECT);
current.setWindSpeed(wind.getDouble(WeatherConstants.KEY_WIND_SPEED));
if (wind.has(WeatherConstants.KEY_WIND_DEGREES)) {
current.setWindDegrees(wind.getInt(WeatherConstants.KEY_WIND_DEGREES));
}
JSONObject clouds = jo.getJSONObject(WeatherConstants.KEY_CLOUDS);
current.setClouds(clouds.getInt("all"));
current.setTimeStamp(jo.getInt(WeatherConstants.KEY_TIMESTAMP));
current.setCurrentLocation(jo.getString(WeatherConstants.KEY_CITY_NAME));
return current;
}
private void fillViewWithValues() {
Current current = mForecast.getCurrent();
if (mDeegreSwitch == 0) {
mCurrentTemperature.setText(current.getDay() + "\u00B0");
// setBackgroundColor(current.getDay());
} else {
int c = current.getDay();
double f = (9.0 / 5.0) * c + 32;
int e = (int) Math.round(f);
mCurrentTemperature.setText(String.valueOf((int) Math.round(f)) + "\u00B0");
// setBackgroundColor(e);
}
mCurrentCondition.setText(current.getConditions());
mPressure.setText(String.valueOf(current.getPressure()) + "hPa");
mClouds.setText(String.valueOf(current.getClouds()) + "%");
mHumidity.setText(String.valueOf(current.getHumidity()) + "%");
mCurrentIcon.setImageResource(current.getIcon());
}
Problems occurs here: getActivity().runOnUiThread inside makeConnectionToApi method. I've tried to fetch an activity from onAttach method and pass it makeConnectionToApi as parameter, it worked...but partially. App didn't crash but fragment`s view was not updated, like there was a second fragment underneath or something.
I have filling it might be something with threads or I'm doing sth wrong with fragments transaction...
Related
I am calling rest API which gets access token from salesforce. after I make a rest call to get data from Salesforce and I'm successfully getting records. and all records are shown in android activity list view.
after that I call fragment but fragment view is not showing.
if I'm not making rest call then fragment show properly.
Here is the MainActivity class
public class MainActivity extends AppCompatActivity {
DrawerLayout dLayout;
private ArrayAdapter<String> listAdapter;
ProgressDialog progressDialog;
JSONTokener tokener;
String accessToken_, instanceURL_;
JSONArray finalResult;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setNavigationDrawer(); // call method
// button_save_account = (Button) findViewById(R.id.button_save_account);
accessToken_ = "00D7F000005oJve!ARUAQPJ8hMWibtO1flIPjZfzV4A__Kzj6wTjJ5XA_xE1zbqDs_0fOTZuxJFiLVxsFx_kNPxuNNK6c7yREtbxq4J7W1oWuUEs";
instanceURL_ = "https://harishgakhar40-dev-ed.my.salesforce.com";
// Create list adapter
listAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new ArrayList<String>());
((ListView) findViewById(R.id.contacts_list)).setAdapter(listAdapter);
try {
MyAsyncTasks myAsyncTasks = new MyAsyncTasks();
myAsyncTasks.execute(accessToken_, instanceURL_).get();
} catch (Exception e) {
}
}
private void setNavigationDrawer() {
dLayout = (DrawerLayout) findViewById(R.id.drawer_layout); // initiate a DrawerLayout
NavigationView navView = (NavigationView) findViewById(R.id.navigation); // initiate a Navigation View
navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
Fragment frag = null; // create a Fragment Object
int itemId = menuItem.getItemId(); // get selected menu item's id
if (itemId == R.id.first) {
frag = new InsertRecords();
Bundle bundle = new Bundle();
bundle.putString("access token", accessToken_);
bundle.putString("instanc url", instanceURL_);
frag.setArguments(bundle);
} else if (itemId == R.id.second) {
Log.v("fragment second ---- ", "In Fragment Second ---- ");
frag = new SecondFragment();
} else if (itemId == R.id.third) {
frag = new ThirdFragment();
}
Toast.makeText(getApplicationContext(), menuItem.getTitle(), Toast.LENGTH_SHORT).show();
if (frag != null) {
Log.v("frag ---- ", "frag ------ " + frag);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Log.v("transaction ---- ", "transaction ------ " + frag);
transaction.replace(R.id.frame, frag); // replace a Fragment with Frame Layout
transaction.commit(); // commit the changes
dLayout.closeDrawers(); // close the all open Drawer Views
return true;
}
return false;
}
});
}
public class MyAsyncTasks extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// display a progress dialog for good user experiance
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage("Please Wait");
progressDialog.setCancelable(false);
progressDialog.setMessage("Loading...");
progressDialog.show();
}
#Override
protected String doInBackground(String... params) {
String accessToken = params[0];
String instanceURL = params[1];
// implement API in background and store the response in current variable
String result = "";
DefaultHttpClient client = new DefaultHttpClient();
String url = instanceURL + "/services/data/v20.0/query/?q=";
String soqlQuery = "Select Id, Name, BillingStreet, BillingCity, BillingState From Account Limit 10 ";
try {
url += URLEncoder.encode(soqlQuery, "UTF-8");
} catch (UnsupportedEncodingException e) {
}
HttpGet getRequest = new HttpGet(url);
getRequest.addHeader("Authorization", "OAuth " + accessToken);
Log.v("Token in doin ---- ", "accessToken ---- in doin ---- " + accessToken);
Log.v("instanceURL doin ---- ", "instanceURL ---- in doin ---- " + instanceURL);
try {
HttpResponse response = client.execute(getRequest);
result = EntityUtils.toString(response.getEntity());
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
#Override
protected void onPostExecute(String result) {
try {
progressDialog.dismiss();
// dismiss the progress dialog after receiving data from API
JSONObject object = (JSONObject) new JSONTokener(result).nextValue();
JSONArray records = object.getJSONArray("records");
// globalState.setAccountNames(new String[records.length()]);
// globalState.setAccounts(new JSONObject[records.length()]);
listAdapter.clear();
for (int i = 0; i < records.length(); i++) {
JSONObject record = (JSONObject) records.get(i);
String accountName = record.getString("Name");
Log.v("accountName---- ", "accountName ---- " + accountName);
listAdapter.add(accountName);
// globalState.getAccountNames()[i] = accountName;
//globalState.getAccounts()[i] = record;
}
} catch (Exception e) {
}
Log.d("data", result.toString());
}
}
}
You are blocking MainThread which is rendering UI.
To avoid this, android provides AsyncTask.
BUT make yourself and others working on your project favor and use Retrofit or other libraries. It will save you so much time and make your code cleaner.
Here you can find a good article.
If you really don't feel like using Retrofit, AsyncTask is an option too
You need to call your getAccountData function inside an AsyncTask. The implementation right now is blocking your UI thread, which created the problem I think.
public class GetAccountData implements AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
// Get account data here.
}
#Override
protected void onPostExecute(final String accountName) {
// Pass the accountName to the calling Activity here.
}
// Implement other methods if you need
}
If you are confused about how you can pass the data from your AsyncTask to your Activity, please consider looking into this answer here.
I have a problem with my activity. It work well for the first time i start but after that is crashed with this
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1842)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1860)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:650)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:609)
I try add this to my activity but it not working
#Override
protected void onSaveInstanceState(Bundle outState) {
//No call for super(). Bug on API Level > 11.
}
When i use commitAllowingStateLoss() instead of commit() for changing Fragment the error now is Activity has been destroy. I have to close the app. I dont know why it run only in the first time of the activity is called.
Here is my function to change the fragment
private void showWaitingFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
WaitingFragment fragment = new WaitingFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
private void showAnswerFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
AnswerFragment fragment = new AnswerFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
First i call showWattingFragment after the server emit event on socket i call showAnswerFragment.
The code for socket
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.d("socket_log", "connected");
}
}).on("quizQuestionReady", new Emitter.Listener() {
#Override
public void call(Object... args) {
showWaitingFragment();
}
}).on("quizQuestionLoaded", new Emitter.Listener() {
#Override
public void call(Object... args) {
showAnswerFragment();
}
}).on("quizEnded", new Emitter.Listener() {
#Override
public void call(Object... args) {
showResultFragment();
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {}
});
socket.connect();
As I said before this worked for the first time i start the activity, not working after i call onBackPress() or finish() then startActivity again
UPDATE my activity
public class StudentQuizActivity extends AppCompatActivity {
#BindView(R.id.quiz_content_frame)
FrameLayout _frame_content;
public Socket socket;
String quiz_code;
public SharedPreferences prefs;
ProgressDialog progressDialog;
int user_id;
String token;
public int currentQuestionIndex = -1;
public int currentQuestionIndexForShowing = 0;
public int countCorrect = 0;
public boolean no_answer = true;
public ArrayList<String> answers;
public ArrayList<String> correct_answers;
public ArrayList<Boolean> corrects;
public JSONObject quizConfig;
public JSONArray quizQuestions;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_student_quiz);
prefs = new SecurePreferences(this);
quiz_code = prefs.getString(AppVariable.QUIZ_CODE, null);
user_id = prefs.getInt(AppVariable.USER_ID, 0);
token = prefs.getString(AppVariable.USER_TOKEN, null);
ButterKnife.bind(this);
this.setTitle("QUIZ");
// prepare spinner
progressDialog = new ProgressDialog(this, R.style.AppTheme_Dark_Dialog);
progressDialog.setIndeterminate(true);
progressDialog.setCanceledOnTouchOutside(false);
prefs.edit().putString(AppVariable.QUIZ_MESSAGE, "Waiting for the quiz to start").apply();
answers = new ArrayList<>();
correct_answers = new ArrayList<>();
corrects = new ArrayList<>();
setSocket();
new GetQuizTask().execute();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
//No call for super(). Bug on API Level > 11.
}
//UI
private void showWaitingFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
WaitingFragment fragment = new WaitingFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
private void showAnswerFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
AnswerFragment fragment = new AnswerFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
private void showResultFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ResultFragment fragment = new ResultFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
public void showDetailFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
DetailFragment fragment = new DetailFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
#Override
public void onBackPressed() {
super.onBackPressed();
}
private class GetQuizTask extends AsyncTask<String, Void, Integer> {
private Exception exception;
private String strJsonResponse;
#Override
protected void onPreExecute() {
progressDialog.setMessage("Loading...");
progressDialog.show();
}
#Override
protected Integer doInBackground(String... params) {
int flag = 0;
try {
URL url = new URL(Network.API_GET_QUIZ);
//prepare json data
JSONObject jsonUserData = new JSONObject();
jsonUserData.put("token", token);
jsonUserData.put("quiz_code", quiz_code);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try {
connection.setReadTimeout(10000);
connection.setConnectTimeout(15000);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setRequestProperty("Accept", "application/json");
connection.setDoInput(true);
connection.setDoOutput(true);
//write
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(jsonUserData.toString());
writer.flush();
//check http response code
int status = connection.getResponseCode();
switch (status){
case HttpURLConnection.HTTP_OK:
//read response
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
sb.append(line).append("\n");
}
bufferedReader.close();
strJsonResponse = sb.toString();
flag = HttpURLConnection.HTTP_OK;
default:
exception = new Exception(connection.getResponseMessage());
}
}
finally{
connection.disconnect();
}
}
catch(Exception e) {
exception = e;
}
return flag;
}
#Override
protected void onPostExecute(Integer status) {
if (status != HttpURLConnection.HTTP_OK){
displayToast(exception.getMessage());
}
else {
try{
JSONObject jsonObject = new JSONObject(strJsonResponse);
String result = jsonObject.getString("result");
if (result.equals("failure")){
String message = jsonObject.getString("message");
progressDialog.dismiss();
displayToast(message);
return;
}
quizConfig = jsonObject.getJSONObject("quiz");
quizQuestions = quizConfig.getJSONArray("questions");
prefs.edit().putInt(AppVariable.QUIZ_TOTAL, quizQuestions.length())
.putString(AppVariable.QUIZ_TITLE, quizConfig.getString("title")).apply();
progressDialog.dismiss();
showWaitingFragment();
return;
} catch (JSONException e) {
e.printStackTrace();
displayToast(e.getMessage());
}
}
progressDialog.dismiss();
}
}
//Socket
private void setSocket(){
if (Network.isOnline(this)){
try {
socket = IO.socket(Network.HOST);
} catch (URISyntaxException e) {
e.printStackTrace();
}
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.d("socket_log", "connected");
}
}).on("quizQuestionReady", new Emitter.Listener() {
#Override
public void call(Object... args) {
currentQuestionIndexForShowing += 1;
prefs.edit().putString(AppVariable.QUIZ_MESSAGE, "Ready for the next question")
.putInt(AppVariable.QUIZ_INDEX, currentQuestionIndexForShowing).apply();
showWaitingFragment();
}
}).on("quizQuestionLoaded", new Emitter.Listener() {
#Override
public void call(Object... args) {
currentQuestionIndex += 1;
showAnswerFragment();
}
}).on("quizQuestionEnded", new Emitter.Listener() {
#Override
public void call(Object... args) {
}
}).on("quizEnded", new Emitter.Listener() {
#Override
public void call(Object... args) {
prefs.edit()
.putInt(AppVariable.QUIZ_INDEX, 0).apply();
showResultFragment();
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {}
});
socket.connect();
}
}
public void emitAnswer(String option){
JSONObject payload = new JSONObject();
try {
payload.put("quiz_code", quiz_code);
payload.put("question_index", currentQuestionIndex);
payload.put("option", option);
payload.put("student_id", user_id);
} catch (JSONException e) {
e.printStackTrace();
}
no_answer = false;
try {
JSONObject quizDetail = quizQuestions.getJSONObject(currentQuestionIndex);
String correct_option = quizDetail.getString("correct_option");
ArrayList<String> options = new ArrayList<>();
options.add(quizDetail.getString("option_a"));
options.add(quizDetail.getString("option_b"));
options.add(quizDetail.getString("option_c"));
options.add(quizDetail.getString("option_d"));
String[] keys = {"a", "b", "c", "d"};
for (int i = 0; i < 4; i++){
if (correct_option.equals(options.get(i))){
correct_option = keys[i];
break;
}
}
if (option.equals(correct_option)){
corrects.add(true);
countCorrect += 1;
}
else {
corrects.add(false);
}
correct_answers.add(correct_option);
} catch (JSONException e) {
e.printStackTrace();
}
answers.add(option);
socket.emit("answeredQuiz", payload);
}
}
There are many things need to check inside your code. Let take a look one by one.
Inner class GetQuizTask
This is an API request task which could take much time. By default, if everything ok, AsyncTask will help you handle it in background, then post the result in UI thread.
In your onPostExecute(Integer status), you implicit call showWaitingFragment() which is the same as this.showWaitingFragment().
That means you are holding a parent reference inside your inner class. This could lead you to memory leak. Example: If your request takes 10 seconds to finish, but before onPostExecute() called, what happens if your activity is destroyed or change its state before 10 seconds? (There are many things could make you activity change, like you call finish(), rotate the screen, System have to clean memory, User press Home button, etc...). So when these things happen, the activity (or this in this. showWaitingFragment()) can't be collected by garbage collection). That leads you to the memory leak.
One more thing. If your activity changed from foreground to background (user press Home button), the onPostExecute needs to perform showFragment in UI thread, which can't be done right now, what happens then?
Those errors will give you the IllegalStateException.
Solution: Using WeakPreference, something like this:
private class GetQuizTask extends AsyncTask<String, Void, Integer> {
WeakReference<StudentQuizActivity> studentQuizActivity;
#Override
protected void onPreExecute() {
// do your work before the task execute..
}
#Override
protected Integer doInBackground(String... params) {
// do your work in background..
}
#Override
protected void onPostExecute(Integer status) {
try{
if (studentQuizActivity.get() != null) {
studentQuizActivity.get().showInfo();
}
} catch (Exception e) {
}
}
}
Avoid boilerplate codes
There are many functions to show fragment, which can simplify like this
private void showFragment(Fragment fragment) {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
Then
showFragment(yourResultFragment);
showFragment(yourTransactionFragment);
Before using dismiss for ProgressDialog, check if (progressDialog.isShowing()). Because user can dismiss it before onPostExecute() performing.
Please, decouple your code. Don't push everything inside your inner class. It will easily lead you to tons of errors. One more thing, if there is no special use-case, try to use the static inner class instead. Follow this answers.
I can't detect all your mistake because I don't get your situation, but I wish this helps! Rewrite your code, carefully, one by one.
This is very simple.
You should use commitAllowingStateLoss() instead of commit()
transaction.commitAllowingStateLoss();
How to achieve this?
Okay I have this process
On Index Activity, when I click the side nav Profile, it will call Fragment (Profile) thru Fragment Transaction
if (id == R.id.nav_profile){
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.setCustomAnimations(R.anim.enter,R.anim.exit,R.anim.enter,R.anim.exit);
transaction.replace(R.id.flContent, new Profile(), "ProfileFragment");
transaction.addToBackStack(null);
viewPager.getAdapter().notifyDataSetChanged();
transaction.commit();
}
Now I'm on the Profile Fragment:
When I click "Apply for Developer" button, it will call DevRegistration activity by Intent
case 1:
btnBeDeveloper.setText("Apply for Developer");
btnBeDeveloper.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent index = new Intent(getActivity(), DevRegistration.class);
startActivity(index);
}
});
break;
Step 3:
On DevRegistration after I click Register, it will display a dialog fragment
FragmentManager fm = getSupportFragmentManager();
df_SuccessDevRegistration dialogFragment = new df_SuccessDevRegistration();
dialogFragment.show(fm, "Dev Register.");
Now this is my Dialog Fragment code:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
View rootView = inflater.inflate(R.layout.fragment_success_developer_registration, container, false);
btnDevGoProfile = (Button) rootView.findViewById(R.id.btnDevGoProfile);
btnDevGoProfile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dismiss();
getActivity().finish();
}
});
return rootView;
}
Now my problem is, when I press the button on the dialog fragment, it should refresh my profile fragment. how to achieve that? I tried detach attach but my app just crashed and for null exception.
public class Profile extends Fragment {
TextView txvStudID, txvStudUsername, txvStudEmail, txvStudBday,txvProfileName;
CollapsingToolbarLayout ctlName;
ImageView imvProfilePic;
Button btnBeDeveloper;
View rootView;
String picURL;
FragmentTransaction ft; Fragment currentFragment;
/** Recycler View**/
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rootView = inflater.inflate(R.layout.activity_profile, container, false);
Toolbar toolbar = (Toolbar) rootView.findViewById(R.id.profile_toolbar);
((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view) {
NavigationView navigationView = (NavigationView) getActivity().findViewById(R.id.nav_view);
getFragmentManager().popBackStack();
navigationView.getMenu().getItem(0).setChecked(true);
}
});
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
((AppCompatActivity)getActivity()).getSupportActionBar().setHomeButtonEnabled(true);
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayShowTitleEnabled(true);
txvStudID = (TextView) rootView.findViewById(R.id.txvStudID);
txvStudUsername = (TextView) rootView.findViewById(R.id.txvStudUsername);
txvStudEmail = (TextView)rootView.findViewById(R.id.txvStudEmail);
txvStudBday = (TextView) rootView.findViewById(R.id.txvStudBday);
txvProfileName = (TextView) rootView.findViewById(R.id.txvProfileName);
ctlName = (CollapsingToolbarLayout) rootView.findViewById(R.id.ctlName);
imvProfilePic = (ImageView) rootView.findViewById(R.id.imvProfilePic);
btnBeDeveloper = (Button) rootView.findViewById(R.id.btnBeDeveloper);
checkLevelOfAccess();
/** get user's data **/
getCurrentUserData(DataClass.currentEnteredUsername);
return rootView;
}
public void checkLevelOfAccess()
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
String acctID = preferences.getString("acctID", "DEFAULT");
switch (checkLevelOfAccess(acctID)) {
// if the level of access is developer
case 1:
btnBeDeveloper.setText("Developer Console");
btnBeDeveloper.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent index = new Intent(getActivity(), UploadApp.class);
startActivity(index);
}
});
break;
// else if the level of access is not a developer
case 0:
switch (checkIfRegistered(acctID))
{
//already apply
case 0:
btnBeDeveloper.setText("Cancel Developer Request");
break;
case 1:
btnBeDeveloper.setText("Apply for Developer");
btnBeDeveloper.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent index = new Intent(getActivity(), DevRegistration.class);
startActivityForResult(index, 10001);
}
});
break;
}
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if ((requestCode == 10001) && (resultCode == Activity.RESULT_OK))
{
System.out.println("IM HERE NA!!!");
checkLevelOfAccess();
}
}
public void getCurrentUserData(String currentUser) {
try {
String accountURL = DataClass.localAddress + "android_php/account.php";
URL url = new URL(accountURL);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
String finalJson = buffer.toString();
JSONObject parentObject = new JSONObject(finalJson);
JSONArray parentArray = parentObject.getJSONArray("users");
for (int x = 0; x < parentArray.length(); x++) {
JSONObject finalObject = parentArray.getJSONObject(x);
if (finalObject.getString("username").equalsIgnoreCase(currentUser) || finalObject.getString("studID").equalsIgnoreCase(currentUser)
|| finalObject.getString("email").equalsIgnoreCase(currentUser)) {
txvStudID.setText(finalObject.getString("studID"));
txvStudUsername.setText(finalObject.getString("username"));
txvStudEmail.setText(finalObject.getString("email"));
txvStudBday.setText(convertDate(finalObject.getString("bday")));
ctlName.setTitle(finalObject.getString("name"));
txvProfileName.setText(finalObject.getString("name"));
//set Profile Picture
picURL = DataClass.localAddress + finalObject.getString("pic");
LoadImageFromURL loadImage = new LoadImageFromURL();
loadImage.execute();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String convertDate(String date) throws ParseException {
String strCurrentDate = date;
DateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd");
DateFormat outputFormat = new SimpleDateFormat("dd MMM yyyy");
Date parseDate = inputFormat.parse(strCurrentDate);
String converted = outputFormat.format(parseDate);
return converted;
}
public class LoadImageFromURL extends AsyncTask<String, Void, Bitmap>{
#Override
protected Bitmap doInBackground(String... params) {
// TODO Auto-generated method stub
try {
InputStream is = new URL(picURL).openConnection().getInputStream();
Bitmap bitMap = BitmapFactory.decodeStream(is);
GetCircleBitmap gcb = new GetCircleBitmap();
Bitmap b = gcb.GetCircleBitmap(bitMap);
return b;
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Bitmap result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
imvProfilePic.setImageBitmap(result);
}
}
public int checkLevelOfAccess(String data)
{
try {
String accountURL = DataClass.localAddress + "android_php/account.php";
URL url = new URL(accountURL);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
String finalJson = buffer.toString();
JSONObject parentObject = new JSONObject(finalJson);
JSONArray parentArray = parentObject.getJSONArray("users");
for (int x = 0; x < parentArray.length(); x++) {
JSONObject finalObject = parentArray.getJSONObject(x);
// true
if (finalObject.getString("acctid").equalsIgnoreCase(data) && finalObject.getString("acctlofa").equals("1"))
{
return 1;
}
else if (finalObject.getString("acctid").equalsIgnoreCase(data) && finalObject.getString("acctlofa").equals("0"))
{
return 0;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return 2;
}
/** Check if the user already applied to become a developer **/
public int checkIfRegistered(String data) {
try {
String accountURL = DataClass.localAddress + "android_php/developer_account.php";
URL url = new URL(accountURL);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
String finalJson = buffer.toString();
JSONObject parentObject = new JSONObject(finalJson);
JSONArray parentArray = parentObject.getJSONArray("users");
for (int x = 0; x < parentArray.length(); x++) {
JSONObject finalObject = parentArray.getJSONObject(x);
// pending application
if (finalObject.getString("acctID").equalsIgnoreCase(data) && finalObject.getString("devStatus").equals("0"))
{
return 0;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return 1;
}
}
I'dd suggest you using intents between activity call, and StartForRsults().
Then when your activity resume using public void onActivityResult(int requestCode, int resultCode, Intent intent) you'll be able to check if the user correctly registered (and not cancelled registration) through a boolead in the intent.
Then, set a global variable "refreshProfile", and make it true when your activity resume with the correct intent saying user registered. Override public void onPostResume(), use a if statement to check wether or not you need to refresh the profile. If yes, do so then make the variable false. if not, do nothing.
Doing so will prevent you from updating your profileFragment when activity is resuming wich can cause some crash sometimes ("IllegalStateException: Can not perform this action after onSaveInstanceState") because you are updating the UI at the wrong moment.
Other option consists into changing the dialogFragment, setting a custom function to refresh your activity.
build.setPositiveButton(positiveButton, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
/*refresh profile here
with instruction like getActivity().refresh();
where refresh is your activity public function to refresh profile.
*/
}
});
However, i dislike that way because your profile will wait user to confirm before being updated. I find it more clearer and elegant to have profile updated THEN prevent the user everything went fine. But personnal opinion here.
In your fragment that you need to refresh create and register a broadcast receiver.
When you want to refresh the fragment (in your case when clicking the button on the dialog fragment) send a broadcast which will be caught by your broadcast receiver on the profile fragment.
This will also make sure that the solution is not too tightly coupled.
You need to return the result back to the activity which contains the profile data. This can be done in several ways. In this case, I assume you want the profile to remain changed permanently. For example if the user quits the app and starts it again a week later, the changes should persist to the profile screen. This suggests that you need the data to be stored permanently. For small amounts of data, such as a boolean flag or a String, you can use SharedPreferences. For more complex data, use a SQLite database or a flat file. Now the dialog just saves the data to the chosen medium and the profile fragment loads the data in onCreate().
I have an app that reads and display data from a weather API as show below.
Now those data you see in the RecyclerView are displayed via a Fragment. What happens is when I click the Forecast button in the toolbar the web service service is running again. Which means that the Fragment is added in the stack/click.
So here is my logic how to fix that. If the stack is null then add the Fragment. If not then don't.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.forecast) {
String tag = "forecastFragment";
Fragment f = getSupportFragmentManager().findFragmentByTag(tag);
if (f == null) {
ForecastFragment forecastFragment = new ForecastFragment();
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.main_content, forecastFragment, "forecastfragment");
ft.addToBackStack("added today current");
forecastFragment.setArguments(b);
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
ft.commit();
} else{
getSupportFragmentManager().findFragmentById(R.id.main_content);
}
}
return super.onOptionsItemSelected(item);
}
Here is what I did, but still the web service is running every time I click the Forecast button.
Any ideas?
Here is my Webservice that is run by the ForecastFragment.
class ForecastFragment extends Fragment {
private static final String FORECAST_KEY = "forecast";
public static String URL=
"http://api.openweathermap.org/data/2.5/forecast/daily?";
EditText editText;
public static String BASE_URL= "";
private String IMG_URL ="http://api.openweathermap.org/img/w/";
private String retrievedLat;
private String retrievedLog;
private RecyclerView mRecyclerView;
ImageView imageView;
public ArrayList<Model> modelList;
private Model m;
WeekForecastAdapter adapter;
public ForecastFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_forecast, container, false);
retrievedLat = getArguments().getString("lat");
retrievedLog = getArguments().getString("log");
//http://api.openweathermap.org/data/2.5/forecast/daily?lat=35&lon=139&units=metric&cnt=10&mode=json&appid=d48708e1e4d8e2b60da14778acd8d56a
BASE_URL = URL +"lat="+retrievedLat+"&lon="+retrievedLog+"&units=metric&cnt=10&mode=json&appid=d48708e1e4d8e2b60da14778acd8d56a";
modelList = new ArrayList<>();
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView = (RecyclerView)rootView.findViewById(R.id.week_forecast_recycler_view);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(linearLayoutManager);
adapter = new WeekForecastAdapter(getActivity(),modelList);
mRecyclerView.setAdapter(adapter);
if(savedInstanceState!=null){
ArrayList<Model> items = savedInstanceState.getParcelableArrayList(FORECAST_KEY);
modelList = savedInstanceState.getParcelableArrayList(FORECAST_KEY);
adapter.setModel(items);
}else {
if(isOnline()) {
weekWeatherData();
}else{
Toast.makeText(getActivity(),"No internet connection",Toast.LENGTH_SHORT).show();
}
}
return rootView;
}
private void weekWeatherData() {
modelList.clear();
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
BASE_URL,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d("TAG", response.toString());
try {
m = new Model();
JSONObject cityObject = response.getJSONObject("city");
String city = cityObject.getString("name");
String country = cityObject.getString("country");
JSONArray jsonObject = response.getJSONArray("list");
for(int i = 0;i<jsonObject.length();i++){
m = new Model();
m.setCity(city);
m.setCountry(country);
//list:
// {"dt":1464343200,"temp":{"day":23.05,"min":8.65,"max":24.96,"night":13.22,"eve":24.85,"morn":8.65},
// "pressure":950.2,"humidity":41,"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01d"
// }],
// "speed":1.16,"deg":342,"clouds":0}
JSONObject innerJSON = jsonObject.getJSONObject(i);
long dateTime = innerJSON.getLong("dt");
Date weekDay = new Date(dateTime * 1000L);
SimpleDateFormat outFormat = new SimpleDateFormat("EEEE");
String day = outFormat.format(weekDay);
SimpleDateFormat outFormat1 = new SimpleDateFormat("dd MMM");
String date = outFormat1.format(weekDay);
m.setDay(day);
m.setDate(date);
m.setDay(day);
//temp:{"day":26.92,"min":19.48,"max":26.92,"night":19.48,"eve":25.65,"morn":26.92}
JSONObject tempObject = innerJSON.getJSONObject("temp");
m.setTemperature(tempObject.getString("day"));
m.setMaxTemperature(tempObject.getString("max"));
m.setMinTemperature(tempObject.getString("min"));
double pressure = innerJSON.getDouble("pressure");
int humidity = innerJSON.getInt("humidity");
m.setPressure(String.valueOf(pressure));
m.setHumidity(String.valueOf(humidity));
JSONArray weather = innerJSON.getJSONArray("weather");
for(int j=0;j<weather.length();j++){
JSONObject weatherObject = weather.getJSONObject(j);
m.setDescription(weatherObject.getString("description"));
m.setImageIcon(IMG_URL+weatherObject.getString("icon"));
}
double speed = innerJSON.getDouble("speed");
m.setSpeed(String.valueOf(speed));
modelList.add(m);
}
} catch (JSONException e) {
Log.e("TAG", e.toString());
}
adapter.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsonObjReq);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.v("Theo","onSaveInstanceState called");
outState.putParcelableArrayList(FORECAST_KEY,modelList);
}
#Override
public void onDestroy() {
super.onDestroy();
Log.v("Theo","onDestroy called");
}
protected boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager)getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
} else {
return false;
}
}
}
Change:
ft.replace(R.id.main_content, forecastFragment, "forecastfragment");
To:
ft.replace(R.id.main_content, forecastFragment, tag);
Because your tag (i.e. "forecastFragment") string value is different than the tag you are passing while adding the fragment (i.e. "forecastfragment"). That's why it is not able to find the fragment by tag and adding it everytime on clicking.
I found another solution too.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.forecast) {
ForecastFragment forecastFragment = null;
int backStackEntryCount =
getSupportFragmentManager().getBackStackEntryCount();
if (backStackEntryCount == 0 && forecastFragment == null) {
forecastFragment = new ForecastFragment();
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.main_content, forecastFragment);
ft.addToBackStack("added today current");
forecastFragment.setArguments(b);
//fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
ft.commit();
}else{
//getSupportFragmentManager().findFragmentById(R.id.main_content);
}
}
return super.onOptionsItemSelected(item);
}
Having navigation drawer in application, Each drawer represents one Fragment each Fragment is having an AsyncTask to download separate data. I am changing Fragments by these codes
private void setupNavigationDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.home_main:
menuItem.setChecked(true);
actionBar.setTitle("Home");
drawerLayout.closeDrawer(GravityCompat.START);
if(getSupportFragmentManager().findFragmentByTag("ranking")==null)
{
getSupportFragmentManager().beginTransaction().add(R.id.list_view_container,
new Home(), "ranking").
addToBackStack("ranking").
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit();
}
else
{
getSupportFragmentManager().popBackStack("ranking", 0);
}
return true;
case R.id.national_events:
menuItem.setChecked(true);
actionBar.setTitle("National events");
drawerLayout.closeDrawer(GravityCompat.START);
if(getSupportFragmentManager().findFragmentByTag("ranking3")==null)
{
getSupportFragmentManager().beginTransaction().add(R.id.list_view_container,
new NationalEvents(), "ranking3").
addToBackStack("ranking3").
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit();
}
else
{
getSupportFragmentManager().popBackStack("ranking3", 3);
}
return true;
case R.id.workshops:
menuItem.setChecked(true);
actionBar.setTitle("Workshops");
drawerLayout.closeDrawer(GravityCompat.START);
if(getSupportFragmentManager().findFragmentByTag("ranking4")==null)
{
getSupportFragmentManager().beginTransaction().add(R.id.list_view_container,
new Workshops(), "ranking4").
addToBackStack("ranking4").
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit();
}
else
{
getSupportFragmentManager().popBackStack("ranking4", 4);
}
return true;
And the code being used for downloading data is
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View home_view = inflater.inflate(R.layout.list_view, container, false);
tf = Typeface.createFromAsset(getActivity().getAssets(), "fonts/cool_jazz.ttf");
swipeLayout = (SwipeRefreshLayout) home_view.findViewById(R.id.swipe_container);
swipeLayout.setColorSchemeColors(R.color.md_purple_500,
R.color.md_deep_purple_A400,
R.color.md_pink_500,
R.color.md_red_500);
mRecyclerView = (RecyclerView) home_view.findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mProgressBar = (ProgressBar) home_view.findViewById(R.id.progress_bar);
mProgressBar.setVisibility(View.VISIBLE);
mDescription=(TextView)home_view.findViewById(R.id.desription);
mDescription.setText(getString(R.string.national_events));
mDescription.setTypeface(tf);
iu1=(TextView)home_view.findViewById(R.id.iu1);
iu1.setTypeface(tf);
iu2=(TextView)home_view.findViewById(R.id.iu2);
iu2.setTypeface(tf);
iu3=(TextView)home_view.findViewById(R.id.iu3);
iu3.setTypeface(tf);
iu4=(TextView)home_view.findViewById(R.id.iu4);
iu4.setTypeface(tf);
iu5=(TextView)home_view.findViewById(R.id.iu5);
iu5.setTypeface(tf);
iu6=(TextView)home_view.findViewById(R.id.iu6);
iu6.setTypeface(tf);
internet=(RelativeLayout)home_view.findViewById(R.id.internet_unavailable);
internet.setVisibility(View.GONE);
Senturl = "http://javatechig.com/?json=get_recent_posts&count=45";
new MainActivityData().execute(Senturl);
swipeLayout.setOnRefreshListener(this);
return home_view;
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);setRetainInstance(true);
}
#Override
public void onRefresh() {
mProgressBar.setVisibility(View.GONE);
internet.setVisibility(View.GONE);
new MainActivityData().execute(Senturl);
}
public class MainActivityData extends AsyncTask<String,Void,Integer>
{
#Override
protected void onPreExecute() {
getActivity().setProgressBarIndeterminateVisibility(true);
}
#Override
protected Integer doInBackground(String... params) {
Integer result = 0;
HttpURLConnection urlConnection;
try {
URL url = new URL(params[0]);
urlConnection = (HttpURLConnection) url.openConnection();
int statusCode = urlConnection.getResponseCode();
// 200 represents HTTP OK
if (statusCode ==200 ) {
BufferedReader r = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
response.append(line);
}
parseResult(response.toString());
result = 1; // Successful
} else {
result = 0; //"Failed to fetch data!";
}
} catch (Exception e){
if(e.getLocalizedMessage()!=null){
Log.d(TAG, e.getLocalizedMessage());
}
}
return result; //"Failed to fetch data!";
}
#Override
protected void onPostExecute(Integer result) {
// Download complete. Let us update UI
mProgressBar.setVisibility(View.GONE);
swipeLayout.setRefreshing(false);
mDescription.setVisibility(View.GONE);
if (result == 1) {
new Thread(new Runnable() {
#Override
public void run() {
mAdapter = new MembersAdapter(getActivity(),membersList);
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if (mAdapter != null)
{
mRecyclerView.setAdapter(mAdapter);
}}
});
}
}).start();
} else {
internet.setVisibility(View.VISIBLE);
}
}
}
private void parseResult(String result) {
try {
JSONObject response = new JSONObject(result);
JSONArray posts = response.optJSONArray("posts");
membersList = new ArrayList<>();
for (int i = 0; i < posts.length(); i++) {
JSONObject post = posts.optJSONObject(i);
Members item = new Members();
item.setTitle(post.optString("title"));
item.setThumbnail(post.optString("thumbnail"));
item.setDescription(post.optString("content"));
item.setDate(post.optString("date"));
//item.setSub_title(post.optString("sub_title"));
membersList.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
Things are working fine but when I am changing the multiple fragments in very small interval of time then Application is getting crashed. What I think is this all is due to a lot of AysncTasks given to the system. May be this want to pause AsyncTask.
I would suggest putting every AsyncTask in one separate non-ui retained fragment (a fragment that doesn't hold any views and is initialized with setRetainInstance(true) method in onCreate(). The AsyncTasks will load the data into this fragment, and during reconfiguration it won't be destroyed thanks to setRetainInstance(true). Then, after reconfiguration you can retrieve the data from this fragment and do with it as you will - populate the adapters and so on.