Android: Content Adapter shouldn't be modified from UI Thread - android

Sometimes I receive this error on my Activity below, sometimes not:
The content of the adapter has changed
but ListView did not receive a notification. Make sure the content of
your adapter is not modified from a background thread, but only from the
UI thread.
but I'm not sure where my mistake on my class below. Does anybody have idea?
public class FavoriteActivity extends SpeakSuperActivity {
private final static String TAG = FavoriteActivity.class.getSimpleName();
private Button btn_filter_topic, btn_filter_rating, btn_filter_none;
private TextView fav_filter_text;
private static ListView listViewFavorites;
private static TextView txtNoFavoritesYet;
private List<Favorite> currentFavorites;
private ArrayAdapter<Favorite> currentFavoritesArrayAdapter;
// required for list loading piece by piece
final int itemsPerLoading = Configuration.LOADED_ITEMS_ON_LIST_AT_ONCE;
boolean loadingMore = false;
private List<Long> idList;
int currentDataLoaded;
private static int oldBtnViewId = 0;
// set the start value as same as the loading value
int maximumDataLoadedYet = Configuration.LOADED_ITEMS_ON_LIST_AT_ONCE;
// 0 = not sorted, 1 = sorted by topic and minimum number of stars
private int caseSelection = 0;
private static View progressView;
private View footerView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.favorites);
Log.d(TAG, "FavoritesScreen onCreate()...");
// indicator for waiting processes
progressView = UIUtils.addBlockingProgressIndicatorBlack(this);
// init Listview
listViewFavorites = (ListView) findViewById(R.id.fav_listview_favorites);
// add the footer before adding the adapter, else the footer
// will not load!
footerView = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.listviewfooter, null, false);
listViewFavorites.addFooterView(footerView);
listViewFavorites = (ListView) findViewById(R.id.fav_listview_favorites);
fav_filter_text = (TextView) findViewById(R.id.fav_filter_text);
btn_filter_none = (Button) findViewById(R.id.btn_fav_filter_none);
btn_filter_topic = (Button) findViewById(R.id.btn_fav_filter_topic);
btn_filter_rating = (Button) findViewById(R.id.btn_fav_filter_rating);
toggleButtonStates(R.id.btn_fav_filter_none);
LoadDataTask ldTask = new LoadDataTask();
ldTask.execute();
// no favorites yet?
txtNoFavoritesYet = (TextView) findViewById(R.id.fav_no_favorites_yet);
updateUI();
}
/**
* An asynchronous Task (doesn't block the UI Thread) for loading the Data in background.
*
* #author Jonas Soukup
*/
private class LoadDataTask extends AsyncTask<Void, Void, LoudmouthException> {
private final String TAG = LoadDataTask.class.getName();
protected void onPreExecute() {
super.onPreExecute();
if (FavoriteProvider.getInstance().getNumOfFavorites() != 0)
progressView.setVisibility(View.VISIBLE);
else
progressView.setVisibility(View.GONE);
listViewFavorites.setVisibility(View.GONE);
fav_filter_text.setVisibility(View.GONE);
btn_filter_none.setVisibility(View.GONE);
btn_filter_topic.setVisibility(View.GONE);
btn_filter_rating.setVisibility(View.GONE);
}
protected LoudmouthException doInBackground(Void... params) {
LoudmouthException exception = null;
Log.d(TAG, "loading data..");
switch (caseSelection) {
case 0:
// Get FavoriteList without sorting
idList = FavoriteProvider.getInstance().getFavoritesByDate();
break;
case 1:
// Get FavoriteList sorted by
// Topics + amount of stars
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
float minRating = prefs.getFloat(getResources().getString(R.string.rating_filter_star_amount), 0);
idList = FavoriteProvider.getInstance().getFavoritesByTopicAndMinRating(minRating);
break;
default:
Log.e(TAG, "No Case with number: " + caseSelection);
}
// reset data loaded, so it loads till maximumDataLoadedYet on a
// refresh of the list
currentDataLoaded = 0;
// reset List on Data change
currentFavorites = new ArrayList<Favorite>();
Log.d(TAG, "..loading data finished");
return exception;
}
protected void onPostExecute(LoudmouthException result) {
try {
Log.d(TAG, "LoadDataTask.onPostExecute()");
super.onPostExecute(result);
progressView.setVisibility(View.GONE);
if (result != null) {
// Error ocurred during loading
android.content.DialogInterface.OnClickListener retryClickListener = new android.content.DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
new LoadDataTask().execute();
}
};
UIUtils.showRetryCancelAlertDialog(getApplicationContext(), result, retryClickListener, null);
} else {
// Everythings fine, data loaded
// showing & hiding
if (FavoriteProvider.getInstance().getNumOfFavorites() == 0) {
fav_filter_text.setVisibility(View.GONE);
btn_filter_none.setVisibility(View.GONE);
btn_filter_topic.setVisibility(View.GONE);
btn_filter_rating.setVisibility(View.GONE);
} else {
fav_filter_text.setVisibility(View.VISIBLE);
btn_filter_none.setVisibility(View.VISIBLE);
btn_filter_topic.setVisibility(View.VISIBLE);
btn_filter_rating.setVisibility(View.VISIBLE);
}
if (idList.size() == 0) {
txtNoFavoritesYet.setVisibility(View.VISIBLE);
listViewFavorites.setVisibility(View.GONE);
} else {
txtNoFavoritesYet.setVisibility(View.GONE);
listViewFavorites.setVisibility(View.VISIBLE);
runOnUiThread(new Runnable() {
public void run() {
btn_filter_none.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
caseSelection = 0;
FavoriteProvider.getInstance().setCurrentFavoriteListStateDirty(true);
toggleButtonStates(v.getId());
updateUI();
}
});
btn_filter_topic.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
caseSelection = 1;
TopicFilterFavDialog tfFavDialog = new TopicFilterFavDialog(FavoriteActivity.this, FavoriteActivity.this, v
.getId());
tfFavDialog.show();
}
});
btn_filter_rating.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
caseSelection = 1;
RatingFilterFavDialog ratDialog = new RatingFilterFavDialog(FavoriteActivity.this, FavoriteActivity.this, v
.getId());
ratDialog.show();
}
});
}
});
}
}
// init listview displaying with data loaded step by step
currentFavoritesArrayAdapter = new FavoriteArrayAdapter(FavoriteActivity.this, FavoriteActivity.this, R.layout.favorite_list_entry,
currentFavorites);
listViewFavorites.setAdapter(currentFavoritesArrayAdapter);
currentFavoritesArrayAdapter.notifyDataSetChanged();
} catch (Exception exception) {
// silent catch because activity could be closed meanwhile
Log.i(TAG, "silent exception catch in onPostExecute: " + exception.getMessage());
}
}
}
/**
* Update UI
*/
public void updateUI() {
LoadDataTask ldTask = new LoadDataTask();
ldTask.execute();
if (currentFavoritesArrayAdapter != null)
currentFavoritesArrayAdapter.notifyDataSetChanged();
}
#Override
protected void onResume() {
super.onResume();
updateUI();
}
private class ListMoreItemsTask extends AsyncTask<Void, Void, LoudmouthException> {
#Override
protected LoudmouthException doInBackground(Void... arg0) {
LoudmouthException exception = null;
loadingMore = true;
// reset loading values if adapter was reseted
if (currentFavoritesArrayAdapter.getCount() == 0)
maximumDataLoadedYet = Configuration.LOADED_ITEMS_ON_LIST_AT_ONCE;
// Get value of Configuration.LOADEDITEMSONLISTATONCE new listitems
for (; currentDataLoaded < maximumDataLoadedYet && currentDataLoaded < idList.size(); currentDataLoaded++) {
// Fill the list with new information
currentFavorites.add(FavoriteProvider.getInstance().getFavorite(idList.get(currentDataLoaded)));
}
maximumDataLoadedYet += itemsPerLoading;
// Done loading more.
loadingMore = false;
return exception;
}
protected void onPostExecute(LoudmouthException result) {
if (result == null) {
// Tell to the adapter that changes have been made, this will
// cause
// the list to refresh
currentFavoritesArrayAdapter.notifyDataSetChanged();
// remove loading view when maximum data is reached
if (currentFavorites.size() == idList.size()) {
listViewFavorites.removeFooterView(footerView);
}
}
}
}
public void toggleButtonStates(int viewId) {
// set clicked button as selected
if (viewId != 0) {
switch (viewId) {
case R.id.btn_fav_filter_none:
btn_filter_none.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.filter_neuste_selected), null, null,
null);
btn_filter_none.setTextColor(getResources().getColor(color.black));
break;
case R.id.btn_fav_filter_topic:
btn_filter_topic.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.filter_themen_selected), null, null,
null);
btn_filter_topic.setTextColor(getResources().getColor(color.black));
break;
case R.id.btn_fav_filter_rating:
btn_filter_rating.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.filter_rating_selected), null, null,
null);
btn_filter_rating.setTextColor(getResources().getColor(color.black));
break;
default:
Log.d("TAG", "No View with id: " + viewId);
}
}
// if previews Button exists and wasn't the same button set the old
// one
// to selected false
if (oldBtnViewId != 0 && oldBtnViewId != viewId) {
// set clicked button as not selected
switch (oldBtnViewId) {
case R.id.btn_fav_filter_none:
btn_filter_none.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.filter_neuste), null, null, null);
btn_filter_none.setTextColor(getResources().getColor(R.color.font_grey));
break;
case R.id.btn_fav_filter_topic:
btn_filter_topic.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.filter_themen), null, null, null);
btn_filter_topic.setTextColor(getResources().getColor(R.color.font_grey));
break;
case R.id.btn_fav_filter_rating:
btn_filter_rating.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.filter_rating), null, null, null);
btn_filter_rating.setTextColor(getResources().getColor(R.color.font_grey));
break;
default:
Log.d("TAG", "No View with id: " + viewId);
}
}
oldBtnViewId = viewId;
}
}

