i have a problem with handling screen rotation and AsyncTask in my activity.
Here's the problem:
I have a MainActivity which has inside a PostersFragment, who manages the layout. Inside it there is a GridView to populate with some images fetched by an AsyncTask.
When i rotate the device it messess up, and i can see an old GridView behind the actual GridView.
It surely is a problem bound to recreation of the activity, i googled a lot and found the setRetainInstance(true) method, i tried to call it in my fragment but nothing changed.
Here's the MainActivity code:
public class MainActivity extends ActionBarActivity {
private final String POSTERSFRAGMENT_TAG ="PFTG";
private DrawerLayout mDrawer;
private ListView mDrawerListView;
private Toolbar toolbar;
private ActionBarDrawerToggle mDrawerToggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getFragmentManager().beginTransaction().add(R.id.frame_container, new PostersFragment(), POSTERSFRAGMENT_TAG).commit();
String[] drawerChoices = getResources().getStringArray(R.array.drawer_choices_array);
mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerListView = (ListView) findViewById(R.id.left_drawer);
mDrawerListView.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, drawerChoices));
mDrawerListView.setOnItemClickListener(new DrawerItemClickListener());
toolbar = (Toolbar) findViewById(R.id.main_activity_toolbar);
if(toolbar!=null){
toolbar.setTitle(getResources().getString(R.string.app_name));
setSupportActionBar(toolbar);
}
mDrawerToggle = new ActionBarDrawerToggle(this,mDrawer,toolbar,R.string.drawer_open,R.string.drawer_close){
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
}
};
mDrawer.setDrawerListener(mDrawerToggle);
}
private class DrawerItemClickListener implements ListView.OnItemClickListener{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id){
String x =parent.getItemAtPosition(position).toString();
if(x.equals(getString(R.string.trending_drawer_option))) {
PostersFragment fragment = new PostersFragment();
getFragmentManager().beginTransaction().replace(R.id.frame_container, fragment).commit();
mDrawer.closeDrawer(mDrawerListView);
}
if(x.equals(getString(R.string.bookmarked_drawer_option))){
BookmarksFragment fragment = new BookmarksFragment();
getFragmentManager().beginTransaction().replace(R.id.frame_container,fragment).commit();
mDrawer.closeDrawer(mDrawerListView);
}
if(x.equals(getString(R.string.settings_drawer_option))){
mDrawer.closeDrawer(mDrawerListView);
Intent intent = new Intent(getApplicationContext(),SettingsActivity.class);
startActivity(intent);
}
}
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
boolean drawerOpen = mDrawer.isDrawerOpen(mDrawerListView);
return super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if(mDrawerToggle.onOptionsItemSelected(item))
return true;
return super.onOptionsItemSelected(item);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
}
And the PostersFragment code:
public class PostersFragment extends android.app.Fragment {
public static final int MAX_PAGES = 50;
public int mPagesLoaded = 0;
private ImageAdapter mImages;
public boolean mIsLoading = false;
public TextView loadingText;
private SharedPreferences sharedPrefs;
private SharedPreferences.OnSharedPreferenceChangeListener spChanged;
public PostersFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mImages = new ImageAdapter(getActivity());
View view = inflater.inflate(R.layout.fragment_main,container,false);
loadingText = (TextView) view.findViewById(R.id.loadingTextView);
loadingText.setVisibility(View.GONE);
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
spChanged = new SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
mImages.clear();
mPagesLoaded=0;
}
};
sharedPrefs.registerOnSharedPreferenceChangeListener(spChanged);
initGrid(view);
startLoading();
return view;
}
private void startLoading()
{
if(mPagesLoaded>=MAX_PAGES)
return;
if(mIsLoading==true)
return;
mIsLoading=true;
if(loadingText!=null)
loadingText.setVisibility(View.VISIBLE);
new FetchPageTask().execute(mPagesLoaded + 1);
}
private void stopLoading()
{
if(mIsLoading==false)
return;
if(mIsLoading==true)
mIsLoading=false;
if(loadingText!=null)
loadingText.setVisibility(View.GONE);
}
private void initGrid(View view)
{
GridView gridView = (GridView) view.findViewById(R.id.gridView);
if(gridView==null)
return;
gridView.setAdapter(mImages);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
ImageAdapter adapter = (ImageAdapter) parent.getAdapter();
Movie movie = adapter.getItem(position);
if (movie == null)
return;
//intent to be launched
Intent intent = new Intent(getActivity(),DetailActivity.class);
intent.putExtra(Movie.EXTRA_MOVIE,movie.toBundle());
getActivity().startActivity(intent);
}
});
gridView.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
int lastScreen = firstVisibleItem + visibleItemCount;
if(lastScreen == totalItemCount)
startLoading();
}
});
}
private class FetchPageTask extends AsyncTask<Integer,Void,Collection<Movie>> {
public final String LOG_TAG = FetchPageTask.class.getSimpleName();
#Override
protected Collection<Movie> doInBackground(Integer... params) {
if (params.length == 0)
return null;
int page = params[0];
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String responseJsonStr = null;
try {
final String API_BASE_URL = "http://api.themoviedb.org/3/movie/";
final String API_PARAM_PAGE = "page";
final String API_PARAM_KEY = "api_key";
final String API_SORTING = sharedPrefs.getString(getString(R.string.pref_sorting_key),getString(R.string.pref_sorting_default_value));
Uri builtUri = Uri.parse(API_BASE_URL).buildUpon()
.appendPath(API_SORTING)
.appendQueryParameter(API_PARAM_PAGE, String.valueOf(page))
.appendQueryParameter(API_PARAM_KEY, getString(R.string.my_api_key))
.build();
Log.d(LOG_TAG, "Query URI: " + builtUri.toString());
URL url = new URL(builtUri.toString());
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null)
return null;
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null)
buffer.append(line + "\n");
if (buffer.length() == 0)
return null;
responseJsonStr = buffer.toString();
} catch (Exception e) {
Log.e(LOG_TAG, "Error", e);
return null;
} finally {
if (urlConnection != null)
urlConnection.disconnect();
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
Log.e(LOG_TAG, "Error closing input stream", e);
}
}
}
try {
return fetchMoviesFromJson(responseJsonStr);
} catch (JSONException je) {
Log.d(LOG_TAG, "Can't parse JSON " + responseJsonStr, je);
return null;
}
}
private Collection<Movie> fetchMoviesFromJson(String jsonStr) throws JSONException {
final String KEY_MOVIES = "results";
JSONObject json = new JSONObject(jsonStr);
JSONArray movies = json.getJSONArray(KEY_MOVIES);
ArrayList<Movie> result = new ArrayList<Movie>();
for (int i = 0; i < movies.length(); i++) {
result.add(Movie.getMovieFromJson(movies.getJSONObject(i)));
}
return result;
}
#Override
protected void onPostExecute(Collection<Movie> movies)
{
stopLoading();
mPagesLoaded++;
mImages.addAll(movies);
}
}
}
How can I prevent it from duplicating? How should i handle the change of configuration?
In your onCreate for MainActivity replace this line:
getFragmentManager().beginTransaction().add(R.id.frame_container, new PostersFragment(), POSTERSFRAGMENT_TAG).commit();
to
if (savedInstanceState == null) {
getFragmentManager().beginTransaction().add(R.id.frame_container, new PostersFragment(), POSTERSFRAGMENT_TAG).commit();
}
EDIT: Sorry, I didn't clarify as to why this is required. The purpose of this check is to see if the fragment is already there. When can we confirm that the fragment is not there? When savedInstanceState is null.
Initially, the Bundle is null when the activity is first created. When the device has a configuration change, all activities/fragments are destroyed and recreated, excepting the ones on which setRetainInstance(true) has been called. These fragments are not destroyed. They are just attached to the new activity…
When the activity is recreated after the configuration change, the instance of the retained fragment is already present, and the savedInstanceState is not null as a result of this. Hence, you check if savedInstanceState == null and only then proceed to add the fragment to avoid duplicated.
Related
I am attempting to pull data from my parse server and display an image and text within a RecyclerView of CardViews. I have encountered a few issues, some of which may not have been corrected appropriately, so please feel free to correct any novice code you find below outside of my two current issues. Finally my two issues are.
The data does not display initially. I have 3 tabs in a ViewPager and I have to swipe over twice in order for it to display. If I'm on tab 1 the data doesn't appear until I swipe to tab 3 and return to tab 1, and vice versa. Because there isn't a tab 4, tab 2 never displays.
The second issue I am currently faced with is that at times the data will not match up. It will have the picture from one row matched with the description from another entity.
Below is my MusicFragment.java
public class MusicFragment extends Fragment {
private ArrayList<String> titles = new ArrayList<>();
private ArrayList<Bitmap> bitmaps = new ArrayList<>();
private ArrayList<String> descriptions = new ArrayList<>();
private boolean notComplete = true;
public MusicFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
RecyclerView musicRecycler = (RecyclerView)inflater.inflate(
R.layout.fragment_music, container, false);
if (notComplete) {
// Get the MusicFragImages class as a reference.
ParseQuery<ParseObject> query = new ParseQuery<>("MusicFragImages");
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
if (e == null) {
for (ParseObject object : objects) {
String description = (String) object.get("description");
ParseFile file = (ParseFile) object.get("image");
String title = (String) object.get("title");
titles.add(title);
descriptions.add(description);
file.getDataInBackground(new GetDataCallback() {
#Override
public void done(byte[] data, ParseException e) {
if (e == null && data != null) {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
bitmaps.add(bitmap);
}
}
});
}
} else {
Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
});
notComplete = false;
}
// Create captioned images and registers it to the adapter.
CaptionedImagesAdapter adapter = new CaptionedImagesAdapter(titles, bitmaps, descriptions);
musicRecycler.setAdapter(adapter);
// Set up the layout.
GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 1);
musicRecycler.setLayoutManager(layoutManager);
adapter.setListener(new CaptionedImagesAdapter.Listener() {
public void onClick(int position) {
Intent intent;
switch (position) {
case 0:
intent = new Intent(getActivity(), AudioActivity.class);
getActivity().startActivity(intent);
break;
case 1:
intent = new Intent(getActivity(), VideoActivity.class);
getActivity().startActivity(intent);
break;
}
}
});
return musicRecycler;
}
}
Additionally, here is my CaptionedImagesAdapter
class CaptionedImagesAdapter extends
RecyclerView.Adapter<CaptionedImagesAdapter.ViewHolder> {
private final ArrayList<String> captions;
private final ArrayList<Bitmap> bitmaps;
private final ArrayList<String> descriptions;
private Listener listener;
interface Listener {
void onClick(int position);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private final CardView cardView;
public ViewHolder(CardView v) {
super(v);
cardView = v;
}
}
public CaptionedImagesAdapter(ArrayList<String> captions, ArrayList<Bitmap> bitmaps, ArrayList<String> descriptions) {
this.captions = captions;
this.bitmaps = bitmaps;
this.descriptions = descriptions;
}
#Override
public int getItemCount() {
return captions.size();
}
public void setListener(Listener listener) {
this.listener = listener;
}
#Override
public CaptionedImagesAdapter.ViewHolder onCreateViewHolder(
ViewGroup parent, int viewType) {
CardView cv = (CardView) LayoutInflater.from(parent.getContext()).inflate(R.layout.card_selection_2, parent, false);
return new ViewHolder(cv);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
final int index = position;
// Creates a CardView
CardView cardView = holder.cardView;
ImageView imageView = cardView.findViewById(R.id.type_image);
imageView.setImageBitmap(bitmaps.get(index));
imageView.setContentDescription(descriptions.get(index));
// Populate the caption.
TextView textView = cardView.findViewById(R.id.type_text);
textView.setText(captions.get(index));
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
if (listener != null)
listener.onClick(index);
}
});
}
}
FOR REFERENCE...... if needed MainActivity.java is below
public class MainActivity extends AppCompatActivity {
// Variables for the audio player.
public static MediaPlayer mediaPlayer;
public static int albumId;
public static int currentSong = -1;
public static boolean isPlaying = false;
private static int[] songs;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Attach the SectionsPageAdapter to the ViewPager
SectionsPageAdapter pagerAdapter = new SectionsPageAdapter(getSupportFragmentManager());
ViewPager pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(pagerAdapter);
int currentTab = 0;
pager.setCurrentItem(currentTab);
// Attach the ViewPager to the TabLayout
TabLayout tabLayout = (TabLayout)findViewById(R.id.tabs);
tabLayout.setupWithViewPager(pager);
// Starts the player.
player();
}
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the app bar.
getMenuInflater().inflate(R.menu.menu_main, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent intent;
switch (item.getItemId()) {
case R.id.action_contact:
intent = new Intent(MainActivity.this, ContactActivity.class);
startActivity(intent);
return true;
case R.id.action_cart:
intent = new Intent(this, CartActivity.class);
startActivity(intent);
return true;
case R.id.action_member:
intent = new Intent(this, ProfileActivity.class);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private class SectionsPageAdapter extends FragmentPagerAdapter {
public SectionsPageAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return 3;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new MusicFragment();
case 1:
return new ArtFragment();
case 2:
return new FashionFragment();
}
return null;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return getResources().getText(R.string.title_music);
case 1:
return getResources().getText(R.string.title_art);
case 2:
return getResources().getText(R.string.title_fashion);
}
return null;
}
}
private void player() {
/*Create a background thread that will automatically advance to
* the next song, as long as there is a next song.*/
// Get the songs.
songs = AudioData.audio[albumId].getSongs();
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
if (isPlaying) {
if (!(mediaPlayer.isPlaying()) && currentSong < songs.length - 1) {
mediaPlayer.stop();
mediaPlayer.reset();
currentSong++;
mediaPlayer = MediaPlayer.create(MainActivity.this, songs[currentSong]);
mediaPlayer.start();
isPlaying = true;
}
//Set the flag to false at the end of the album.
if (currentSong == songs.length) {
isPlaying = false;
}
}
handler.postDelayed(this, 1000);
}
});
}
#Override
public void onBackPressed() {
super.onBackPressed();
finishAffinity();
}
}
Thanks again to Harikumar for correcting the first issue. I ended up correcting the second issue with the code below. It was within the enhance for loop.
for (ParseObject object : objects) {
String description = (String) object.get("description");
ParseFile file = (ParseFile) object.get("image");
String title = (String) object.get("title");
Bitmap bitmap;
titles.add(title);
descriptions.add(description);
byte[] data;
try {
data = file.getData();
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
bitmaps.add(bitmap);
adapter.notifyDataSetChanged(); //notify your adapter that data has changed
} catch (ParseException pe) {
Toast.makeText(getContext(), pe.getMessage(), Toast.LENGTH_SHORT).show();
}
}
Data will be updated if you notify your adapter CaptionedImagesAdapter. Try modifying the code to:
public class MusicFragment extends Fragment {
private ArrayList<String> titles = new ArrayList<>();
private ArrayList<Bitmap> bitmaps = new ArrayList<>();
private ArrayList<String> descriptions = new ArrayList<>();
private CaptionedImagesAdapter adapter;
private boolean notComplete = true;
public MusicFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
RecyclerView musicRecycler = (RecyclerView)inflater.inflate(
R.layout.fragment_music, container, false);
GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 1);
musicRecycler.setLayoutManager(layoutManager);
adapter = new CaptionedImagesAdapter(titles, bitmaps, descriptions);
musicRecycler.setAdapter(adapter);
if (notComplete) {
// Get the MusicFragImages class as a reference.
ParseQuery<ParseObject> query = new ParseQuery<>("MusicFragImages");
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
if (e == null) {
for (ParseObject object : objects) {
String description = (String) object.get("description");
ParseFile file = (ParseFile) object.get("image");
String title = (String) object.get("title");
titles.add(title);
descriptions.add(description);
file.getDataInBackground(new GetDataCallback() {
#Override
public void done(byte[] data, ParseException e) {
if (e == null && data != null) {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
bitmaps.add(bitmap);
adapter.notifyDataSetChanged(); //notify your adapter that data has changed
}
}
});
}
} else {
Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
});
notComplete = false;
}
adapter.setListener(new CaptionedImagesAdapter.Listener() {
public void onClick(int position) {
Intent intent;
switch (position) {
case 0:
intent = new Intent(getActivity(), AudioActivity.class);
getActivity().startActivity(intent);
break;
case 1:
intent = new Intent(getActivity(), VideoActivity.class);
getActivity().startActivity(intent);
break;
}
}
});
return musicRecycler;
}
}
Here is a small optimization for your 2nd solution: update notifyDataSetChanged() only once after the for loop (put it just outside the for loop). This is better in terms of performance.
I'm currently facing a bug in restoring the Position of an ArrayList after orientation cchange to enhance the user experience. I try to store the ArrayList and already made movieData Parcelable. When using a debugger after orientation change savedInstance obviously is not null and contained an int value and presumably the parcelable Array List and I don't really know why this code doesn't work yet.
Fragment Class:
public class MovieGridFragment extends Fragment {
public clickInterfaceHelper clickListener;
private GridView movieGridView;
private int index;
public List<movieData> movieDataList = new ArrayList<>();
public ArrayList<movieData> restoreList;
public MovieGridFragment() {} //empty constructor
#Override
public void onAttach(Context context) {
super.onAttach(context);
}
public void setClickListener(clickInterfaceHelper listener) {
this.clickListener = listener;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null)
index = savedInstanceState.getInt("INDEX");
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setHasOptionsMenu(true);
if(movieDataList.isEmpty() && networkChecker.isNetworkAvailableChecker(getContext())) {
movieDataList = new ArrayList<movieData>();
}
if(!movieDataList.isEmpty() && !networkChecker.isNetworkAvailableChecker(getContext())) {
movieDataList = new ArrayList<movieData>();
}
View rootView = inflater.inflate(R.layout.movie_display_fragment, container, false);
movieGridView = (GridView) rootView.findViewById(R.id.gv_movie_display);
if(savedInstanceState != null && savedInstanceState.containsKey("OLDMOVIEDATA")) {
//index = savedInstanceState.getInt("INDEX");
//movieDataList.addAll(Arrays.asList((movieData[]) savedInstanceState.getSerializable("OLDMOVIEDATA")));
restoreList = savedInstanceState.getParcelableArrayList("OLDMOVIEDATA");
movieAdapter adapter = new movieAdapter(getActivity(),restoreList);
adapter.notifyDataSetChanged();
//movieGridView.setAdapter(adapter);
movieGridView.smoothScrollToPosition(index);
}
else {
movieAdapter adapter = new movieAdapter(getActivity(), movieDataList);
adapter.notifyDataSetChanged();
movieGridView.setAdapter(adapter);
}
movieGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(clickListener != null)
clickListener.clickOnItem(position);
}
});
return rootView;
}
#Override
public void onSaveInstanceState(Bundle outState) {
//outState.putSerializable("OLDMOVIEDATA",movieData.movieDataArray);
outState.putParcelableArrayList("OLDMOVIEDATA",restoreList);
outState.putInt("INDEX",movieGridView.getFirstVisiblePosition());
super.onSaveInstanceState(outState);
}
}
Adapter:
public class movieAdapter extends ArrayAdapter<movieData> {
public movieAdapter(Context context, List<movieData> movieObject) {
super(context, 0, movieObject);
}
public View getView(int pos, View convertingView, ViewGroup viewGroup) {
movieData movieDatas = getItem(pos);
String url="http://image.tmdb.org/t/p/w185"+movieDatas.getMovieImagePath();
if(convertingView == null)
convertingView = LayoutInflater.from(getContext()).inflate(R.layout.image_display,viewGroup,false);
ImageView imageView = (ImageView) convertingView.findViewById(R.id.iv_movie_image);
Picasso.with(getContext()).load(url.trim()).into(imageView);
return convertingView;
}
}
and the main activity:
public class MainActivity extends AppCompatActivity implements clickInterfaceHelper {
public static String sorterString = null;
public static String urlBase = "https://api.themoviedb.org/3/movie/";
public static String urlFinal = null;
RequestQueue requestQueue;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState == null) {
MovieGridFragment fragment = new MovieGridFragment();
fragment.setClickListener(this);
getSupportFragmentManager().beginTransaction()
.add(R.id.activity_container, fragment)
.commit();
movieData.movieDataPosition = 0;
}
if(savedInstanceState != null) {
sorterString = savedInstanceState.getString("SORTER");
}
if(sorterString==null)
sorterString="popular?";
if(sorterString!="favorite" && sorterString!=null) {
if(networkChecker.isNetworkAvailableChecker(this)) {
movieRequest();
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu_act, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == R.id.m_popularity_action) {
if(sorterString != "popular?") {
sorterString = "popular?";
if(networkChecker.isNetworkAvailableChecker(this))
movieRequest();
}
return true;
}
if(id == R.id.m_action_voter) {
if(sorterString != "top_rated?") {
sorterString = "top_rated?";
if(networkChecker.isNetworkAvailableChecker(this))
movieRequest();
}
return true;
}
if(id == R.id.m_favorite_btn) {
if(sorterString != "favorite") {
SQLiteOpenHelper helper = new movieDataDbHelper(this);
SQLiteDatabase database = helper.getReadableDatabase();
Cursor cursor= database.query(movieDataContract.contractEntry.TABLE_NAME,
new String[] {
movieDataContract.contractEntry.ID,
movieDataContract.contractEntry.IMG_PATH},null,null,null,null,null);
if(cursor.getCount() == 0) {
Toast.makeText(this, "there are no favorite movies yet!",Toast.LENGTH_SHORT).show();
} else {
sorterString = "favorite";
showFavoriteFragment();
}
database.close();
helper.close();
cursor.close();
}
return true;
}
return super.onOptionsItemSelected(item);
}
public void showFavoriteFragment() {
favoriteMoviesDetailsFragment fragment = new favoriteMoviesDetailsFragment();
try {
getFragmentManager().beginTransaction().replace(R.id.activity_container,fragment).commit();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
outState.putString("SORTER", sorterString);
outState.putInt("POSITION",movieData.movieDataPosition);
super.onSaveInstanceState(outState, outPersistentState);
}
public void movieRequest() {
final MovieGridFragment gridFragment = new MovieGridFragment();
gridFragment.setClickListener(this);
urlFinal = urlBase + sorterString + movieData.apiKey;
urlFinal.trim();
requestQueue = Volley.newRequestQueue(this);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, urlFinal, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray array = response.getJSONArray("results");
movieData.movieDataArray = new movieData[array.length()];
for (int i = 0; i < array.length(); i++) {
movieData movie = new movieData();
JSONObject jsonObject = array.getJSONObject(i);
movie.setMovieId(jsonObject.getString("id"));
movie.setMovieImagePath(jsonObject.getString("poster_path"));
movie.setMovieTitle(jsonObject.getString("original_title"));
movie.setMoviePlot(jsonObject.getString("overview"));
movie.setMovieVoting(jsonObject.getString("vote_average"));
movie.setMovieReleaseDate(jsonObject.getString("release_date"));
movieData.movieDataArray[i] = movie;
}
gridFragment.movieDataList = Arrays.asList(movieData.movieDataArray);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.activity_container, gridFragment);
try {
transaction.commitAllowingStateLoss();
} catch (Exception e) {
e.printStackTrace();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("volley", String.valueOf(error));
}
}
);
requestQueue.add(jsonObjectRequest);
}
#Override
public void clickOnItem(int id) {
movieData.movieDataPosition = id;
if(movieData.movieDataArray == null) {
movieRequest();
} else {
Intent intent = new Intent(this, detailsActivity.class);
intent.putExtra("FRAGMENT","MOVIE");
startActivity(intent);
}
}
#Override
public void favoriteMovieItem(int movieId) {
movieData.dbPosition = movieId;
Intent intent = new Intent(this,detailsActivity.class);
intent.putExtra("FRAGMENT","favorite");
startActivity(intent);
}
}
You already use the
#Override
public void onSaveInstanceState(Bundle outState) {
//outState.putSerializable("OLDMOVIEDATA",movieData.movieDataArray);
outState.putParcelableArrayList("OLDMOVIEDATA",restoreList);
outState.putInt("INDEX",movieGridView.getFirstVisiblePosition());
super.onSaveInstanceState(outState);
}
Just use it to store the position you need to save. Get the position back using the bundle given in the "onCreateView".
If it does not work, put "setRetainInstance(true)" in the "onCreate" function of your fragment. It will prevent your fragment being destroyed then recreated from nothing during orientation change.
However, I read somewhere that's not the correct way to do so with fragment having UI elements (but i never found anything wrong doing this).
If you want an alternative way not using "setRetainInstance", store (and restore) the position on the activity
public void onSaveInstanceState(Bundle outState)"
function. To do so, create a function "getPosition()" in your fragment, call it in the activity saveInstanceState, and create a function "refresh(int position)" in your fragment (and call it on the restored position value) once the fragment is loaded/recreated in the activity.
I'm building a UI that is comprised of a GridView with images extracted from an API, I'm using an ImageListAdapter and a MovieFragment, when I start the app I just get an empty screen.
I've tried using a list of predownloaded images and it works.
Fetching the data from the API is on an AsyncTask and I believe that the problem is timing, the fact that gridview.setAdapter() is called too early.
This is the code:
public class MainActivity extends AppCompatActivity {
private final String LOG_TAG = MainActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getFragmentManager()
.beginTransaction()
.add(R.id.container, new MovieFragment())
.commit();
}
}}
public class MovieFragment extends Fragment {
private final String LOG_TAG = MovieFragment.class.getSimpleName();
public ImageListAdapter imageAdapter;
String urlPopular = "https://api.themoviedb.org/3/movie/popular?api_key=";
String urlRatings = "https://api.themoviedb.org/3/movie/top_rated?api_key=";
public MovieFragment() {
};
#Override
public void onStart() {
super.onStart();
FetchMovieData movieTask = new FetchMovieData();
movieTask.execute(urlPopular);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.movie_fragment_main, container, false);
GridView gridview = (GridView) rootView.findViewById(R.id.grid_view);
Log.d(LOG_TAG, imageAdapter.getCount() +"");
gridview.setAdapter(imageAdapter);
gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
Toast.makeText(getActivity(), "" + position,
Toast.LENGTH_SHORT).show();
}
});
return rootView;
}
public class ImageListAdapter extends ArrayAdapter {
private Context context;
private LayoutInflater inflater;
private String[] imageUrls;
public ImageListAdapter(Context context, String[] imageUrls) {
super(context, R.layout.image_item, imageUrls);
this.context = context;
this.imageUrls = imageUrls;
inflater = LayoutInflater.from(context);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.d(LOG_TAG, imageUrls[position]);
if (null == convertView) {
convertView = inflater.inflate(R.layout.image_item, parent, false);
}
Picasso
.with(context)
.load(imageUrls[position])
.fit() // will explain later
.into((ImageView) convertView);
return convertView;
}
}
public class FetchMovieData extends AsyncTask<String,Void,String[][]> {
private final String LOG_TAG = FetchMovieData.class.getSimpleName();
#Override
protected String[][] doInBackground(String... params) {
String url = params[0];
if (params.length == 0){
return null;
}
// Will contain the raw JSON response as a string.
String movieJSON = null;
try {
movieJSON = getMovieInfo(url);
} catch (final IOException e) {
Log.d(LOG_TAG, "Error closing stream", e);
}
try{
return getMovieDataFromJSON(movieJSON);
}
catch (JSONException e){
Log.d(LOG_TAG, e.getMessage(),e);
e.printStackTrace();
}
//Just in case...
return null;
}
private String getMovieInfo(String myurl) throws IOException{
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try{
URL url = new URL(myurl);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
inputStream = urlConnection.getInputStream();
StringBuffer stringBuffer = new StringBuffer();
if (inputStream == null){
return null;
}
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
stringBuffer.append(line + "\n");
}
if (stringBuffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
Log.d(LOG_TAG, stringBuffer.toString());
return stringBuffer.toString();
}
finally {
if(urlConnection != null){
urlConnection.disconnect();
}
}
}
private String[][] getMovieDataFromJSON(String jsonObj) throws JSONException{
JSONObject mainJSON = new JSONObject(jsonObj);
final String POSTERS = "poster_path";
final String ORIGINAL_TITLE = "original_title";
final String SYNOPSIS = "overview";
final String USER_RATING = "vote_average";
final String RELEASE_DATE = "release_date";
final String RESULTS = "results";
// Building a String[][] of movie info while:
// movie[][0] = Poster path
// movie[][1] = Original Title
// movie[][2] = Synopsis
// movie[][3] = User Rating
// movie[][4] = Release Date
JSONArray movieIndexArray = mainJSON.getJSONArray(RESULTS);
String[][] movie = new String[20][5];
for(int i = 0; i < movieIndexArray.length(); i++) {
JSONObject movieObject = movieIndexArray.getJSONObject(i);
movie[i][0] = movieObject.getString(POSTERS);
movie[i][1] = movieObject.getString(ORIGINAL_TITLE);
movie[i][2] = movieObject.getString(SYNOPSIS);
movie[i][3] = movieObject.getString(USER_RATING);
movie[i][4] = movieObject.getString(RELEASE_DATE);
}
return movie;
}
private String[] buildPosterArray(String[][] result){
String[] url = new String[20];
Uri.Builder builtUri = new Uri.Builder();
builtUri.scheme("http");
builtUri.authority("image.tmdb.org");
builtUri.appendPath("t");
builtUri.appendPath("p");
builtUri.appendPath("w185");
for (int i = 0 ; i < result.length ; i++){
builtUri.appendEncodedPath((result[i][0]));
builtUri.build();
url[i] = builtUri.toString();
}
return url;
}
protected void onPostExecute(String[][] result){
if(result != null){
String[] posterArray = buildPosterArray(result);
imageAdapter = new ImageListAdapter(getActivity(), posterArray);
Log.d(LOG_TAG, imageAdapter.getCount() +"");
}
}
}
}
I finally solved it, I used the extension of BaseAdapter instead of ArrayAdapter:
public class ImageAdapter extends BaseAdapter {
private Context mContext;
private String[] moviePath;
public ImageAdapter(Context c, String[] path) {
mContext = c;
this.moviePath = path;
}
public int getCount() {
return moviePath.length;
}
//Needed due to methods being abstract
public Object getItem(int position) {return null;}
public long getItemId(int position) {return 0;}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = (ImageView) convertView;
if (imageView == null) {
// if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(500, 500));
imageView.setPadding(5, 5, 5, 5);
} else {
imageView = (ImageView) convertView;
}
//imageView.setImageResource(mThumbIds[position]);
Picasso.with(getActivity())
.load(moviePath[position])
.fit()
.into(imageView);
return imageView;
}
}
I also used the setAdapter() inside the onPostExecute() method.
Thanks you all for your help =D
I am creating an app where a list of hotels will be shown, all the data is coming from MySQL using JSON and PHP, I created the custom list view by extending the base adapter to a custom one, but I am not able to implement a OnItemClickListener for the listview, as i want to show the Hotel Name of that row in Toast whenever the user clicks on a row of list view. I tried various example available on internet, but i just doesn't work.
Adapter
public class CustomListAdapterHotel extends BaseAdapter {
private Activity activity;
private LayoutInflater inflater;
private List<WorldsBillionaires> billionairesItems;
ImageLoader imageLoader = AppController.getInstance().getImageLoader();
public CustomListAdapterHotel(Activity activity, List<WorldsBillionaires> billionairesItems) {
this.activity = activity;
this.billionairesItems = billionairesItems;
}
#Override
public int getCount() {
return billionairesItems.size();
}
#Override
public Object getItem(int location) {
return billionairesItems.get(location);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (inflater == null)
inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null)
convertView = inflater.inflate(R.layout.list_hotel, null);
if (imageLoader == null)
imageLoader = AppController.getInstance().getImageLoader();
//NetworkImageView thumbNail = (NetworkImageView) convertView.findViewById(R.id.thumbnail);
TextView hotel_name = (TextView) convertView.findViewById(R.id.hotel_name);
TextView zone = (TextView) convertView.findViewById(R.id.zone);
TextView contact_person = (TextView) convertView.findViewById(R.id.contact_person);
TextView contact_number = (TextView) convertView.findViewById(R.id.contact_number);
TextView btc_direct = (TextView) convertView.findViewById(R.id.btcdirect);
// getting billionaires data for the row
WorldsBillionaires m = billionairesItems.get(position);
// name
hotel_name.setText(String.valueOf(m.getHotel_Name()));
zone.setText(String.valueOf(m.getHotel_Zone()));
contact_person.setText(String.valueOf(m.getContact_Person()));
contact_number.setText(String.valueOf(m.getContact_Number()));
btc_direct.setText(String.valueOf(m.getBtc_Direct()));
return convertView;
}
}
Model
public class WorldsBillionaires {
private String hotel_name,hotel_zone,contact_person,contact_number,btc_direct;
public WorldsBillionaires(String hotel_name, String hotel_zone, String contact_person, String contact_number, String btc_direct) {
this.hotel_name=hotel_name;
this.hotel_zone=hotel_zone;
this.contact_person=contact_person;
this.contact_number=contact_number;
this.btc_direct=btc_direct;
}
public WorldsBillionaires() {
}
public String getZone() {
return zone;
}
public void setZone(String zone) {
this.zone = zone;
}
public String getThumbnailUrl() {
return thumbnailUrl;
}
public void setThumbnailUrl(String thumbnailUrl) {
this.thumbnailUrl = thumbnailUrl;
}
public String getHotel_Name() {
return hotel_name;
}
public void setHotel_Name(String hotel_name) {
this.hotel_name = hotel_name;
}
public String getHotel_Zone() {
return hotel_zone;
}
public void setHotel_Zone(String hotel_zone) {
this.hotel_zone = hotel_zone;
}
public String getContact_Person() {
return contact_person;
}
public void setContact_Person(String contact_person) {
this.contact_person = contact_person;
}
public String getContact_Number() {
return contact_number;
}
public void setContact_Number(String contact_number) {
this.contact_number = contact_number;
}
public String getBtc_Direct() {
return btc_direct;
}
public void setBtc_Direct(String btc_direct) {
this.btc_direct = btc_direct;
}
}
Main Activity
public class ShowHotel extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
// Billionaires json url
private ProgressDialog pDialog;
private List<WorldsBillionaires> worldsBillionairesList = new ArrayList<WorldsBillionaires>();
private ListView listView;
private CustomListAdapterHotel adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_hotel);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setLogo(R.mipmap.ic_launcher);
getSupportActionBar().setDisplayUseLogoEnabled(true);
listView = (ListView) findViewById(R.id.list);
adapter = new CustomListAdapterHotel(this, worldsBillionairesList);
listView.setAdapter(adapter);
pDialog = new ProgressDialog(this);
// Showing progress dialog before making http request
pDialog.setMessage("Loading...");
pDialog.show();
// Creating volley request obj
JsonArrayRequest billionaireReq = new JsonArrayRequest("http://192.168.247.1/AdminBihar/getHotel.php?zone="+methods.zone,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
hidePDialog();
// Parsing json
for (int i = 0; i < response.length(); i++) {
try {
JSONObject obj = response.getJSONObject(i);
WorldsBillionaires worldsBillionaires = new WorldsBillionaires();
worldsBillionaires.setHotel_Name(obj.getString("hotel_name"));
worldsBillionaires.setThumbnailUrl(obj.getString("image"));
worldsBillionaires.setHotel_Zone(obj.getString("zone"));
worldsBillionaires.setContact_Person(obj.getString("contact_person"));
worldsBillionaires.setContact_Number(obj.getString("contact_number"));
worldsBillionaires.setBtc_Direct(obj.getString("btc_direct"));
// adding Billionaire to worldsBillionaires array
worldsBillionairesList.add(worldsBillionaires);
} catch (JSONException e) {
e.printStackTrace();
}
}
// notifying list adapter about data changes
// so that it renders the list view with updated data
adapter.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
hidePDialog();
}
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(billionaireReq);
}
#Override
public void onDestroy() {
super.onDestroy();
hidePDialog();
}
private void hidePDialog() {
if (pDialog != null) {
pDialog.dismiss();
pDialog = null;
}
}
}
so after you get json data, in activity that shows your list do something like this:
public class DisplayListView extends AppCompatActivity {
ListView listView;
protected void onCreate(){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_list_view);
listView = (ListView) findViewById(R.id.listview);
hotelAdapter = new CustomListAdapterHotel (this, R.layout.row_layout);
listView.setAdapter(hotelAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id){
Model stuff = (Model) hotelAdapter.getItem(position);
String hotelName = stuff.getHotel_Name();
Toast.makeText(getApplicationContext(), hotelName, Toast.LENGTH_SHORT).show();
}
});
there, this worked for me :)
i using ListView in fragment. I have one asynctask to download json data from remote server. I try refresh programmatically my displayed adapter/listview in onPostExecute function but it doesn't work for me.
My main activity with three fragments, three listview, three adapter and one async task.
public class ContactsActivity extends ActionBarActivity implements ActionBar.TabListener {
SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;
private static List<Item> BackList = new ArrayList<Item>();
private static List<Item> BackList2 = new ArrayList<Item>();
private static List<Item> BackList3 = new ArrayList<Item>();
private static ListView ListView;
private static Context activity;
public static String HASH;
private static final String[] timestamp = {"0"};
private static WeatherAdapter adapter;
private static int fragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.contacts);
Intent myIntent= getIntent();
HASH = myIntent.getStringExtra("HASH");
Log.d("Intent - contactActivity", HASH);
final ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
actionBar.addTab(
actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this));
}
(new PrefetchData()).execute();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.contacts, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return PlaceholderFragment.newInstance(position + 1);
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
fragment = position;
switch (position) {
case 0:
return getString(R.string.title_section1).toUpperCase(l);
case 1:
return getString(R.string.title_section2).toUpperCase(l);
case 2:
return getString(R.string.title_section3).toUpperCase(l);
}
return null;
}
}
public static Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public static class PlaceholderFragment extends Fragment {
private static final String ARG_SECTION_NUMBER = "section_number";
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
int index = getArguments().getInt(ARG_SECTION_NUMBER);
fragment = index;
activity = getActivity();
ListView listview1 = (ListView) rootView.findViewById(R.id.listView);
switch(fragment){
case 1:
adapter = new WeatherAdapter(activity, R.layout.listview_item_row, BackList);
listview1.setOnItemClickListener(new ListView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> a, View v, int i, long l) {
Intent rozmowa = new Intent(getActivity(), Incotalk.class);
rozmowa.putExtra("HASH", HASH);
startActivity(rozmowa);
}
});
break;
case 2:
adapter = new WeatherAdapter(activity, R.layout.listview_item_row2, BackList2);
break;
case 3:
adapter = new WeatherAdapter(activity, R.layout.listview_item_row3, BackList3);
break;
}
listview1.setAdapter(adapter);
ListView = listview1;
return rootView;
}
}
/**
* Async Task to make http call
*/
private class PrefetchData extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// before making http calls
}
#Override
protected Void doInBackground(Void... arg0) {
final String id = HASH;
final String url = "http://freshfrog.pl/projects/talk.php?user="+id+"&t=" + timestamp[0];
Log.d("BBB","start");
try {
String page = new Communicator().executeHttpGet(url);
JSONObject jsonObject = new JSONObject(page);
timestamp[0] = jsonObject.getString("t");
HASH = jsonObject.getJSONObject("s").getString("hash");
JSONArray oczekujacy = jsonObject.getJSONArray("m");
// wiadomosci
BackList.clear(); // czyści przed odświerzeniem
BackList2.clear();
BackList3.clear();
for (int i=oczekujacy.length()-1; i>0; i--) {
JSONObject actor = oczekujacy.getJSONObject(i);
String message = actor.getString("m");
String hash = actor.getString("n");
String t = actor.getString("t");
int l = BackList.size();
Boolean jest = false;
for(int j=0; j<l; j++){
Item item = BackList.get(j);
if(!item.isSection()){
ContactItem contactItem= (ContactItem) item;
if( (contactItem.hash).equals(hash) ){
jest = true;
break;
}
}
//Log.d("bbb", BackList.get(j).hash);
}
if(!jest && !hash.equals(id)) BackList.add(
new ContactItem(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher),
message,
hash));
}
// znajomi
BackList2.add(new SectionItem("Otrzymane zaproszenia"));
oczekujacy = jsonObject.getJSONObject("f").getJSONObject("p").getJSONArray("sending");
for (int i=0; i<oczekujacy.length(); i++) {
JSONObject actor = oczekujacy.getJSONObject(i);
String name = actor.getString("name");
String hash = actor.getString("hash");
String avatar = actor.getString("avatar");
BackList2.add(new ContactItem(getBitmapFromURL(avatar) , name, hash) );
}
// szukaj
BackList3.add(new SectionItem("Znajomi"));
Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, null);
while (phones.moveToNext())
{
String name= phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
BackList3.add(new ContactItem(
BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher),
name,
phoneNumber) );
}
} catch (Exception e) {
Log.d("BBB", e.toString());
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
/* gdy skończy */
adapter.notifyDataSetChanged();
ListView listview2 = (ListView) findViewById(R.id.listView);
listview2.invalidateViews();
//Toast.makeText(ContactsActivity.this, "coś przyszło", Toast.LENGTH_SHORT).show();
Log.d("BBB", "powinno sie odswieżyc");
new PrefetchData().execute();
}
}
}
My custom adapter
public class WeatherAdapter extends ArrayAdapter<Item> {
Context context;
int layoutResourceId;
List<Item> data = null;
private LayoutInflater vi;
public WeatherAdapter(Context context, int layoutResourceId, List<Item> data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
WeatherHolder holder = null;
SectionHolder holder2 = null;
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
Item i = data.get(position);
if(row == null){
if(!i.isSection()){
row = inflater.inflate(layoutResourceId, parent, false);
holder = new WeatherHolder();
holder.imgIcon = (ImageView)row.findViewById(R.id.imgIcon);
holder.txtTitle = (TextView)row.findViewById(R.id.txtTitle);
row.setTag(holder);
ContactItem contactItem = (ContactItem)i;
holder.txtTitle.setText(contactItem.title);
holder.imgIcon.setImageBitmap(contactItem.icon);
}else{
row = inflater.inflate(R.layout.listview_header_row, parent, false);
holder2 = new SectionHolder();
holder2.txtTitle = (TextView)row.findViewById(R.id.txtTitle);
row.setTag(holder2);
SectionItem sectionItem = (SectionItem)i;
holder2.txtTitle.setText(sectionItem.title);
}
}
else
{
if(!i.isSection()){
//holder = (WeatherHolder) row.getTag();
}else{
//holder2 = (SectionHolder) row.getTag();
}
}
return row;
}
public void update(List<Item> newlist) {
Log.d("bbb","aktualizacja listview");
data.clear();
data.addAll(newlist);
this.notifyDataSetChanged();
}
#Override
public void notifyDataSetChanged() // Create this function in your adapter class
{
//notifySetDataChanged()
super.notifyDataSetChanged();
}
static class WeatherHolder
{
ImageView imgIcon;
TextView txtTitle;
}
static class SectionHolder
{
TextView txtTitle;
}
}
the part of the "if(row == null){" should only contain initializations of the views and the viewHolders.
it shouldn't contain any setting of data to the views.
after this part ( after the "else {...}" ) , you should update the views with the new data .
here's my fix to your code (looks ugly, but should work) :
...
int type=getViewType();
switch(type)
{
case 0:
if(row == null)
{
row = inflater.inflate(layoutResourceId, parent, false);
holder = new WeatherHolder();
holder.imgIcon = (ImageView)row.findViewById(R.id.imgIcon);
holder.txtTitle = (TextView)row.findViewById(R.id.txtTitle);
row.setTag(holder);
}
else
holder = (WeatherHolder) row.getTag();
ContactItem contactItem = (ContactItem)i;
holder.txtTitle.setText(contactItem.title);
holder.imgIcon.setImageBitmap(contactItem.icon);
break;
case 1:
if(row == null)
{
row = inflater.inflate(R.layout.listview_header_row, parent, false);
holder2 = new SectionHolder();
holder2.txtTitle = (TextView)row.findViewById(R.id.txtTitle);
row.setTag(holder2);
}
else
holder2 = (SectionHolder) row.getTag();
SectionItem sectionItem = (SectionItem)i;
holder2.txtTitle.setText(sectionItem.title);
break;
}
return row;
...
... int getViewType(...) {... return i.isSection()? 1:0;}
... int getViewTypeCount(){return 2;}
btw, you should really watch the lecture "the world of listView" . they have great tips that will make your code much better.
for example, you can use getViewTypeCount , getViewType, getItem, as shown on the API .
to view your code i see that you have started your async execution again on postExcecute
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
/* gdy skończy */
adapter.notifyDataSetChanged();
ListView listview2 = (ListView) findViewById(R.id.listView);
listview2.invalidateViews();
//Toast.makeText(ContactsActivity.this, "coś przyszło", Toast.LENGTH_SHORT).show();
Log.d("BBB", "powinno sie odswieżyc");
new PrefetchData().execute();
}
also clearing data inside your doBackground
To get changes on your data you should not clear your data just get updates records and notify your adapeter
try to change the method data.addAll(newlist) by using addall(newlist, data);
inside addall method add one by one the list of element. this way it should work.
i had the same problem and i correct it the way i explained.