I have a list that I sending to a background asynctask object to do somework on. I am also sending a custom list adapter to be able to populate my list in the background. But the list returns zero and it seems like nothing is added to it as its size remains zero. I know because i debuged it. my custom list adapter works just fine though and creates the list perfectly.
Here's my code.
Fragment_Events.java
public class Fragment_Events extends android.support.v4.app.Fragment implements AdapterView.OnItemClickListener {
FragmentController controller;
ListView eventsListView;
List<Event> events;
EventsListAdapter eventsListAdapter;
public Fragment_Events() {
// Required empty public constructor
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
controller = (FragmentController) getActivity();
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
eventsListView = (ListView)getActivity().findViewById(R.id.listView_events);
events = new ArrayList<Event>();//SIZE REMAINS 0 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
eventsListAdapter = new EventsListAdapter(getActivity(),R.layout.list_events,events);
eventsListView.setAdapter(eventsListAdapter);
DLEvents.init(events,eventsListAdapter);
Bundle sendingBundle = new Bundle();
ArrayList<String> eventNames = new ArrayList<String>();
sendingBundle.putStringArrayList(AppUtils.EVENT_NAMES,eventNames);
controller.sendData(sendingBundle);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_events, container, false);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
}
}
DLEvents.java
public class DLEvents {
public static final String EVENTS_OBJECT = "Events";
public static final String NAME_COLUMN = "name";
public static final String DESC_COLUMN = "description";
public static final String DATE_COLUMN = "date";
public static final String FOLL_COLUMN = "followers";
public static final String TC_COLUMN = "ticketCount";
public static final String IMAGE_COLUMN = "image";
public static void init(List<Event> list,EventsListAdapter eventsListAdapter){
DownLoadData downLoadData = new DownLoadData(list,eventsListAdapter);
downLoadData.execute();
}
public static class DownLoadData extends AsyncTask<Void,Event,Void>{
public List<Event>events;
public EventsListAdapter eventsListAdapter;
public DownLoadData(List<Event>events, EventsListAdapter eventsListAdapter) {
super();
this.events = events;
this.eventsListAdapter = eventsListAdapter;
}
public Bitmap byteArrayToBitmap(byte[] bytes){
Bitmap temp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
return temp;
}
#Override
protected Void doInBackground(Void... params) {
ParseQuery<ParseObject> query = ParseQuery.getQuery(EVENTS_OBJECT);
try {
for(ParseObject tempParseObject: query.find()){
String tempName = tempParseObject.getString(NAME_COLUMN);
String tempDesc = tempParseObject.getString(DESC_COLUMN);
String tempID = tempParseObject.getObjectId();
int tempTC = tempParseObject.getInt(TC_COLUMN);
ParseFile tempPF = (ParseFile)tempParseObject.get(IMAGE_COLUMN);
Bitmap tempBM = byteArrayToBitmap(tempPF.getData());
int tempFoll = tempParseObject.getInt(FOLL_COLUMN);
Event event = new Event(tempName,tempDesc,null,tempID,tempTC,tempBM,tempFoll);
publishProgress(event);
}
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onProgressUpdate(Event... values) {
super.onProgressUpdate(values);
//events.add(values[0]); //I commented it out because it causes my listview to have duplicates, if you can shed some light on this too , I'd appreciate it. Commenting it back in also doesn't affect the size of my list
eventsListAdapter.add(values[0]);
}
}
}
Asynctask seems to be working fine as the list is populated with no issues. but the list is still at a size 0 event though it's updated in the UI thread via onprogressreport
the adapter populates the list perfectly! that isn't the issue. The event's list that is being passed on to asynctask remains at a zero size. No item is being added. That is the issue.
You have to call notifyDataSetChanged() to update the adapter and let it know there is new data.
#Override
protected void onProgressUpdate(Event... values) {
super.onProgressUpdate(values);
//events.add(values[0]); //I commented it out because it causes my listview to have duplicates, if you can shed some light on this too , I'd appreciate it. Commenting it back in also doesn't affect the size of my list
eventsListAdapter.add(values[0]);
eventsListAdapter.notifyDataSetChanged();
}
You need to ask adapter to refresh itself once data is available or its data is modified.
Do this
#Override
protected void onProgressUpdate(Event... values) {
super.onProgressUpdate(values);
events.add(values[0]);
eventsListAdapter.add(values[0]);
eventsListAdapter.notifyDataSetChanged();
}
Related
I have an Android Fragment (in Java) that displays recyclerview. Now I would like to read the data for the items in the recyclerview from a firebase database. They should be stored into an array list orderList. For this purpose, I would like to use LiveData and a ViewModel because I read several times that this is the recommended way of implementing it. Further, I would like the Fragment to update the recyclerview automatically whenever new data is stored in the firebase database.
I tried to follow the steps that are described in the offical Firebase Blog (https://firebase.googleblog.com/2017/12/using-android-architecture-components.html) but unfortunately the result is always an empty list. No elements are being displayed altough there are some relevant entries in the database that should be returned and displayed. The implementation of the recyclerview itself is correct (I checked that by manually adding items into the recylcerview).
Here is my Fragment that holds the recyclerview:
public class FR_Orders extends Fragment {
private FragmentOrdersBinding binding;
//Define variables for the RecyclerView
private RecyclerView recyclerView_Order;
private RV_Adapter_Orders adapter_Order;
private RecyclerView.LayoutManager layoutManager_Order;
private ArrayList<RV_Item_Order> orderList;
public FR_Orders() {
// Required empty public constructor
}
public static FR_Orders newInstance(String param1, String param2) {
FR_Orders fragment = new FR_Orders();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
orderList = new ArrayList<RV_Item_Order>();
// Obtain a new or prior instance of ViewModel_FR_Orders from the ViewModelProviders utility class.
ViewModel_FR_Orders viewModel = new ViewModelProvider(this).get(ViewModel_FR_Orders.class);
LiveData<DataSnapshot> liveData = viewModel.getDataSnapshotLiveData();
liveData.observe(this, new Observer<DataSnapshot>() {
#Override
public void onChanged(#Nullable DataSnapshot dataSnapshot) {
for(DataSnapshot ds: dataSnapshot.getChildren()) {
if (dataSnapshot != null) {
String drinkName = "";
String drinkSize = "";
String orderDate = "";
String orderStatus = "";
int orderDateInMilliseconds = 0;
int orderID = 0;
int quantity = 0;
int tableNumber = 0;
// update the UI here with values in the snapshot
if( dataSnapshot.child("drinkName").getValue(String.class)!=null) {
drinkName = dataSnapshot.child("drinkName").getValue(String.class);
}
if(dataSnapshot.child("drinkSize").getValue(String.class)!=null) {
drinkSize = dataSnapshot.child("drinkSize").getValue(String.class);
}
if(dataSnapshot.child("orderDate").getValue(String.class)!=null) {
orderDate = dataSnapshot.child("orderDate").getValue(String.class);
}
if(dataSnapshot.child("orderStatus").getValue(String.class)!=null) {
orderStatus = dataSnapshot.child("orderStatus").getValue(String.class);
}
if(dataSnapshot.child("orderDateInMilliseconds").getValue(Integer.class)!=null) {
orderDateInMilliseconds = dataSnapshot.child("orderDateInMilliseconds").getValue(Integer.class);
}
if(dataSnapshot.child("quantity").getValue(Integer.class)!=null) {
quantity = dataSnapshot.child("quantity").getValue(Integer.class);
}
if(dataSnapshot.child("orderID").getValue(Integer.class)!=null) {
orderID = dataSnapshot.child("orderID").getValue(Integer.class);
}
if(dataSnapshot.child("tableNumber").getValue(Integer.class)!=null) {
tableNumber = dataSnapshot.child("tableNumber").getValue(Integer.class);
}
orderList.add(new RV_Item_Order(drinkName, drinkSize, orderDateInMilliseconds, orderDate, tableNumber, orderStatus, quantity, orderID));
;
}
}
}
});
}// end onCreate
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentOrdersBinding.inflate(inflater, container, false);
buildRecyclerView();
return binding.getRoot();
}
public void buildRecyclerView() {
recyclerView_Order = binding.rvDrinksToBeDisplayed;
recyclerView_Order.setHasFixedSize(true);
layoutManager_Order = new LinearLayoutManager(this.getContext());
adapter_Order = new RV_Adapter_Orders(orderList);
recyclerView_Order.setLayoutManager(layoutManager_Order);
recyclerView_Order.setAdapter(adapter_Order);
adapter_Order.setOnItemClickListener(new RV_Adapter_Orders.OnItemClickListener() {
/*
Define what happens when clicking on an item in the RecyclerView
*/
#Override
public void onItemClick(int position) {
}
});
}//end build recyclerView
}//End class
Here is the LiveData class
public class LiveData_FirebaseOrder extends LiveData<DataSnapshot> {
private static final String LOG_TAG = "LiveData_FirebaseOrder";
private final Query query;
private final MyValueEventListener listener = new MyValueEventListener();
public LiveData_FirebaseOrder(Query query) {
this.query = query;
}
public LiveData_FirebaseOrder(DatabaseReference ref) {
this.query = ref;
}
#Override
protected void onActive() {
Log.d(LOG_TAG, "onActive");
query.addValueEventListener(listener);
}
#Override
protected void onInactive() {
Log.d(LOG_TAG, "onInactive");
query.removeEventListener(listener);
}
private class MyValueEventListener implements ValueEventListener {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
setValue(dataSnapshot);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(LOG_TAG, "Can't listen to query " + query, databaseError.toException());
}
}
}
Here is the ViewModel class (the full name of the database is not given because of privacy issues).
public class ViewModel_FR_Orders extends ViewModel {
private static final DatabaseReference ORDERS_REF =
FirebaseDatabase.getInstance("https://....firebasedatabase.app").getReference("/Orders");
private final LiveData_FirebaseOrder liveData = new LiveData_FirebaseOrder(ORDERS_REF);
#NonNull
public LiveData<DataSnapshot> getDataSnapshotLiveData() {
return liveData;
}
}
And here is a screenshot of the Firebase Database that shows that there are some entries in the node Orders that should be returned
Does anyone have an idea what I am making wrong? I tried to stick exactly to the instructions of the offical Firebase Blog.
Update: I found out that the query itself returns the correct datasnapshots but the recyclerview is not built and updated.
I've encountered a problem where I'm trying to pass a some information through to another activity, but the arraylist i'm using to store the data is returning null for the unique identifier i'm using to define each arraylist entry.
This is the class:
import java.util.ArrayList;
public class NutritionLessons {
public NutritionLessons(String lessonName, String lessonCode, String lessonCategory, String lessonContent){
this.lessonName = lessonName;
this.lessonCode = lessonCode;
this.lessonCategory = lessonCategory;
this.lessonContent = lessonContent;
}
private String lessonName;
private String lessonCode;
private String lessonCategory;
private String lessonContent;
public String getLessonName() {
return lessonName;
}
public void setLessonName(String lessonName) {
this.lessonName = lessonName;
}
public String getLessonCode() {
return lessonCode;
}
public void setLessonCode(String lessonCode) {
this.lessonCode = lessonCode;
}
public String getLessonCategory() {
return lessonCategory;
}
public void setLessonCategory(String lessonCategory) {
this.lessonCategory = lessonCategory;
}
public String getLessonContent() {
return lessonContent;
}
public void setLessonContent(String lessonContent) {
this.lessonContent = lessonContent;
}
This is the arraylist in the class
public static ArrayList<NutritionLessons> getLessons(){
ArrayList<NutritionLessons> lessons = new ArrayList<>();
lessons.add(new NutritionLessons("Basic Food Groups", "eee", "Nutrition Essentials",
"blah"));
lessons.add(new NutritionLessons("Food", "abc", "abc", "abc"));
return lessons;
}
And this is the for-each loop i'm using the return the lesson information to another activity
public static NutritionLessons getLessons(String lessonCode){ //lessonCode: null
ArrayList<NutritionLessons> lessons = NutritionLessons.getLessons();
for(final NutritionLessons lesson : lessons){
if(lesson.getLessonCode().equals(lessonCode)){
return lesson;
}
}
return lessons.get(lessons.size()-1);
}
It says that the lessonCode is returning null when being passed through and i'm not sure why, any help would be greatly appreciated!
EDIT: Attaching the places i've called getLesson(String lessonCode) - the idea is to have the information in the arraylist in a recycler view, and a subsequent activity with the lessonContent
recyclerView code:
public class nutritionLessonsList extends AppCompatActivity {
RecyclerView mRecyclerView2;
private nutritionLessonsAdapter mAdapter2;
private RecyclerView.LayoutManager layoutManager2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nutrition_lessons_list);
mRecyclerView2 = findViewById(R.id.recyclerView2);
mRecyclerView2.setHasFixedSize(true);
layoutManager2 = new LinearLayoutManager(this);
mRecyclerView2.setLayoutManager(layoutManager2);
nutritionLessonsAdapter.Listener listener = new nutritionLessonsAdapter.Listener(){
#Override
public void onClick(View view, String lessonCode) {
launchDetailActivity(lessonCode);
}
};
mAdapter2 = new nutritionLessonsAdapter(NutritionLessons.getLessons(), listener);
mRecyclerView2.setAdapter(mAdapter2);
}
private void launchDetailActivity(String message){
Intent intent = new Intent(nutritionLessonsList.this, nutritionLessonPage.class);
intent.putExtra(nutritionLessonPage.INTENT_MESSAGE, message);
startActivity(intent);
}
}
The subsequent lesson page code
public class nutritionLessonPage extends AppCompatActivity {
public static final String INTENT_MESSAGE = "au.edu.unsw.infs3634.gamifiedlearning.intent_message";
TextView mLessonName;
TextView mLesson;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nutrition_lesson_page);
Intent intent = getIntent();
String lessonCode = intent.getStringExtra(INTENT_MESSAGE);
final NutritionLessons nutritionLessons = NutritionLessons.getLessons(lessonCode);
// //Instantiating the view objects
mLessonName = findViewById(R.id.tvLessonName2);
mLesson = findViewById(R.id.tvLesson);
// //Set the content value
mLessonName.setText(nutritionLessons.getLessonName());
mLesson.setText(nutritionLessons.getLessonContent());
}
}
I want to add that, when I click through the recyclerview into the lesson page, only the last element in the array is passed through (ie. lessons.add(new NutritionLessons("Food", "abc", "abc", "abc"));) regardless of which recyclerView row i click
This is regarding your last statement that "regardless of which recyclerView row i click"
That's because the lessonCode that you're passing while calling getLessons() is different and is not present in your arraylist and you've handled that case when lessonCode doesn't match then return the last element -
return lessons.get(lessons.size()-1);
And the last element in your list is this -
new NutritionLessons("Food", "abc", "abc", "abc")
Hope I understood it correctly or correct me if I misunderstood your question.
i have a problem which is making me crazy.
i know how to use "SharedPreferences" in android but i dont know where to put it in my project,like onCreate(),onDestroy() or somewhere else.
*i want to save NoteLab.mNotes in NoteListFragment
*Note.java
package notes.com.example.alireza;
public class Note {
public UUID nId;
public Date nDate;
public String nTitle;
public String nDetails;
public Note(){
nId = UUID.randomUUID();
nDate = new Date();
}
public Date getnDate(){
return nDate;
}
public UUID getnUUID(){
return nId;
}
public String getnTitle() {
return nTitle;
}
public void setnTitle(String nTitle) {
this.nTitle = nTitle;
}
public String getnDetails() {
return nDetails;
}
public void setnDetails(String nDetails) {
this.nDetails = nDetails;
}
}
*NoteLab.java
package notes.com.example.alireza;
import android.content.Context;
import java.util.ArrayList;
import java.util.UUID;
class NoteLab {
public static ArrayList<Note> mNotes;
public static NoteLab noteLab;
public Context mAppContext;
private NoteLab(Context AppContext){
mAppContext = AppContext;
mNotes = new ArrayList<Note>();
}
public static NoteLab get(Context context){
if (noteLab == null){
noteLab = new NoteLab(context.getApplicationContext());
}
return noteLab;
}
public static ArrayList<Note> getNotes(){
return mNotes;
}
public static Note getNote(UUID mId){
for (Note n: mNotes){
if (mId == n.getnUUID()){
return n;
}
}
return null;
}
}
*NoteListFragment.java
package notes.com.example.alireza;
public class NoteListFragment extends ListFragment {
Note note;
ArrayList<Note> notes;
public static Date date;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
notes = NoteLab.get(getActivity()).getNotes();
myArrayAdapter arrayAdapter = new myArrayAdapter(notes);
setListAdapter(arrayAdapter);
}
#Override
public void onStart() {
super.onStart();
View emptyView = getActivity().getLayoutInflater().inflate(R.layout.emptymainlist,null);
((ViewGroup)getListView().getParent()).addView(emptyView);
getListView().setEmptyView(emptyView);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
int checked = 1;
Note c = ((myArrayAdapter)getListAdapter()).getItem(position);
Intent i = new Intent(getActivity(),NoteActivity.class);
i.putExtra("id",c.getnUUID());
i.putExtra(NoteListActivity.EXTRA_DATE,checked);
startActivity(i);
}
//custom arrayList
public class myArrayAdapter extends ArrayAdapter<Note> {
public myArrayAdapter(ArrayList<Note> notes) {
super(getActivity(), 0, notes);
}
#SuppressLint("SetTextI18n")
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = getActivity().getLayoutInflater().inflate(R.layout.notelistfragment_item, null);
}
Note n = getItem(position);
date = n.getnDate();
PersianCalendar persianCalendar = new PersianCalendar();
persianCalendar.setTime(date);
TextView titleTextView = convertView.findViewById(R.id.titleTextView);
titleTextView.setText(n.getnTitle());
TextView detailTextView = convertView.findViewById(R.id.detailsTextView);
detailTextView.setText(n.getnDetails());
TextView dateTextView = convertView.findViewById(R.id.dateTextView);
dateTextView.setText(DateFormat.getDateInstance(DateFormat.FULL).format(date) + " : تاریخ ذخیره ");
return convertView;
}
}
#Override
public void onResume() {
super.onResume();
((myArrayAdapter)getListAdapter()).notifyDataSetChanged();
}
as you understand from the codes, i want to save my mNotes arrayList which is placed in NoteLab.java.there is NoteListActivtiy.java too which is supporting NoteListFragment but i think this can be done in NoteListFragment.
thanks to stackoverflow and everyone who tryes to help me.
You can use Gson library to convert what you want to String then you can get it back again.
Where should you put your code ?? it depends on your business (or requirements).
If you want to pass your array of items to fragment or another activity you can use Gson lib to convert it to string then put it into bundle and pass this bundle to whatever you want. Then in the fragment or the activity you can get this array by Gson also.
Here is an example:
Gson gson = new Gson();
gson.toSring(yourData);
// then you can get the data by
Gson gson = new Gson();
String data = yourBundle.getString("your_key");
yourDataModel = gson.fromJson(data, YourDataModel.class);
// it will work even with ArrayList
i am writing a flickr client as part of a project from a book that i am reading. in it i create a subclass of HandlerThread that downloads images from flickr and then sets them in an ImageView. i set a placeholder .png earlier in the program and this binds (but with delay) however when i try to replace it nothing happens. the placeholder stays there and is not replaced. it seems like something is happening between that is preventing my HandlerThread from running properly. i have tried stepping through this with the debugger and also looking through the logcat however the logcat has been particularly unhelpful ever since the last update to android studio. it works partially if at all. so right i am getting no error message. earlier i got one stating that i had a null pointer exception but i wasnt able to see where it had come from and upon running the application again it was gone. i am posting samples of my code including the main Fragment which serves as the UI Thread, and the ThumbnailDownloader class which is my HandlerThread subclass.
public class PhotoGalleryFragment extends Fragment {
private static final String TAG = "PhotoGalleryFragment";
private RecyclerView mRecyclerView;
private List<GalleryItem> mItems = new ArrayList<>();
private ThumbnailDownloader<PhotoHolder> mThumbnailDownloader;
public static PhotoGalleryFragment newInstance(){
return new PhotoGalleryFragment();
}
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setRetainInstance(true);
new FetchItemsTask().execute();
Handler responseHandler = new Handler();
mThumbnailDownloader = new ThumbnailDownloader<>(responseHandler);
mThumbnailDownloader.setThumbnailDownloadListener( new ThumbnailDownloader.ThumbnailDownloadListener<PhotoHolder>() {
#Override
public void onThumbnailDownloaded(PhotoHolder target, Bitmap bitmap) {
Log.i(TAG, "setThumbnailDownloadListener() called!");
Drawable drawable = new BitmapDrawable(getResources(), bitmap);
target.bindDrawable(drawable);
}
});
mThumbnailDownloader.start();
mThumbnailDownloader.getLooper();
Log.i(TAG, "background thread started!");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.fragment_photo_gallery, container, false);
mRecyclerView = (RecyclerView) v.findViewById(R.id.photo_recycler_view);
mRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 3));
setupAdapter();
return v;
}
public void onDestroyView(){
super.onDestroyView();
mThumbnailDownloader.clearQueue();
}
#Override
public void onDestroy(){
super.onDestroy();
mThumbnailDownloader.quit();
Log.i(TAG, "background thread destroyed!");
}
private void setupAdapter(){
if (isAdded()){
mRecyclerView.setAdapter(new PhotoAdapter(mItems));
}
}
private class PhotoHolder extends RecyclerView.ViewHolder{
private ImageView mItemImageView;
public PhotoHolder(View itemView){
super(itemView);
mItemImageView = (ImageView) itemView.findViewById(R.id.item_image_view);
}
public void bindDrawable(Drawable drawable){
mItemImageView.setImageDrawable(drawable);
}
}//end PhotoHolder inner class
private class PhotoAdapter extends RecyclerView.Adapter<PhotoHolder>{
private List<GalleryItem> mGalleryItems;
public PhotoAdapter(List<GalleryItem> items){
mGalleryItems = items;
}
#Override
public PhotoHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
View view = layoutInflater.inflate(R.layout.list_item_gallery, viewGroup, false);
return new PhotoHolder(view);
}
#Override
public void onBindViewHolder(PhotoHolder photoHolder, int position) {
GalleryItem galleryItem = mGalleryItems.get(position);
Drawable placeholder = getResources().getDrawable(R.drawable.wait); <--this is the placeholder image
photoHolder.bindDrawable(placeholder);//this <--this sets the placeholder but seems to wait for the thumbnail download to complete for some reason
mThumbnailDownloader.queueThumbnail(photoHolder, galleryItem.getUrl());
}
#Override
public int getItemCount() {
return mGalleryItems.size();
}
}
private class FetchItemsTask extends AsyncTask<Void, Void, List<GalleryItem>>{
#Override
protected List<GalleryItem> doInBackground(Void... params) {
return new FlickrFetchr().fetchItems();
}
#Override
protected void onPostExecute(List<GalleryItem> items){
mItems = items;
setupAdapter();
}
}//end FetchItemsTask inner class
}//end class
and here is my HandlerThread implementation:
public class ThumbnailDownloader<T> extends HandlerThread {
private static final String TAG = "ThumbnailDownloader";
private static final int MESSAGE_DOWNLOAD = 0;
private boolean mHasQuit = false;
private Handler mRequestHandler = new Handler();
private Handler mResponseHandler = new Handler();
private ThumbnailDownloadListener<T> mThumbnailDownloadListener;
private ConcurrentMap<T, String> mRequestMap = new ConcurrentHashMap<>();
public interface ThumbnailDownloadListener<T>{
void onThumbnailDownloaded(T target, Bitmap bitmap);
}
public void setThumbnailDownloadListener(ThumbnailDownloadListener<T> listener){
mThumbnailDownloadListener = listener;
}
public ThumbnailDownloader(Handler responseHandler){
super(TAG);
mResponseHandler = responseHandler;
Log.i(TAG, "ThumbnailDownloader created!");
}
#Override
protected void onLooperPrepared(){
mRequestHandler = new Handler(){
#Override
public void handleMessage(Message msg){
if (msg.what == MESSAGE_DOWNLOAD){
T target = (T) msg.obj;
Log.i(TAG, "got a request for a url:" + mRequestMap.get(target));
handleRequest(target);
}
}
};
}
#Override
public boolean quit(){
mHasQuit = true;
return super.quit();
}
public void queueThumbnail(T target, String url){
Log.i(TAG, "got a url: " + url);
if(url == null){
mRequestMap.remove(target);
}else {
mRequestMap.put(target, url);
mRequestHandler.obtainMessage(MESSAGE_DOWNLOAD, target).sendToTarget();
}
}
public void clearQueue(){
mRequestHandler.removeMessages(MESSAGE_DOWNLOAD);
mRequestMap.clear();
}
private void handleRequest(final T target){
try{
final String url = mRequestMap.get(target);
if (url == null){
return;
}
byte[] bitmapBytes = new FlickrFetchr().getUrlBytes(url);
final Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length);
Log.i(TAG, "Bitmap created!"); //<---this is output in the logcat at the terminal but not the android monitor
mResponseHandler.post(new Runnable(){
#Override
public void run() {
if (mRequestMap.get(target) != null || mHasQuit){
return;
}
mRequestMap.remove(target);
mThumbnailDownloadListener.onThumbnailDownloaded(target, bitmap);
}
});
}catch (IOException ioe){
Log.e(TAG, "error downloading image: ", ioe);
}
}
}
honestly at this point i am not even sure where the problem is. it doesn't seem like queueThumbnail ever runs. but just setting the placeholder wait.png takes so long that it almost seems like there is some mix up between the placeholder and the downloaded image when it comes to binding to the ViewHolder. i am just not sure where it could be. i added comments to point this out.
I am trying to populate data from my main activity using the adapter below. When i run the activity the screen remains blanked. I believe it has to do with the ArrayList which is null perhaps. Can someone tell me why my data is not being displayed. am on this bug for three days now :/
public class CopyOfSecondWheelAdapter extends AbstractWheelTextAdapter {
ArrayList<convertor_pst> PostList = new ArrayList<convertor_pst>();
public ImageLoader imageLoader;
Convertor main;
public CopyOfSecondWheelAdapter(Context context) {
super(context, R.layout.count_layout, NO_RESOURCE);
setItemTextResource(R.id.country_name);
}
#Override
public View getItem(int index, View cachedView, ViewGroup parent) {
View view = super.getItem(index, cachedView, parent);
ImageView img = (ImageView) view.findViewById(R.id.flag);
imageLoader.DisplayImage(PostList.get(index).getDevise(), img);
System.out.println("get item count:"+getItemsCount() );
TextView text = (TextView)view.findViewById(R.id.lib);
text.setText(PostList.get(index).getQuotite());
return view;
}
#Override
public int getItemsCount() {
return PostList.toArray().length;
}
#Override
protected CharSequence getItemText(int index) {
return PostList.get(index).getDevise().toString();
}
}
UPDATE:
In my Main class i have already an
ArrayList<convertor_pst> PostList = new ArrayList<convertor_pst>();
which is populated.
Here is my main class that is my convertor.class
ArrayList<convertor_pst> PostList = new ArrayList<convertor_pst>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.convertor);
context = this;
text_devise_two = (TextView)findViewById(R.id.text_spacetwo);
final WheelView country = (WheelView) findViewById(R.id.country);
country.setVisibleItems(10);
country.setViewAdapter(new FirstWheelAdapter(this));
edt_validate = (EditText)findViewById(R.id.edt_validate);
current_type_loc = (TextView)findViewById(R.id.current_type_loc);
refresh_header= (TextView)findViewById(R.id.refresh_header);
//set current time
Calendar c = Calendar.getInstance();
SimpleDateFormat df = new SimpleDateFormat("dd/MMM/yyyy");
String formattedDate = df.format(c.getTime());
refresh_header.setText(getResources().getString(R.string.mise_a_jour)+" "+formattedDate);
image_one = (ImageView)findViewById(R.id.image_one);
image_two = (ImageView)findViewById(R.id.image_two);
final WheelView currency = (WheelView) findViewById(R.id.currency);
currency.setVisibleItems(10);
currency.setViewAdapter(new CopyOfSecondWheelAdapter(this));
country.addChangingListener(new OnWheelChangedListener() {
#Override
public void onChanged(WheelView wheel, int oldValue, int newValue) {
if (!scrolling) {
}
}
});
country.addScrollingListener( new OnWheelScrollListener() {
#Override
public void onScrollingStarted(WheelView wheel) {
scrolling = true;
}
#Override
public void onScrollingFinished(WheelView wheel) {
scrolling = false;
//1.
wheelSelector(country.getCurrentItem());
}
});
currency.addScrollingListener( new OnWheelScrollListener() {
#Override
public void onScrollingStarted(WheelView wheel) {
scrolling = true;
}
#Override
public void onScrollingFinished(WheelView wheel) {
scrolling = false;
//1.
secondWheel(currency.getCurrentItem());
}
});
country.setCurrentItem(1);
currency.setCurrentItem(3);
new loadingTask().execute();
}
/*1. Change currency */
public void wheelSelector (int id){
if (id==0){
current_type_loc.setText("EUR");
image_one.setBackgroundResource(R.drawable.eur);
}else {
current_type_loc.setText("USD");
image_one.setBackgroundResource(R.drawable.usd);
}
}
class loadingTask extends AsyncTask<Void, Void,Void> {
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
pd = ProgressDialog.show(Convertor.this, "", "Chargement en cours..", true);
super.onPreExecute();
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
pd.dismiss();
doc = Jsoup.parse(getxml,"", Parser.xmlParser());
taux = doc.select("taux");
for (int i = 0; i < taux.size(); i++) {
PostList.add(new convertor_pst(taux.get(i).getElementsByTag("devise").text().toString(),
taux.get(i).getElementsByTag("dateCours").text().toString(),
taux.get(i).getElementsByTag("libelle").text().toString(),
taux.get(i).getElementsByTag("quotite").text().toString(),
taux.get(i).getElementsByTag("fixing").text().toString()));
}
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
envelope =
"soap content"
String requestEnvelope=String.format(envelope, "28-03-2013","true");
getxml = Util.CallWebService(URL,SOAP_ACTION,requestEnvelope);
System.out.println(getxml);
return null;
}
}
public void secondWheel(int index){
text_devise_two.setText(PostList.get(index).getDevise());
edt_validate.setText(" "+PostList.get(index).getFixing());
}
/*
*
* (non-Javadoc)
* #see android.app.Activity#onPause()
* check if activity go to background
*/
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
if (Util.isApplicationBroughtToBackground(Convertor.this)==true){
startActivity(new Intent(Convertor.this,Compte.class));
}
}
}
This is the original wheel adapter class
public class CopyOfSecondWheelAdapter extends AbstractWheelTextAdapter {
ArrayList<convertor_pst> PostList;
public ImageLoader imageLoader;
// Countries names
private String countries[] =
new String[] {"EUR", "USD","EUR", "USD","EUR", "USD","EUR", "USD","EUR", "USD","EUR", "USD"};
// Countries flags
private int flags[] = new int[] {R.drawable.eur, R.drawable.usd,R.drawable.eur, R.drawable.usd,R.drawable.eur, R.drawable.usd,R.drawable.eur, R.drawable.usd,R.drawable.eur, R.drawable.usd,R.drawable.eur, R.drawable.usd};
/**
* Constructor
*/
Convertor main;
public CopyOfSecondWheelAdapter(Context context) {
super(context, R.layout.count_layout, NO_RESOURCE);
setItemTextResource(R.id.country_name);
}
#Override
public View getItem(int index, View cachedView, ViewGroup parent) {
View view = super.getItem(index, cachedView, parent);
ImageView img = (ImageView) view.findViewById(R.id.flag);
img.setImageResource(flags[index]);
TextView text = (TextView)view.findViewById(R.id.lib);
text.setText("code");
return view;
}
#Override
public int getItemsCount() {
return countries.length;
}
#Override
protected CharSequence getItemText(int index) {
return countries[index];
}
}
As far as I understand
currency.setViewAdapter(new CopyOfSecondWheelAdapter(this));
this line creates the adapter, but you fill it up at this line :
new loadingTask().execute();
which is after, so you must call
yourAdapter.notifyDataSetChanged();
on your adapter to update the data.
Android Developer Help says
notifyDataSetChanged()
Notifies the attached observers that the
underlying data has been changed and any View reflecting the data set
should refresh itself.
So in your case you must
create an adapter (yourAdapter = new CopyOfSecondWheelAdapter ....)
assign it with the setViewAdater (WheelView.setViewAdapter(yourAdapter))
in the "postExecute" of your async task, do a call with yourAdapter.notifyDataSetChanged();
By the way, I am not sure to understand what you are doing, but in case you need to have a set of data displayed at two different locations, you don't need to duplicate (create a copy). The two list display can share the same adapter.
UPDATE
You have done an update to your question and I answer to that update :
In the original adapter the countries are not loaded in the async task. So when you assign the adapter, the display show the correct values because they are present in the adapter at the moment you assign it.
In your case, you load the values in the async task. When you create the adapter it is empty and you assign it empty, so the display shows an empty list. You should notify your display of the data change.
So in the original, no need to notify as the data is the correct one at the time of assignment. In your case you have to implement a notifyDataSetChanged(). Or change the type of adapter you are extending.
If I see it correctly, you have 2 times a variable name PostList which confuses you. One is created in your activity and one in your adapter and ass you call add() to the variable of your activity, the list in your adapter never gets the items.
Create a setter for the list in your adapter and set the list in your onPostExecute().