It fails because you modify currentFavorite in ListMoreItemsTasks, which is the underlying list that backs your adapter.
The modification is made in doInBackground, which is not the UI Thread.
I would recommend using publishProgress to receive the data to add on the UI Thread and add it to the adapter there (via the adapter's method, not the array, which you should probably not keep after having created the adapter)
edit
Replace
private class ListMoreItemsTask extends AsyncTask<Void, Void, LoudmouthException> {
with
private class ListMoreItemsTask extends AsyncTask<Void, Favorite, LoudmouthException> {
so progresses are Favorite elements, then
currentFavorites.add(FavoriteProvider.getInstance().getFavorite(idList.get(currentDataLoaded)));
with
publishProgress(FavoriteProvider.getInstance().getFavorite(idList.get(currentDataLoaded));
plus insert in the AsyncTask the onProgressUpdate :
onProgressUpdate(Favorite... values) {
currentFavorites.add(values[0]);
currentFavoritesArrayAdapter.notifyDataSetChanged();
}

Related

Calling a method from Fragment inside my class (AsyncTask class to be specific) [duplicate]

I am trying to implement callback between AsyncTask and Fragment but cannot find correct info how to do it. The issue is that all callback implementations are between activity and asynctask but I need between fragment and asynctask. Could someone give me small working example how to implement it without activity.
My action structure: Fragment call DialogFragment -> choose something and send server request to async task -> async task process everything and update view and some variables. My main problem is that I call prepareData() only once in onCreate and when I walk between other fragment and returns come back I see old data. That is to say there is not enough to update only view in onPost of asynctask. It will be good to have callback which will update the whole variables.
public class TermsAndConditionsFragment extends SherlockFragment implements OnClickListener, OnTouchListener, OnItemClickListener, onTaskListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fm = getSherlockActivity().getSupportFragmentManager();
prepareData();
}
public void prepareData() {
termsAndConditionsM = new TermsAndConditionsManager(getSherlockActivity());
termsAndConditions = termsAndConditionsM.getTermsAndConditions();
if (termsAndConditions != null) {
int totalPayments = Integer.valueOf(termsAndConditions.get(ServerAPI.NO_OF_PAYMENTS));
if (totalPayments > 0) {
paymentsData = termsAndConditionsM.getpayments();
if (paymentsData != null) {
payments = new ArrayList<Payment>();
for (int i = 1; i <= totalPayments; i++) {
paymentValues = new Payment();
paymentValues.setPaymentID(Integer.valueOf(paymentsData.get(ServerAPI.PAYMENT_NO + "_" + i)));
paymentValues.setPaymentDate(paymentsData.get(ServerAPI.PAYMENT_DATE + "_" + i));
paymentValues.setPaymentTotalAmount(paymentsData.get(ServerAPI.PAYMENT_TOTAL + "_" + i));
payments.add(paymentValues);
}
}
}
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = init(inflater, container);
if (payments != null || termsAndConditions != null)
updateTermsAndConditionsView();
return rootView;
}
private View init(LayoutInflater inflater, ViewGroup container) {
rootView = inflater.inflate(R.layout.fragment_terms_and_conditions, container, false);
...
return rootView;
}
public void updateTermsAndConditionsView() {
etHowMuch.setText("£" + termsAndConditions.get(ServerAPI.AMOUNT_OF_CREDIT));
etForHowLong.setText(Helpers.ConvertDays2Date(Integer.valueOf(termsAndConditions.get(ServerAPI.TERM_OF_AGREEMENT_IN_DAYS))));
PaymentAdapter adapter = new PaymentAdapter(getSherlockActivity(), R.layout.custom_loan_item, payments);
lvPayments.setAdapter(adapter);
tvNoOfPayments.setText(termsAndConditions.get(ServerAPI.NO_OF_PAYMENTS));
tvFirstPayment.setText(termsAndConditions.get(ServerAPI.FIRST_PAYMENT_DATE));
tvTotalRepayable.setText("£" + termsAndConditions.get(ServerAPI.TOTAL_REPAYABLE));
}
#Override
public void onClick(View v) {
ft = fm.beginTransaction();
howMuch = etHowMuch.getText().toString();
forHowLong = etForHowLong.getText().toString();
switch (v.getId()) {
case R.id.etHowMuch:
f = new NumberPaymentsPickerFragment();
args = new Bundle();
args.putInt(Const.HOW_MUCH, Integer.valueOf(howMuch.replace("£", "")));
args.putDouble(ServerAPI.PAYMENT_STEP, Const.PAYMENT_STEP);
args.putString(Const.STATE, ServerAPI.TERMS_AND_CONDITIONS);
f.setArguments(args);
f.setTargetFragment(this, DIALOG_FRAGMENT);
f.show(getActivity().getSupportFragmentManager(), Const.HOW_MUCH);
break;
case R.id.etForHowLong:
f = new NumberPaymentsPickerFragment();
args = new Bundle();
args.putInt(Const.FOR_HOW_LONG, Integer.valueOf(Helpers.ConvertDate2Days(forHowLong)));
args.putDouble(ServerAPI.PAYMENT_STEP, Const.PAYMENT_STEP);
args.putString(Const.STATE, ServerAPI.TERMS_AND_CONDITIONS);
f.setArguments(args);
f.setTargetFragment(this, DIALOG_FRAGMENT);
f.show(getActivity().getSupportFragmentManager(), Const.FOR_HOW_LONG);
break;
case R.id.tvPersonalDetails:
sfm.saveCurFragment(ServerAPI.PERSONAL_DETAILS, 0);
ft.replace(android.R.id.content, new PersonalDetailsFragment(), ServerAPI.PERSONAL_DETAILS).addToBackStack(null).commit();
break;
case R.id.tvAgreementDetails:
sfm.saveCurFragment(ServerAPI.AGREEMENT_DETAILS, 0);
ft.replace(android.R.id.content, new AgreementDetailsFragment(), ServerAPI.AGREEMENT_DETAILS).addToBackStack(null).commit();
break;
case R.id.bApply:
break;
}
#Override
public void onUpdateData() {
Log.d(TAG, "Update data");
}
}
DialogFragment:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
...
}
public Dialog onCreateDialog(Bundle savedInstanceState) {
...
return createDialog(v, R.string.for_how_long, etHowMuch, etForHowLong, etPromotionCode);
}
return null;
}
private Dialog createDialog(View view, int titleResID, final EditText howMuchField, final EditText forHowLongField, final EditText promotionCodeField) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(titleResID);
builder.setView(view);
builder.setPositiveButton(R.string.set, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
doShowProgress();
}
private void doShowProgress() {
ExecuteServerTaskBackground task = new
ExecuteServerTaskBackground(getActivity());
task.action = ServerAPI.GET_TERMS_AND_CONDITIONS;
onTaskListener listener = new onTaskListener() {
#Override
public void onUpdateData() {
Log.d(TAG, "Updaaate");
}
};
task.setListener(listener);
task.args = args;
task.execute();
}
}).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
return builder.create();
}
AsyncTask:
onTaskListener mListener;
public interface onTaskListener {
void onUpdateData();
}
public void setListener(onTaskListener listener){
mListener = listener;
}
public ExecuteServerTaskBackground(Activity activity) {
this.mActivity = activity;
this.mContext = activity.getApplicationContext();
}
#Override
protected void onPreExecute() {
pb = (ProgressBar) mActivity.findViewById(R.id.progressBar1);
pb.setVisibility(View.VISIBLE);
}
#Override
protected Void doInBackground(Void... params) {
ServerAPI server = new ServerAPI(mContext);
if (!args.isEmpty())
server.serverRequest(action, args);
else
server.serverRequest(action, null);
return null;
}
#Override
protected void onPostExecute(Void result) {
mListener.onUpdateData();
//There is I just update view but how to update whole variables throughtout callback?
// tvNoOfPayments = (TextView) mActivity.findViewById(R.id.tvNoOfPaymentsValue);
// tvFirstPayment = (TextView) mActivity.findViewById(R.id.tvFirstPaymentValue);
// tvTotalRepayable = (TextView) mActivity.findViewById(R.id.tvTotalRepayableValue);
//
// lvPayments = (ListView) mActivity.findViewById(R.id.lvData);
//
// termsConditionsM = new TermsAndConditionsManager(mContext);
//
// termsAndConditions = termsConditionsM.getTermsAndConditions();
//
// int totalPayments = Integer.valueOf(termsAndConditions.get(ServerAPI.NO_OF_PAYMENTS));
//
// if (totalPayments > 0) {
// if (termsAndConditions != null) {
// tvNoOfPayments.setText(termsAndConditions.get(ServerAPI.NO_OF_PAYMENTS));
// tvFirstPayment.setText(termsAndConditions.get(ServerAPI.FIRST_PAYMENT_DATE));
// tvTotalRepayable.setText("£" + termsAndConditions.get(ServerAPI.TOTAL_REPAYABLE));
// }
//
// paymentsData = termsConditionsM.getpayments();
//
// if (paymentsData != null) {
// Log.d(TAG, paymentsData.toString());
//
// payments = new ArrayList<Payment>();
//
// for (int i = 1; i <= totalPayments; i++) {
// paymentValues = new Payment();
// paymentValues.setPaymentID(Integer.valueOf(paymentsData.get(ServerAPI.PAYMENT_NO + "_" + i)));
// paymentValues.setPaymentDate(paymentsData.get(ServerAPI.PAYMENT_DATE + "_" + i));
// paymentValues.setPaymentTotalAmount(paymentsData.get(ServerAPI.PAYMENT_TOTAL + "_" + i));
// payments.add(paymentValues);
// }
//
// PaymentAdapter adapter = new PaymentAdapter(mContext, R.layout.custom_loan_item, payments);
// lvPayments.setAdapter(adapter);
// }
//
}
pb.setVisibility(View.GONE);
super.onPostExecute(result);
}
Without taking your code in consideration I will post the most essential to make a functional callback.
TestFragment:
public class TestFragment extends Fragment {
/* Skipping most code and I will only show you the most essential. */
private void methodThatStartsTheAsyncTask() {
TestAsyncTask testAsyncTask = new TestAsyncTask(new FragmentCallback() {
#Override
public void onTaskDone() {
methodThatDoesSomethingWhenTaskIsDone();
}
});
testAsyncTask.execute();
}
private void methodThatDoesSomethingWhenTaskIsDone() {
/* Magic! */
}
public interface FragmentCallback {
public void onTaskDone();
}
}
TestAsyncTask:
public class TestAsyncTask extends AsyncTask<Void, Void, Void> {
private FragmentCallback mFragmentCallback;
public TestAsyncTask(FragmentCallback fragmentCallback) {
mFragmentCallback = fragmentCallback;
}
#Override
protected Void doInBackground(Void... params) {
/* Do your thing. */
return null;
}
#Override
protected void onPostExecute(Void result) {
mFragmentCallback.onTaskDone();
}
}

Recycler View Adapter: Best practice to notify that data set has updated

I am trying to make a volley request to api's url. The problem is that data is fetched appropriately, but every time data set updates, the whole recycler view refreshes again and begins from the start; in the docs it is mentioned that use notifyDataSetChanged() as the last resort. How can it be avoided and what are the best practices for such tasks? Any design pattern that should be followed?
Here is the Fragment Code :-
public class PageFragment extends Fragment implements SortDialogCallback {
private static final String TAG = PageFragment.class.getSimpleName();
/**
* Unsplash API, By Default=10
*/
private static final String per_page = "10";
public static String order_By;
/**
* Unsplash API call parameter, By Default=latest
* Change it in Pager Fragment, based on Tab tapped
*/
RecyclerView recyclerView;
ImageAdapter imageAdapter;
GridLayoutManager layoutManager;
EndlessRecyclerViewScrollListener scrollListener;
FloatingActionButton actionButton;
FrameLayout no_internet_container;
Bundle savedInstanceState;
// Attaching Handler to the main thread
Handler handler = new Handler();
boolean shouldHandlerRunAgain = true;
private ArrayList<DataModel> model;
/**
* Handler is attached to the Main Thread and it's message queue, because it is the one who created it.
* <p>
* Handler is responsible for checking every second that are we connected to internet, and if we are, then :-
* 1. Then we remove empty view
* 2. Make the network call
* 3. Stop handler from posting the code again using shouldHandlerRunAgain variable
* 3.1 This is a kill switch otherwise handler will post the runnable again and again to the message queue, which will be executed as soon as it reaches the looper
* <p>
* Handler removeCallbacks is used to remove all the pending runnables in the Message Queue
*/
Runnable job = new Runnable() {
#Override
public void run() {
Log.d(TAG, "Thread run " + job.hashCode());
swapViews();
if (shouldHandlerRunAgain)
handler.postDelayed(job, HANDLER_DELAY_TIME);
}
};
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("ORDER_BY", order_By);
}
#Override
public void onResume() {
super.onResume();
if (handler != null)
handler.post(job);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "Starting Handler");
layoutManager = new GridLayoutManager(getContext(), 2);
scrollListener = new EndlessRecyclerViewScrollListener(layoutManager) {
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
Log.w(TAG, "On load More Called with page number " + page);
loadDataUsingVolley(page, order_By);
}
};
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.search:
Toast.makeText(getContext(), "Async task", Toast.LENGTH_SHORT).show();
break;
default:
Toast.makeText(getContext(), "Invalid Options", Toast.LENGTH_SHORT).show();
}
return true;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_page_fragment, menu);
}
private void swapViews() {
if (detectConnection(getContext()) == false) {
recyclerView.setVisibility(View.INVISIBLE);
actionButton.setVisibility(View.INVISIBLE);
no_internet_container.setVisibility(View.VISIBLE);
} else {
Log.d(TAG, "Removing callbacks from handler and stopping it from posting");
shouldHandlerRunAgain = false;
handler.removeCallbacks(job, null);
handler = null;
recyclerView.setVisibility(View.VISIBLE);
actionButton.setVisibility(View.VISIBLE);
no_internet_container.setVisibility(View.INVISIBLE);
if (savedInstanceState != null) {
loadDataUsingVolley(1, savedInstanceState.getString("ORDER_BY"));
} else {
order_By = "latest";
loadDataUsingVolley(1, order_By);
}
}
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, final Bundle savedInstanceState) {
this.savedInstanceState = savedInstanceState;
View view = inflater.inflate(R.layout.fragment_page, container, false);
actionButton = (FloatingActionButton) view.findViewById(R.id.sort_button);
actionButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
SortDialog sortDialog = new SortDialog();
sortDialog.setTargetFragment(PageFragment.this, 911);
sortDialog.show(getChildFragmentManager(), "sortfragment");
}
});
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
recyclerView.setHasFixedSize(true);
no_internet_container = (FrameLayout) view.findViewById(R.id.no_internet_container);
return view;
}
void setUpRecyclerView() {
if (imageAdapter == null)
imageAdapter = new ImageAdapter(getContext(), (model==null)?new ArrayList<DataModel>():model);
recyclerView.setAdapter(imageAdapter);
recyclerView.setLayoutManager(layoutManager);
recyclerView.addOnScrollListener(scrollListener);
}
void loadDataUsingVolley(int page, String order_by) {
final ProgressDialog dialog = ProgressDialog.show(getContext(), "Wallser", "Loading");
RequestQueue requestQueue = Volley.newRequestQueue(getContext());
String URL = "https://api.unsplash.com/photos/?page=" + page + "&client_id=" + api_key + "&per_page=" + per_page + "&order_by=" + order_by;
Log.d(TAG, URL);
JsonArrayRequest objectRequest = new JsonArrayRequest(Request.Method.GET, URL, null, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray array) {
int len = array.length();
if (model == null)
model = new ArrayList<>();
for (int i = 0; i < len; i++) {
try {
JSONObject object = array.getJSONObject(i);
String id = object.getString("id");
JSONObject object1 = object.getJSONObject("urls");
String imageURL = object1.getString("regular");
JSONObject object2 = object.getJSONObject("links");
String downloadURL = object2.getString("download");
model.add(new DataModel(imageURL, downloadURL, id));
Log.d(TAG, downloadURL);
} catch (JSONException e) {
e.printStackTrace();
}
}
if (dialog != null) {
dialog.dismiss();
}
Log.d(TAG, model.size() + "");
setUpRecyclerView();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
dialog.dismiss();
Toast.makeText(getContext(), "" + error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
requestQueue.add(objectRequest);
}
/**
* marks a new network call to Unsplash API
* Thus, set model array list to null, to start fresh.
* as model is reset, ImageAdapter also needs to start fresh.
*
* #param order_by
*/
#Override
public void onDialogFinish(String order_by) {
model = null;
imageAdapter=null;
order_By = order_by;
loadDataUsingVolley(1, order_By);
}
}

ConcurrentModificationException Android AsyncTask

The updateUserSection method is called in a SearchView's OnQueryTextChange. When I type fast into the SearchView, I get a ConcurrentModificationException (it works if I type slowly). I can't tell what causes this problem.
public void updateUserSection(String text){
relevantUsers.clear();
for(String key: allUsers.keySet()) {
if ((key.toLowerCase().contains(text.toLowerCase()))) {
relevantUsers.put(key, allUsers.get(key));
}
}
// instance is a private reference to this AddTrailsAct, probably doesn't matter
instance.generateButtons();
}
private synchronized void generateButtons() {
usersLayout.removeAllViewsInLayout();
// make the first row
currentRow = new LinearLayout(getApplicationContext());
// make it pretty
makePretty(currentRow);
// add the first row
usersLayout.addView(currentRow);
// limits 3 buttons per row
rowIndex = 0;
// iterate through relevantUsers and try to find pictures
(new SetButtonTask(relevantUsers)).execute();
}
private class SetButtonTask extends AsyncTask<Void, Void, Void> {
private HashMap<String, String> userList;
private HashMap<String, Bitmap> nameToBitmap = new HashMap<String, Bitmap>();
public SetButtonTask(HashMap<String, String> userList) {
this.userList = userList;
}
#Override
protected Void doInBackground(Void... v) {
for (String name: userList.keySet()) {
putToBitmap(name, userList.get(name));
}
return null;
}
#Override
protected void onPostExecute(Void v) {
// THE RUNTIME ERROR POINTS TO THE LINE BELOW
for (String name: nameToBitmap.keySet()) {
instance.addToUsersLayout(nameToBitmap.get(name), name);
}
}
private void putToBitmap(String name, String id) {
try {
nameToBitmap.put(name, Bitmap.createScaledBitmap(
BitmapFactory.decodeStream((new URL("https://graph.facebook.com/" +
id +
"/picture?type=large")).openConnection().getInputStream()),
200,
200,
true));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
// add button to the usersLayout
private synchronized void addToUsersLayout(final Bitmap profPicBitmap, final String name) {
runOnUiThread(new Runnable() {
#Override
public void run() {
numTasks++;
Log.d("myTag","the UiThread has " + numTasks + " threads running");
// the button we'll be building
final ImageButton b = new ImageButton(getApplicationContext());
b.setImageBitmap(profPicBitmap);
// touch animation
b.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// set filter when pressed
if (event.getAction() == MotionEvent.ACTION_DOWN) {
b.setColorFilter(new
PorterDuffColorFilter(getResources().getColor(R.color.skyBlue),
PorterDuff.Mode.MULTIPLY));
}
// handle "click"
if (event.getAction() == MotionEvent.ACTION_UP) {
Log.d("myTag", "imageButton pressed");
// add the trail
((Project_18) getApplication()).getMe().addTrail(fb, relevantUsers.get(name));
}
// remove filter on release/cancel
if (event.getAction() == MotionEvent.ACTION_UP ||
event.getAction() == MotionEvent.ACTION_CANCEL) {
b.clearColorFilter();
}
return true;
}
});
// contains button and name of the user
LinearLayout buttonLayout = new LinearLayout(getApplicationContext());
// make button look good and add to buttonLayout
makePretty(b, name, buttonLayout);
// add to buttonMap
buttonMap.put(name, buttonLayout);
// add buttonLayout to row
currentRow.addView(buttonLayout);
// row index handling
if (rowIndex < 2) {
rowIndex ++;
} else {
// reset index
rowIndex = 0;
// make new row
currentRow = new LinearLayout(getApplicationContext());
makePretty(currentRow);
// add new row to the layout
usersLayout.addView(currentRow);
}
numTasks--;
}
});
}

How to add item from bottom to top after Pull refresh ListView?

This is my class for Print List-view in Android
public class ChatActivity extends FragmentActivity implements OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.act_chat);
listview = (PullToRefreshListView) findViewById(R.id.listView);
editMsg = (EditText) findViewById(R.id.txt_inputText);
mLastSeenTime = (TextView) findViewById(R.id.lastSeenDatetextview);
sendMsgBut = (ImageView) findViewById(R.id.btn_Send);
recciverImage = (ImageView) findViewById(R.id.recciverImage);
backbutton = (ImageView) findViewById(R.id.contact_btnMenu);
sendMsgBut.setOnClickListener(this);
recciverImage.setOnClickListener(this);
backbutton.setOnClickListener(this);
arrChatlist = dbHelper.fetchChatHistory(member_id, reccvierid);
chatList.addAll(arrChatlist);
chatAdapter = new ChatAdapter(this, chatList);
listview.setAdapter(chatAdapter);
listview.setSelection(listview.getAdapter().getCount() - 1);
dbHelper.updateIsRead(reccvierid);
#Override
public void onClick(View arg0) {
switch (arg0.getId()) {
case R.id.btn_Send:
if (TextUtils.isEmpty(editMsg.getText().toString()))
return;
else {
mChatService.SendMessage(Integer.parseInt(member_id), Integer
.parseInt(reccvierid), editMsg.getText().toString());
Chat chat = new Chat();
chat.setMessage(editMsg.getText().toString());
chat.setRecieverID(reccvierid);
chat.setSenderID(member_id);
chatList.add(chat);
dbHelper.addMessage(chat);
chatAdapter.notifyDataSetChanged();
editMsg.setText("");
System.out.println("Messae : " + chat.getMessage());
listview.setSelection(listview.getAdapter().getCount() - 1);
}
break;
default:
break;
}
}
// ****************************** For Location Name *********|||||||
private class SyncStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
switch (intent.getIntExtra(BroadcastNotifier.EXTENDED_DATA_STATUS,
BroadcastNotifier.STATE_ACTION_COMPLETE)) {
case BroadcastNotifier.STATE_ACTION_MESSAGE_RECEVED:
boolean isCurrentUser = false;
Chat chat = (Chat) intent
.getSerializableExtra(BroadcastNotifier.EXTENDED_CHAT_RECEIVED);
for (Datamodel model : HomeActivity.arrModel) {
if (("~" + model.getPhoneNumber()).equals(chat
.getSenderName())) {
chat.setSenderID(model.getId());
chat.setSenderName(model.getContactName());
}
if (chat.getConnectionId().equals(ConnectionId)) {
isCurrentUser = true;
}
}
if (isCurrentUser) {
dbHelper.addMessage(chat);
chatList.add(chat);
chatAdapter.notifyDataSetChanged();
listview.setSelection(listview.getAdapter().getCount() - 1);
} else {
mChatService.createNotification(chat);
}
break;
}
}
}
//-------- SigNal R Method------------------------\\\
public ChatEventHandler mChatHandler = new ChatEventHandler() {
String previousMessage = "";
#Override
public void UpdateMessage(String message, String sendername,
long senderId) {
if (previousMessage != message) {
System.out.println("new message: " + message + " sendername:"
+ sendername);
Chat chat = new Chat();
chat.setMessage(message);
chat.setRecieverID(member_id);
chat.setSenderID("" + senderId);
chat.setSenderName(sendername);
chat.setIsUnread(false);
dbHelper.addMessage(chat);
chatList.add(chat);
previousMessage = message;
listview.setSelection(listview.getAdapter().getCount() - 1);
}
runOnUiThread(new Runnable() {
#Override
public void run() {
chatAdapter.notifyDataSetChanged();
listview.setSelection(listview.getAdapter().getCount() - 1);
}
});
}
class loadmessge extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
chatAdapter.notifyDataSetChanged();
listview.onRefreshComplete();
super.onPostExecute(result);
}
}
}
This is my XML of listview:
<com.lociiapp.PullToRefreshListView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="150dp"
android:stackFromBottom="true"
android:transcriptMode="normal" >
I am able to display list-view in Android. Using chatadapter I have applied pull to refresh listview to load data 1 - 1 item in listview after refreshing but its working fine but I want to display that after refresh last item come in last in adapter and first item come in top adapter like tat way but I am unable to do that please see my screen you ll better understand what am trying to do please suggest how I will achieve.
.
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
chatAdapter.notifyDataSetChanged();
// loadPopupData(context, listView, emptyView,i);
listview.setSelection(listview.getAdapter().getCount() - 1);
listview.onRefreshComplete();
super.onPostExecute(result);
}
}
replace this code and Enjoy!!!
Append your chat messages at the end of your list, or implement getItem to return items reversed (length - position).
Looking at your code, I think the first option is the easiest:
public void addMessage(Chat chat) {
values.add(values.size()-1, chat);
this.notifyDataSetChanged();
}

gridview changing position automatically when notifiedDatasetChangedCalled?

here ia an application where i displaying some text with image background but it got changes position
automatically when notifieddatasetchanged() is called, please help me how to fixed it constant position ,below is my code. thanks you
public View getView(final int position, View convertView, ViewGroup parent) {
//ImageView imageView;
View v;
TextView tv = null;
if (convertView == null) {
LayoutInflater li = getLayoutInflater();
v = li.inflate(R.layout.show_table_gridview, null);
tv = (TextView)
v.findViewById(R.id.tab_num);
tv.setText(""+position+1));
tv.setTextColor(Color.BLACK);
HashMap<Integer, List<OrderlistData>> orederMap1 = ConText
.getTotlaMap();
List<OrderlistData> orderlist1 = new ArrayList<OrderlistData>();
Set<Integer> keySet1 = orederMap1.keySet();
if (keySet1.contains(position))
orderlist1 = orederMap1.get(position);
if (orderlist1.isEmpty()){
}
else{
tv.setBackgroundColor(Color.CYAN);
}
}
else {
v = convertView;
}
/**
* Code for changing background if data is content
*/
return v;
}
here is the code for updating gridview in every 20sec
//=============Refreshing gridview ==============
private class UpdateGridview extends AsyncTask<Context, Integer, String>
{
#Override
protected String doInBackground(Context... params) {
int i = 0;
while (i < 10) {
try {
Thread.sleep(30000);
Message msg = handler.obtainMessage();
handler.sendMessage(msg);
i++;
} catch (Exception e) {
Log.i("makemachine", e.getMessage());
}
}
return "COMPLETE!";
}
private final Handler handler = new Handler() {
public void handleMessage(Message msg) {
getCurrent_orderlist_StatusFromServer();
gridadapter.notifyDataSetChanged();
System.out
.println("i called notifyDataSetChanged()=======================");
}
};
// -- gets called just before thread begins
#Override
protected void onPreExecute()
{
Log.i( "makemachine", "onPreExecute()" );
super.onPreExecute();
}
#Override
protected void onProgressUpdate(Integer... values)
{
super.onProgressUpdate(values);
}
// -- called if the cancel button is pressed
#Override
protected void onCancelled()
{
super.onCancelled();
Log.i( "makemachine", "onCancelled()" );
}
// -- called as soon as doInBackground method completes
// -- notice that the third param gets passed to this method
#Override
protected void onPostExecute( String result )
{
super.onPostExecute(result);
Log.i( "makemachine", "onPostExecute(): " + result );
}
}
It's happening like this because you are giving the if condition. It's because at the first time only convertview gets assigned. For the second time it's not entering into the if condition.
And you have to execute the codes within the if. So just remove the if condition, it will work properly.

Categories

Resources