How to make app like Flipboard? - android

I want to make an application similar like Flipboard on android like this. I am using gridview for showing Gallery images, but it's not applicable. How can I achieve this? I also want to apply page curl and flip.because page curl and flip.
I have to implement curl effect in flipboard please anyone guide me.

you can achieve it by using ViewFlipper or viewPager APIs.
ViewPager API is supported above ICS. but, for lover version you can use android.support-v4 library.
for View Flipper you can use animation for flipping.
ViewFlipper source code::
import android.app.Activity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.Window;
import android.view.WindowManager;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.ViewFlipper;
public class ViewFlipperActivity extends Activity implements android.view.GestureDetector.OnGestureListener {
/** Called when the activity is first created. */
private int[] imageID = {
R.drawable.a01, R.drawable.a02,
R.drawable.a03, R.drawable.a04,
R.drawable.a05, R.drawable.a06,
R.drawable.a07, R.drawable.a08,
R.drawable.a09, R.drawable.a010,
R.drawable.a011
};
private ViewFlipper viewFlipper = null;
private GestureDetector gestureDetector = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
//Remove notification bar
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
viewFlipper = (ViewFlipper) findViewById(R.id.viewflipper);
// gestureDetector Object is used to detect gesture events
gestureDetector = new GestureDetector(this);
for (int i = 0; i < imageID.length; i++)
{
ImageView image = new ImageView(this);
image.setImageResource(imageID[i]);
image.setScaleType(ImageView.ScaleType.FIT_XY);
viewFlipper.addView(image, new LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
}
}
public boolean onDown(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}
public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
// TODO Auto-generated method stub
if (arg0.getX() - arg1.getX() > 120)
{
this.viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_left_in));
this.viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_left_out));
this.viewFlipper.showNext();
return true;
}
else if (arg0.getX() - arg1.getX() < -120)
{
this.viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_right_in));
this.viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_right_out));
this.viewFlipper.showPrevious();
return true;
}
return true;
}
public void onLongPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
// TODO Auto-generated method stub
return false;
}
public void onShowPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
public boolean onSingleTapUp(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
return this.gestureDetector.onTouchEvent(event);
}
}
View Flipper XML layout:
<ViewFlipper
android:id="#+id/viewflipper"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
ViewPager dource code::
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.Menu;
import android.view.View;
import android.widget.ImageView;
public class MainActivity extends Activity {
private ViewPager viewPager;
private static int NUM_AWESOME_VIEWS = 20;
private Context cxt;
private pageradapter adapter;;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cxt = this;
adapter = new pageradapter();
viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setAdapter(adapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
private class pageradapter extends PagerAdapter{
#Override
public int getCount() {
return NUM_AWESOME_VIEWS;
}
/**
* Create the page for the given position. The adapter is responsible
* for adding the view to the container given here, although it only
* must ensure this is done by the time it returns from
* {#link #finishUpdate()}.
*
* #param container The containing View in which the page will be shown.
* #param position The page position to be instantiated.
* #return Returns an Object representing the new page. This does not
* need to be a View, but can be some other container of the page.
*/
#Override
public Object instantiateItem(View collection, int position) {
ImageView iv = new ImageView(cxt);
iv.setBackgroundResource(R.drawable.a01);
((ViewPager) collection).addView(iv,0);
return iv;
}
/**
* Remove a page for the given position. The adapter is responsible
* for removing the view from its container, although it only must ensure
* this is done by the time it returns from {#link #finishUpdate()}.
*
* #param container The containing View from which the page will be removed.
* #param position The page position to be removed.
* #param object The same object that was returned by
* {#link #instantiateItem(View, int)}.
*/
#Override
public void destroyItem(View collection, int position, Object view) {
((ViewPager) collection).removeView((ImageView) view);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view==((ImageView)object);
}
/**
* Called when the a change in the shown pages has been completed. At this
* point you must ensure that all of the pages have actually been added or
* removed from the container as appropriate.
* #param container The containing View which is displaying this adapter's
* page views.
*/
#Override
public void finishUpdate(View arg0) {}
#Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {}
#Override
public Parcelable saveState() {
return null;
}
#Override
public void startUpdate(View arg0) {
}
}
}
viewPager XML layout::
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v4.view.ViewPager
android:id="#+android:id/viewpager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</RelativeLayout>

Not sure about the layout but this page flipping animation tutorial might help:
http://openaphid.github.com/blog/2012/05/21/how-to-implement-flipboard-animation-on-android/

If someone uses library from accepted answer and needs to flip pages without swipe gesture (for example to implement next and previous buttons) can use methods which I did for myself. I spend a while to figure out how does the library works so I think it can be helpful.
add this to FlipCards.java
protected void flipToNextCard()
{
if(accumulatedAngle >= (maxIndex-1)*180 || state != STATE_INIT)
return;
controller.showFlipAnimation();
forward = true;
setState(STATE_AUTO_ROTATE);
controller.getSurfaceView().requestRender();
}
protected void flipToPreviousCard()
{
if(accumulatedAngle <= 0 || state != STATE_INIT)
return;
controller.showFlipAnimation();
forward = false;
swapCards();
frontCards.resetWithIndex(backCards.getIndex() - 1);
controller.flippedToView(getPageIndexFromAngle(accumulatedAngle-1), false);
setState(STATE_AUTO_ROTATE);
controller.getSurfaceView().requestRender();
}
and this to FlipViewController.java
public void flipToNextView()
{
cards.flipToNextCard();
}
public void flipToPreviousView()
{
cards.flipToPreviousCard();
}

Related

ViewPager and YouTubePlayer

In my actvity I have a viewPager with for example 3 pages.
In all of theses pages, I have a YouTubePlayer with a different id video.
The problem is that all the YouTubePlayer component has the same video at the same time.
Concretely :
When the first page is displayed, the YouTubePlayer show the first video, so all seems to be ok.
When I try to scroll to the 2nd page, I can see that the 2nd YouTubePlayer show the same video.
When the 2nd page is completely displayed (After scrolling), behind the view pager prepare the 3rd page. So on the 3rd page the 3rd id video is set to the YouTubePlayer component. At that moment the 2nd page currently displayed switch automatically to the 3rd video.
It was like if the instance of YouTubePlayer was single for all the pages.
But on each page new FragmentYouTubePlayer() is correctly called.
I don't understand where is the problem.
Finally, I wonder if it's possible to use severals YouTubePlayer component (in a viewpager) at the same time or not ?
Thanks for your help.
I don't remember exactly what was wrong, but yes, I solved my problem. So, if it can help you, here is the code :
In my main activity, using PagerAdapter :
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public ScreenSlidePagerAdapter(android.support.v4.app.FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
fragmentYouTubeContent = FragmentYouTubeContent.create(position);
return fragmentYouTubeContent;
}
#Override
public int getCount() {
int nb = 3;
return nb;
}
}
My FragmentYouTubeContent.class
package com.orange.OrangeJobs;
import java.util.List;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubeStandalonePlayer;
import com.google.android.youtube.player.YouTubeThumbnailLoader;
import com.google.android.youtube.player.YouTubeThumbnailView;
import android.support.v4.app.Fragment;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
public class FragmentYouTubeContent extends Fragment implements YouTubeThumbnailView.OnInitializedListener {
public static final int REQ_START_STANDALONE_PLAYER = 101;
private static final int REQ_RESOLVE_SERVICE_MISSING = 2;
private static final int RECOVERY_DIALOG_REQUEST = 1;
/**
* The fragment's page number.
*/
private int mPageNumber;
private String urlYouTube;
private boolean canHideStatusBar = false;
private Dialog errorDialog;
FrameLayout rl;
private YouTubeThumbnailView thumbnailView;
/**
* Factory method for this fragment class. Constructs a new fragment for the given page number.
*/
public static FragmentYouTubeContent create(int pageNumber) {
FragmentYouTubeContent fragment = new FragmentYouTubeContent();
fragment.setPageNumber(pageNumber);
return fragment;
}
public FragmentYouTubeContent() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#SuppressLint("InlinedApi")
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setRetainInstance(true);
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.youtube, container, false);
urlYouTube = "YOUR_VIDEO_URL";
if (!"".equals(urlYouTube)) {
thumbnailView = (YouTubeThumbnailView) rootView.findViewById(R.id.youtubethumbnailview);
thumbnailView.initialize(Params.YOUTUBE_KEY, this);
thumbnailView.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
// Launch standalone YoutTube player
Intent intent = null;
intent = YouTubeStandalonePlayer.createVideoIntent(getActivity(), YOUTUBE_KEY, urlYouTube, 0, true, false);
if (intent != null) {
if (canResolveIntent(intent)) {
canHideStatusBar = true;
startActivityForResult(intent, REQ_START_STANDALONE_PLAYER);
} else {
// Could not resolve the intent - must need to install or update the YouTube API service.
YouTubeInitializationResult
.SERVICE_MISSING
.getErrorDialog(getActivity(), REQ_RESOLVE_SERVICE_MISSING).show();
}
}
}});
}
return rootView;
}
#Override
public void onResume() {
super.onResume();
boolean isLandscape = false;
int currentOrientation = getResources().getConfiguration().orientation;
if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
isLandscape = true;
}
else {
isLandscape = false;
}
if (canHideStatusBar && this.isVisible() && isLandscape) {
Utils.hideStatusBar(getActivity());
canHideStatusBar = false;
}
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onInitializationSuccess(YouTubeThumbnailView thumbnailView, YouTubeThumbnailLoader thumbnailLoader) {
thumbnailLoader.setVideo(urlYouTube);
}
#Override
public void onInitializationFailure(YouTubeThumbnailView thumbnailView, YouTubeInitializationResult errorReason) {
if (errorReason.isUserRecoverableError()) {
if (errorDialog == null || !errorDialog.isShowing()) {
errorDialog = errorReason.getErrorDialog(getActivity(), RECOVERY_DIALOG_REQUEST);
errorDialog.show();
}
} else {
String errorMessage = String.format(getString(R.string.error_thumbnail_view), errorReason.toString());
Toast.makeText(getActivity(), errorMessage, Toast.LENGTH_LONG).show();
}
}
// ***** Private methods *************************************************************************************
private boolean canResolveIntent(Intent intent) {
List<ResolveInfo> resolveInfo = getActivity().getPackageManager().queryIntentActivities(intent, 0);
return resolveInfo != null && !resolveInfo.isEmpty();
}
// ***** Properties methods *************************************************************************************
/**
* Returns the page number represented by this fragment object.
*/
public int getPageNumber() {
return mPageNumber;
}
/**
* #param pageNumber the pageNumber to set
*/
public void setPageNumber(int pageNumber) {
this.mPageNumber = pageNumber;
}
/**
* #return the canHideStatusBar
*/
public boolean isCanHideStatusBar() {
return canHideStatusBar;
}
/**
* #param canHideStatusBar the canHideStatusBar to set
*/
public void setCanHideStatusBar(boolean canHideStatusBar) {
this.canHideStatusBar = canHideStatusBar;
}
}
My layout : youtube.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:background="#color/black"
android:scrollbarStyle="outsideOverlay"
android:orientation="horizontal" >
<com.google.android.youtube.player.YouTubeThumbnailView
android:id="#+id/youtubethumbnailview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:contentDescription="#string/empty_string"
android:src="#drawable/ic_media_embed_play"
/>
</RelativeLayout>

Progress Bar set visible on each page of ViewPager

I have a viewpager that loads the images selected by the user from gallery.
At the last page of that viewpager, I have an upload button.
The button is supposed to load the images in viewpager to a website. However, my problem is here, I want to show a progressbar under each image in the viewpager.
in my xml file, I have the progressbar as invisible, and whenever the user presses the upload bar, the progressbar is set to visible.
This works fine for the current position I am in (which is the last). However, if I swipe backwards, I do not see the progressbar.
I need to show the progressbar under each image in viewpager not just the last page.
Any help is appreciated.
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ActivityInfo;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.app.NotificationCompat;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import java.util.ArrayList;
public class ViewPagerAdapter extends PagerAdapter {
// Declare Variables
int click=0;
int execute=0;
private NotificationManager mNotifyManager;
private NotificationCompat.Builder mBuilder;
View itemView;
int id=1;
Context context;
int number_pages;
ArrayList<Uri> uris;
LayoutInflater inflater;
/**
* get the information from the other activity
* #param context
* #param imageUris paths of the images
* #param number_images : number of pages displayed according to the number of images selected
*/
public ViewPagerAdapter(Context context, ArrayList<Uri> imageUris, int number_images) {
this.context = context;
this.uris = imageUris;
this.number_pages = number_images;
}
/**
* get the number of pages to be used by the initiate number
* #return number of pages
*/
#Override
public int getCount() {
return number_pages;
}
/**
* get the layout
* #param view
* #param object
* #return
*/
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((RelativeLayout) object);
}
/**
* initiate the items of the pages
* #param container
* #param position : position of the current page
* #return the view
*/
#Override
public Object instantiateItem(ViewGroup container, final int position) {
ImageView img;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
itemView = inflater.inflate(R.layout.viewpager_item, container, false);
final ProgressBar spinner= (ProgressBar)itemView.findViewById(R.id.loading);
Button btn = (Button) itemView.findViewById(R.id.button);
// Locate the ImageView in viewpager_item.xml
img = (ImageView) itemView.findViewById(R.id.View1);
// Capture position and set to the ImageView
img.setImageURI(uris.get(position));
if (number_pages - position == 1) {
btn.setVisibility(View.VISIBLE);
}
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
click=1;
CustomViewPagerListener spinners = new CustomViewPagerListener();
spinners.onPageScrolled(position,10,10);
spinners.onPageSlected(position);
final ConnectivityManager connMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
final android.net.NetworkInfo wifi = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
final android.net.NetworkInfo mobile = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (wifi.isAvailable() && wifi.getDetailedState() == NetworkInfo.DetailedState.CONNECTED || mobile.isAvailable() && mobile.getDetailedState() == NetworkInfo.DetailedState.CONNECTED) {
for (int i = 0; i < number_pages; i++) {
mNotifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(context);
mBuilder.setContentTitle("Upload").setContentText("Upload in Porgress").setSmallIcon(R.drawable.ic_launcher);
new Uploader().execute();
}
}
else{
//show alert box
AlertDialog alertDialog = new AlertDialog.Builder(context).create();
alertDialog.setTitle("Error Uploading");
alertDialog.setMessage("Please make sure you are connected to the internet");
alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//ok
}
});
alertDialog.show();
}
}
class Uploader extends AsyncTask<Void, Integer, Integer> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Displays the progress bar for the first time.
mBuilder.setProgress(100, 0, false);
mNotifyManager.notify(id, mBuilder.build());
}
#Override
protected void onProgressUpdate(Integer... values) {
// Update progress
mBuilder.setProgress(100, values[0], false);
mNotifyManager.notify(id, mBuilder.build());
super.onProgressUpdate(values);
}
#Override
protected Integer doInBackground(Void... params) {
int i;
execute++;
for (i = 0; i <= 100; i += 20) {
// Sets the progress indicator completion percentage
publishProgress(Math.min(i, 100));
try {
// Sleep for 5 seconds
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
Log.d("TAG", "sleep failure");
}
}
return null;
}
#Override
protected void onPostExecute(Integer result) {
super.onPostExecute(result);
if(execute==number_pages-1){
mBuilder.setContentText("Upload Complete");
}
// Removes the progress bar
mBuilder.setProgress(0, 0, false);
mNotifyManager.notify(id, mBuilder.build());
}
}
});
// Add viewpager_item.xml to ViewPager
((ViewPager) container).addView(itemView);
return itemView;
}
/**
* Destroy the item of the views when done
* #param container
* #param position
* #param object
*/
#Override
public void destroyItem (ViewGroup container,int position, Object object){
// Remove viewpager_item.xml from ViewPager
((ViewPager) container).removeView((RelativeLayout) object);
}
private class CustomViewPagerListener extends ViewPager.SimpleOnPageChangeListener {
final ProgressBar spinner= (ProgressBar)itemView.findViewById(R.id.loading);
#Override
public void onPageSelected(int p){
if(click==1){
spinner.setVisibility(View.VISIBLE);
}
}
#Override
public void onPageScrolled(int p, float positionOffset, int positionOffsetPixels) {
if(click==1)
spinner.setVisibility(View.VISIBLE);
}
}
}
XML Example :
<RealtiveLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
</ViewPager>
<ProgressBar
....
android:layout_alignParentBottom="true" />
this will cause to the Progress to be on all Items cause the progress bar is not included to the ViewPager at all.

Singleton variable not being updated. Always reset

I posted a question yesterday regarding a problem with my listview. The state of an image button in the listview wasn't saved (it was reset to default state (unchecked)).
Android listview image button
However much I tried, I was unable to resolve it.
Rigt now though, I've got a problem with singletons:
I want to save a string from a row object when it's image button is "checked" and send it to a singleton ArrayList<String>.
The weird part is that the ArrayList only contains one element at the most and it even "flushes" (removes all objects) without being prompted to.
MainActivity (CONTAINS THE SINGLETON!!!)
package com.example.geostocks;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.json.JSONArray;
import org.json.JSONException;
import com.example.geostocks.R;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.SearchView;
/* MainActivity.
* Made by: Joakim Bajoul Kakaei (881129-0298)
* Description: Creates and sets up the MainActivity programmatically.
* It is mainly associated with activity_main.xml, but uses the
* listview_layout.xml in connection to it.
*
* The idea was to keep the class as "clean" as possible and use
* multiple classes to help making coding and efficiency more easier.
*/
public class MainActivity extends Activity {
public static ArrayList<String> checkedCompanies = new ArrayList<String>();
public Menu m; // Variable to store a menu-item as a public variable.
// This helps with data allocation; instead of declaring the
// searchview and searchmanager in the creation of the
// application,
// it will wait to do it once the user decides to start the
// search.
// an array to store all jsonobjects in.
private JSONArray companies;
// an arraylist to store multiple companyobjects created later.
private List<companiesBuilder> allCompanies = new ArrayList<companiesBuilder>();
/*
* (non-Javadoc)
*
* #see android.app.Activity#onCreate(android.os.Bundle)
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
/*
* executes the AsyncTask (top10). When the task is executed, it
* then gets the JSONArray which is bouncing around.
*/
companies = new top10().execute("DO IT!").get();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ExecutionException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
/*
* The following snippet mainly creates the adapterobject and associates
* it with it's elements, context and layout.
*/
final ListView companyList = (ListView) findViewById(R.id.listView);
final companiesAdapter compAdp = new companiesAdapter(this,
R.layout.listview_layout);
System.out.println("after"); // debugging
/*
* a loop to create companyBuilder-objects from the JSONArray and then
* add those objects to an ArrayList (allCompanies).
*/
for (int i = 0; companies.length() > i; i++) {
System.out.println("companies-looper"); // debugging
System.out.println(companies.length()); // debugging
try {
System.out.println(companies.getJSONObject(i)); // debugging
allCompanies.add(new companiesBuilder(companies
.getJSONObject(i)));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* this loop goes through every company that has been built and adds it
* to the custom listview adapter.
*/
for (companiesBuilder built : allCompanies) {
compAdp.add(built);
}
companyList.setAdapter(compAdp);
}
/*
* (non-Javadoc)
*
* #see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
m = menu; // adds a reference to the variable m (menu).
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return (super.onCreateOptionsMenu(menu)); // returns the super for
// efficiency.
}
/*
* (non-Javadoc)
*
* #see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.search:
openSearch(); // when searchbutton is clicked, it will start the
// opensearch method.
return true;
case R.id.action_settings:
// openSettings();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/*
* Written by: Joakim Bajoul Kakaei Description: Invoked when user presses
* search icon. Opens up the searchview in the menu.
*/
public void openSearch() {
/*
* snippet taken from
* http://developer.android.com/training/search/setup.html with some
* changes to it.
*/
SearchManager sm = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView sv = (SearchView) m.findItem(R.id.search).getActionView();
sv.setSearchableInfo(sm.getSearchableInfo(getComponentName()));
}
/*
* top10 (AsyncTask) Name: Joakim Bajoul Kakaei (881129-0298) Description:
* This class handles the connection between the JSONparser and the
* mainActivity using a different thread. It's mainly used to help with
* memory allocation as well as making sure the main-thread isn't too
* overloaded with too many assignments.
*/
private class top10 extends AsyncTask<String, String, JSONArray> {
#Override
protected JSONArray doInBackground(String... params) {
JSONparser jparser = new JSONparser();
companies = jparser.topCompanies();
System.out.println("background"); // debugging
return companies;
}
#Override
protected void onPostExecute(JSONArray jarr) {
System.out.println("onpost");
}
}
}
SearchActivity (onBackPressed() is called here to display all elements in the singleton)
package com.example.geostocks;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.json.JSONArray;
import org.json.JSONException;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.KeyEvent;
import android.widget.ListView;
public class SearchActivity extends Activity {
JSONArray companies;
String query;
private List<companiesBuilder> allCompanies = new ArrayList<companiesBuilder>();
companiesAdapter compAdp;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
handleIntent(getIntent());
try {
/*
* executes the AsyncTask (top10). When the task is executed, it
* then gets the JSONArray which is bouncing around.
*/
companies = new searchList().execute("DO IT!").get();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ExecutionException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
/*
* The following snippet mainly creates the adapterobject and associates
* it with it's elements, context and layout.
*/
final ListView companyList = (ListView) findViewById(R.id.listView_search);
compAdp = new companiesAdapter(this, R.layout.listview_layout);
System.out.println("after"); // debugging
/*
* a loop to create companyBuilder-objects from the JSONArray and then
* add those objects to an ArrayList (allCompanies).
*/
for (int i = 0; companies.length() > i; i++) {
System.out.println("companies-looper"); // debugging
System.out.println(companies.length()); // debugging
try {
System.out.println(companies.getJSONObject(i)); // debugging
allCompanies.add(new companiesBuilder(companies
.getJSONObject(i)));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* this loop goes through every company that has been built and adds it
* to the custom listview adapter.
*/
for (companiesBuilder built : allCompanies) {
for (int i = 0; i < MainActivity.checkedCompanies.size(); i++) {
System.out.println("CHECKED" + MainActivity.checkedCompanies.get(i));
if (MainActivity.checkedCompanies.get(i).equals(built.getSymbol())) {
built.setSelect(true);
}
}
compAdp.add(built);
}
companyList.setAdapter(compAdp);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
super.onBackPressed();
System.out.println(MainActivity.checkedCompanies.size());
System.out.println("BACK PRESSED!");
for (int i = 0; i < MainActivity.checkedCompanies.size(); i++) {
System.out.println("CHECKED" + MainActivity.checkedCompanies.get(i));
}
}
return true;
}
#Override
protected void onNewIntent(Intent intent) {
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
query = intent.getStringExtra(SearchManager.QUERY);
System.out.println(query);
// use the query to search your data somehow
}
}
private class searchList extends AsyncTask<String, String, JSONArray> {
#Override
protected JSONArray doInBackground(String... params) {
JSONparser jparser = new JSONparser();
companies = jparser.search(query);
System.out.println("background"); // debugging
return companies;
}
#Override
protected void onPostExecute(JSONArray jarr) {
System.out.println("onpost");
}
}
}
CompaniesAdapter (Where I have a onClickListener to the ImageButton and it tries to
manipulate the singleton):
package com.example.geostocks;
import java.util.ArrayList;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.TextView;
/* companiesAdapter.
* Made by: Joakim Bajoul Kakaei (881129-0298)
* Description: Since the listview we have decided to use has multiple objects on each row,
* the listview's adapter needs to be customized to meet those requirements.
* This class may be revised later on (to add or remove objects from the rowItemObjects).
*/
public class companiesAdapter extends ArrayAdapter<companiesBuilder> implements
OnClickListener {
private final int companiesBuilderResource;
private ArrayList<companiesBuilder> companies;
private static ArrayList<String> checked = new ArrayList<String>();
public companiesAdapter(final Context context,
final int companiesBuilderResource) {
super(context, 0);
this.companiesBuilderResource = companiesBuilderResource;
companies = new ArrayList<companiesBuilder>();
}
public void addChecked(String symbol) {
MainActivity.checkedCompanies.add(symbol);
}
public void removeChecked(String symbol) {
MainActivity.checkedCompanies.remove(symbol);
}
public void add(companiesBuilder row) {
companies.add(row);
notifyDataSetChanged();
}
#Override
public int getCount() {
return companies.size();
}
#Override
public companiesBuilder getItem(int i) {
return companies.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(final int position, final View convertView,
final ViewGroup parent) {
// We need to get the best view (re-used if possible) and then
// retrieve its corresponding rowItem, to optimize lookup efficiency.
final View view = getourView(convertView);
final rowItem rowItem = getrowItem(view);
// final companiesBuilder company = getItem(position);
final companiesBuilder row = companies.get(position);
// Setting up both the titleobject's with their corresponding variables
// (from the row-object).
rowItem.titleView_left.setText(row.getName());
rowItem.titleView_right.setText(row.getPrice());
// Setting up the subtitle's items will be a little bit tougher, since
// it requires
// some manipulating of the xml-data.
rowItem.subTitleView_left.setText(row.getSymbol());
/*
* If-clauses to change the right subtitle's color palette to make it
* easier for the user to distinguish increase and decrease.
*/
if (Double.parseDouble(row.getChange()) < 0) {
rowItem.subTitleView_right
.setTextColor(Color.parseColor("#E51400"));
rowItem.subTitleView_right.setText(row.getPercent() + "%" + " "
+ "( " + row.getChange() + ")");
} else if (Double.parseDouble(row.getChange()) > 0) {
rowItem.subTitleView_right
.setTextColor(Color.parseColor("#339933"));
rowItem.subTitleView_right.setText(row.getPercent() + "%" + " "
+ "( +" + row.getChange() + ")");
} else {
rowItem.subTitleView_right.setText(row.getPercent() + "%" + " "
+ "(" + row.getChange() + ")");
}
// Setting image view is simple enough...
for (int i = 0; checked.size() > i; i++) {
System.out.println("CHECKED" + checked.get(i));
}
rowItem.imageButton.setSelected(row.getSelected());
view.setOnClickListener(new OnClickListener() {
/*
* Add an onClickListener that is associated with view (view being
* every row).
*/
#Override
public void onClick(View v) {
new AlertDialog.Builder(getContext()).setTitle(row.getName())
.show();
}
});
rowItem.imageButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View button) {
if (button.isSelected()) {
button.setSelected(false);
addChecked(row.getSymbol());
} else {
button.setSelected(true);
removeChecked(row.getSymbol());
}
row.setSelect(view.isSelected());
for (int i = 0; MainActivity.checkedCompanies.size() > i; i++) {
System.out.println("CHECKEDLOOP"
+ MainActivity.checkedCompanies.get(i));
}
}
});
return view;
}
private View getourView(final View convertView) {
// The ourView will be recycling / reusing the convertview if
// possible.
// Guess why? Exactly. CUZ WE LOOOOOOOOOOVE HAVING EFFICIENT CODE! <3
View ourView = null;
if (null == convertView) {
final Context context = getContext();
final LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ourView = inflater.inflate(companiesBuilderResource, null);
} else {
ourView = convertView;
}
return ourView;
}
private rowItem getrowItem(final View ourView) {
// Recycling and reusing tags and objects is the name of the game!
final Object tag = ourView.getTag();
rowItem rowItem = null;
/*
* Sets up the listview's rowitems with their corresponding listview
* items (textviews and images).
*/
if (null == tag || !(tag instanceof rowItem)) {
rowItem = new rowItem();
rowItem.titleView_right = (TextView) ourView
.findViewById(R.id.title_right);
rowItem.titleView_left = (TextView) ourView
.findViewById(R.id.title_left);
rowItem.subTitleView_left = (TextView) ourView
.findViewById(R.id.subtitle_left);
rowItem.subTitleView_right = (TextView) ourView
.findViewById(R.id.subtitle_right);
rowItem.imageButton = (ImageButton) ourView
.findViewById(R.id.add_button);
ourView.setTag(rowItem);
} else {
rowItem = (rowItem) tag;
}
return rowItem;
}
/*
* since views are recycled, these references will always be there to be
* reused. Again, it's all about optimization!
*/
private static class rowItem {
public TextView titleView_left;
public TextView titleView_right;
public TextView subTitleView_left;
public TextView subTitleView_right;
public ImageButton imageButton;
}
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
}
}
I've also tried using a global variable in the sense that I used a class with the application=name.
However, I can't use that class in the adapter. This in turn makes it impossible for me to manipulate said global variables, since context is missing.
This is the global class:
package com.example.geostocks;
import java.util.ArrayList;
import android.app.Application;
public class checkedCompanies extends Application{
private ArrayList<companiesBuilder> checked = new ArrayList<companiesBuilder>();
public ArrayList<companiesBuilder> get() {
return checked;
}
public void set(companiesBuilder built) {
checked.add(built);
}
public void remove(companiesBuilder removeIndex){
checked.remove(removeIndex);
}
}

Android listview image button

First of all I'd like to thank all of you for helping me on numerous occasions before. SO have alwasy been my go-to place when faced with problems with programming.
This time however, I've been unable to find a solution to my problem...
I'm currently developing an android app that uses two activities (one main activity and a search activity).
Both of which hold a listview - the main activity has an already populated and fully functional listview and, the search activity has a populated one which seems to lack functionallity.
The listview is created in a custom adapter and contains an image button (toggling with a selector) and four textviews.
My problem is that when I toggle the image button in my search activity and then press back to get back to the main activity and finally go back to the search results, the image button is "unchecked".
Since the image button is a CRUCIAL point in both the design and the following functionallity, I'd really appriciate any kind of help.
package com.example.geostocks;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.json.JSONArray;
import org.json.JSONException;
import com.example.geostocks.R;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.SearchView;
/* MainActivity.
* Made by: Joakim Bajoul Kakaei (881129-0298)
* Description: Creates and sets up the MainActivity programmatically.
* It is mainly associated with activity_main.xml, but uses the
* listview_layout.xml in connection to it.
*
* The idea was to keep the class as "clean" as possible and use
* multiple classes to help making coding and efficiency more easier.
*/
public class MainActivity extends Activity {
public Menu m; // Variable to store a menu-item as a public variable.
// This helps with data allocation; instead of declaring the
// searchview and searchmanager in the creation of the
// application,
// it will wait to do it once the user decides to start the
// search.
// an array to store all jsonobjects in.
private JSONArray companies;
// an arraylist to store multiple companyobjects created later.
private List<companiesBuilder> allCompanies = new ArrayList<companiesBuilder>();
/*
* (non-Javadoc)
*
* #see android.app.Activity#onCreate(android.os.Bundle)
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
/*
* executes the AsyncTask (top10). When the task is executed, it
* then gets the JSONArray which is bouncing around.
*/
companies = new top10().execute("DO IT!").get();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ExecutionException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
/*
* The following snippet mainly creates the adapterobject and associates
* it with it's elements, context and layout.
*/
final ListView companyList = (ListView) findViewById(R.id.listView);
final companiesAdapter compAdp = new companiesAdapter(this,
R.layout.listview_layout);
System.out.println("after"); // debugging
/*
* a loop to create companyBuilder-objects from the JSONArray and then
* add those objects to an ArrayList (allCompanies).
*/
for (int i = 0; companies.length() > i; i++) {
System.out.println("companies-looper"); // debugging
System.out.println(companies.length()); // debugging
try {
System.out.println(companies.getJSONObject(i)); // debugging
allCompanies.add(new companiesBuilder(companies
.getJSONObject(i)));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* this loop goes through every company that has been built and adds it
* to the custom listview adapter.
*/
for (companiesBuilder built : allCompanies) {
compAdp.add(built);
}
companyList.setAdapter(compAdp);
}
/*
* (non-Javadoc)
*
* #see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
m = menu; // adds a reference to the variable m (menu).
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return (super.onCreateOptionsMenu(menu)); // returns the super for
// efficiency.
}
/*
* (non-Javadoc)
*
* #see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.search:
openSearch(); // when searchbutton is clicked, it will start the
// opensearch method.
return true;
case R.id.action_settings:
// openSettings();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/*
* Written by: Joakim Bajoul Kakaei Description: Invoked when user presses
* search icon. Opens up the searchview in the menu.
*/
public void openSearch() {
/*
* snippet taken from
* http://developer.android.com/training/search/setup.html with some
* changes to it.
*/
SearchManager sm = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView sv = (SearchView) m.findItem(R.id.search).getActionView();
sv.setSearchableInfo(sm.getSearchableInfo(getComponentName()));
}
/*
* top10 (AsyncTask) Name: Joakim Bajoul Kakaei (881129-0298) Description:
* This class handles the connection between the JSONparser and the
* mainActivity using a different thread. It's mainly used to help with
* memory allocation as well as making sure the main-thread isn't too
* overloaded with too many assignments.
*/
private class top10 extends AsyncTask<String, String, JSONArray> {
#Override
protected JSONArray doInBackground(String... params) {
JSONparser jparser = new JSONparser();
companies = jparser.topCompanies();
System.out.println("background"); // debugging
return companies;
}
#Override
protected void onPostExecute(JSONArray jarr) {
System.out.println("onpost");
}
}
}
package com.example.geostocks;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.json.JSONArray;
import org.json.JSONException;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.ListView;
public class SearchActivity extends Activity {
JSONArray companies;
String query;
private List<companiesBuilder> allCompanies = new ArrayList<companiesBuilder>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
handleIntent(getIntent());
try {
/*
* executes the AsyncTask (top10). When the task is executed, it
* then gets the JSONArray which is bouncing around.
*/
companies = new searchList().execute("DO IT!").get();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ExecutionException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
/*
* The following snippet mainly creates the adapterobject and associates
* it with it's elements, context and layout.
*/
final ListView companyList = (ListView) findViewById(R.id.listView_search);
final companiesAdapter compAdp = new companiesAdapter(this,
R.layout.listview_layout);
System.out.println("after"); // debugging
/*
* a loop to create companyBuilder-objects from the JSONArray and then
* add those objects to an ArrayList (allCompanies).
*/
for (int i = 0; companies.length() > i; i++) {
System.out.println("companies-looper"); // debugging
System.out.println(companies.length()); // debugging
try {
System.out.println(companies.getJSONObject(i)); // debugging
allCompanies.add(new companiesBuilder(companies
.getJSONObject(i)));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* this loop goes through every company that has been built and adds it
* to the custom listview adapter.
*/
for (companiesBuilder built : allCompanies) {
compAdp.add(built);
}
companyList.setAdapter(compAdp);
}
#Override
public void onBackPressed() {
super.onBackPressed();
}
#Override
protected void onNewIntent(Intent intent) {
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
query = intent.getStringExtra(SearchManager.QUERY);
System.out.println(query);
// use the query to search your data somehow
}
}
private class searchList extends AsyncTask<String, String, JSONArray> {
#Override
protected JSONArray doInBackground(String... params) {
JSONparser jparser = new JSONparser();
companies = jparser.search(query);
System.out.println("background"); // debugging
return companies;
}
#Override
protected void onPostExecute(JSONArray jarr) {
System.out.println("onpost");
}
}
}
Custom listviewAdapter:
package com.example.geostocks;
import java.util.ArrayList;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.TextView;
/* companiesAdapter.
* Made by: Joakim Bajoul Kakaei (881129-0298)
* Description: Since the listview we have decided to use has multiple objects on each row,
* the listview's adapter needs to be customized to meet those requirements.
* This class may be revised later on (to add or remove objects from the rowItemObjects).
*/
public class companiesAdapter extends ArrayAdapter<companiesBuilder> implements
OnClickListener {
private final int companiesBuilderResource;
private ArrayList<companiesBuilder> companies;
public companiesAdapter(final Context context,
final int companiesBuilderResource) {
super(context, 0);
this.companiesBuilderResource = companiesBuilderResource;
companies = new ArrayList<companiesBuilder>();
}
public void add(companiesBuilder row) {
companies.add(row);
notifyDataSetChanged();
}
#Override
public int getCount() {
return companies.size();
}
#Override
public companiesBuilder getItem(int i) {
return companies.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(final int position, final View convertView,
final ViewGroup parent) {
// We need to get the best view (re-used if possible) and then
// retrieve its corresponding rowItem, to optimize lookup efficiency.
final View view = getourView(convertView);
final rowItem rowItem = getrowItem(view);
// final companiesBuilder company = getItem(position);
final companiesBuilder row = companies.get(position);
// Setting up both the titleobject's with their corresponding variables
// (from the row-object).
rowItem.titleView_left.setText(row.getName());
rowItem.titleView_right.setText(row.getPrice());
// Setting up the subtitle's items will be a little bit tougher, since
// it requires
// some manipulating of the xml-data.
rowItem.subTitleView_left.setText(row.getSymbol());
/*
* If-clauses to change the right subtitle's color palette to make it
* easier for the user to distinguish increase and decrease.
*/
if (Double.parseDouble(row.getChange()) < 0) {
rowItem.subTitleView_right
.setTextColor(Color.parseColor("#E51400"));
rowItem.subTitleView_right.setText(row.getPercent() + "%" + " "
+ "( " + row.getChange() + ")");
} else if (Double.parseDouble(row.getChange()) > 0) {
rowItem.subTitleView_right
.setTextColor(Color.parseColor("#339933"));
rowItem.subTitleView_right.setText(row.getPercent() + "%" + " "
+ "( +" + row.getChange() + ")");
} else {
rowItem.subTitleView_right.setText(row.getPercent() + "%" + " "
+ "(" + row.getChange() + ")");
}
// Setting image view is simple enough...
rowItem.imageButton.setSelected(row.getSelected());
view.setOnClickListener(new OnClickListener() {
/*
* Add an onClickListener that is associated with view (view being
* every row).
*/
#Override
public void onClick(View v) {
new AlertDialog.Builder(getContext()).setTitle(row.getName())
.show();
}
});
rowItem.imageButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View button) {
if (button.isSelected()) {
button.setSelected(false);
} else {
button.setSelected(true);
}
row.setSelect(view.isSelected());
}
});
return view;
}
private View getourView(final View convertView) {
// The ourView will be recycling / reusing the convertview if
// possible.
// Guess why? Exactly. CUZ WE LOOOOOOOOOOVE HAVING EFFICIENT CODE! <3
View ourView = null;
if (null == convertView) {
final Context context = getContext();
final LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ourView = inflater.inflate(companiesBuilderResource, null);
} else {
ourView = convertView;
}
return ourView;
}
private rowItem getrowItem(final View ourView) {
// Recycling and reusing tags and objects is the name of the game!
final Object tag = ourView.getTag();
rowItem rowItem = null;
/*
* Sets up the listview's rowitems with their corresponding listview
* items (textviews and images).
*/
if (null == tag || !(tag instanceof rowItem)) {
rowItem = new rowItem();
rowItem.titleView_right = (TextView) ourView
.findViewById(R.id.title_right);
rowItem.titleView_left = (TextView) ourView
.findViewById(R.id.title_left);
rowItem.subTitleView_left = (TextView) ourView
.findViewById(R.id.subtitle_left);
rowItem.subTitleView_right = (TextView) ourView
.findViewById(R.id.subtitle_right);
rowItem.imageButton = (ImageButton) ourView
.findViewById(R.id.add_button);
ourView.setTag(rowItem);
} else {
rowItem = (rowItem) tag;
}
return rowItem;
}
/*
* since views are recycled, these references will always be there to be
* reused. Again, it's all about optimization!
*/
private static class rowItem {
public TextView titleView_left;
public TextView titleView_right;
public TextView subTitleView_left;
public TextView subTitleView_right;
public ImageButton imageButton;
}
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
}
}
Selector for imagebutton
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/ic_added_button" android:state_selected="true"/>
<item android:drawable="#drawable/ic_add_button" android:state_selected="false"/>
</selector>
Create model for companies (ex. Company class).
In Company class add property isSelected.
Fill array of companies from your JSONArray. Pass this array to ListView adapter.
In rowItem.imageButton.setOnClickListener update rowItem state (selected or not) in source array (array of companies, which was created from JSONArray).
Note: if you will save list row state, you should save this state in source array of your list adapter.
In MainActivity:
CompanyListAdapter adapter = new CompanyListAdapter(activity);
ArrayList<Company> companies = getCompaniesFromJsonArray();
for(Company company : companies){
adapter.add(company);
}
listView.setAdapter(adapter);
Company.java
package com.donvigo.TestCustomActionBar;
public class Company {
private String name;
private boolean isSelected;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isSelected() {
return isSelected;
}
public void setSelected(boolean isSelected) {
this.isSelected = isSelected;
}
}
CompanyListAdapter.java
package com.donvigo.TestCustomActionBar;
import android.app.Activity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
public class CompanyListAdapter extends BaseAdapter {
private Activity activity;
private ArrayList<Company> companies;
public CompanyListAdapter(Activity activity){
this.activity = activity;
companies = new ArrayList<Company>();
}
public void add(Company company){
companies.add(company);
notifyDataSetChanged();
}
#Override
public int getCount() {
return companies.size();
}
#Override
public Object getItem(int i) {
return companies.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
ViewHolder holder;
if(convertView == null){
convertView = activity.getLayoutInflater().inflate(R.layout.list_row_layout, null);
holder = new ViewHolder();
holder.textViewName = (ImageView) convertView.findViewById(R.id.textViewName);
holder.rowImage = (ImageView) convertView.findViewById(R.id.rowImage);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
final Company row = companies.get(position);
// refresh state of your row image
holder.rowImage.setSelected(row.isSelected());
holder.rowImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (view.isSelected()) {
view.setSelected(false);
} else {
view.setSelected(true);
}
row.setSelected(view.isSelected());
}
});
return convertView;
}
private class ViewHolder{
public TextView textViewName;
public ImageView rowImage;
}
}
This is main idea. Also, if you will save row states in ListView permanently (not just 1 time when you download and show data from internet) - you have to save you companies data in database, or in another data storage (ex.: in text file) and next time when you open activity - restore previously saved companies list.
Seen your code, no where you are saving checked state of button. Point is when you navigate from MainActivity to SearchActivity your listview with custom adapter is populated and displayed, there you set some button, now once you navigate back to main activity from there you SearchAvtivity is destroyed and is completely redrawn when you navigate back. Hence you see every then fresh again.
If you want to retain checked state of button, you should save their latest state in preference and load it from there or you can keep global data variable for holding checked states of buttons so to retain it during entire life cycle of your applications.
Read about Activity life cycle and stack, when they are destroyed and created, this will throw you more insight over why this is happening.
hope it help.

Refreshing Android ListView data inside OnClickListener

I've been working on a personal project in Android and ran into a strange situation regarding an Activity which uses a ListView. The basics of the problem are that I have a list of items, each which have 2 buttons, edit and delete. Right now I'm working on implementing the Delete button, which works functionally, but doesn't update the ListView correctly. Instead, it puts what was just deleted on top of the list. It of course refreshes whenever I renavigate to that activity.
Right now the Delete button is detected inside the a custom BaseAdapter, and when I call the notifyDataSetChanged, the situation described above happens instead of removing the now deleted item. How can I correctly update the list inside the adapter class?
I realize that there have been some questions about this, but I haven't been able to integrate them, and solutions I think may work don't really explain how they work; I'm using this project to understand Android app development more, so I would prefer answers with some level of explanation, although any help is of course appreciated!
Thanks!
Here's the relevent code. Note that this is an unfinished project, so there are some unused/incomplete things inside it. Please ignore these.
EditItemsActivity:
package com.example.mybudget;
import java.util.List;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
public class EditItemsActivity extends Activity implements OnGestureListener{
private DatabaseHandler db;
private List<DataPoint> dpList;
private EditItemsAdapter adapter;
private ListView lv;
private GestureDetector gestureDetector;
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_items);
// Show the Up button in the action bar.
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
getActionBar().setDisplayHomeAsUpEnabled(true);
db = new DatabaseHandler(this);
dpList = db.allDataThisMonth();
lv = (ListView) findViewById(R.id.edititems);
adapter = new EditItemsAdapter(this, R.id.edititems, dpList);
lv.setAdapter(adapter);
gestureDetector = new GestureDetector(getBaseContext(), this);
// buttonDelete.setVisibility(View.GONE);
}
public void refreshList()
{
adapter.notifyDataSetChanged();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_edit_items, menu);
return true;
}
#Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
public void onDelete()
{
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY)
{
// Log.d("Swipe", "" + velocityX + ", " + velocityY);
// if(velocityX > 200 && velocityY < 50 && velocityY > -50)
// {
// buttonEdit.setVisibility(View.GONE);
// buttonDelete.setVisibility(View.VISIBLE);
// }
// else if(velocityX < -200 && velocityY < 50 && velocityY > -50)
// {
// buttonDelete.setVisibility(View.GONE);
// buttonEdit.setVisibility(View.VISIBLE);
// }
return false;
}
#Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
// TODO Auto-generated method stub
return false;
}
#Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
#Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
}
And here's the adapter class:
package com.example.mybudget;
import java.text.NumberFormat;
import java.util.List;
import android.app.Activity;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.TextView;
public class EditItemsAdapter extends BaseAdapter implements OnClickListener{
private List<DataPoint> dpList;
private Activity activity;
private DatabaseHandler db;
public EditItemsAdapter(Activity a)
{
activity = a;
}
public EditItemsAdapter(Activity a, int textViewResourceId, List<DataPoint> dpList)
{
super();
this.dpList = dpList;
activity = a;
db = new DatabaseHandler(activity);
}
public static class ViewHolder
{
public TextView item1;
public TextView item2;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
//ViewHolder holder;
NumberFormat format = NumberFormat.getCurrencyInstance();
if (v == null)
{
// LayoutInflater vi =
// (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LayoutInflater vi = activity.getLayoutInflater();
v = vi.inflate(R.layout.edit_grid_items, null);
// holder = new ViewHolder();
// holder.item1 = (TextView) v.findViewById(R.id.edit_item_name);
// holder.item2 = (TextView) v.findViewById(R.id.edit_item_cost);
// v.setTag(holder);
TextView tv1 = (TextView)v.findViewById(R.id.edit_item_name);
TextView tv2 = (TextView)v.findViewById(R.id.edit_item_cost);
Button edit = (Button)v.findViewById(R.id.edit_item_button);
Button delete = (Button)v.findViewById(R.id.delete_item_button);
final DataPoint dp = dpList.get(position);
tv1.setText(dp.getName());
tv2.setText(Float.toString(dp.getCost()));
delete.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
db.deleteRowByKey(dp);
((EditItemsActivity) activity).refreshList();
}
});
}
// else
// holder = (ViewHolder)v.getTag();
// if(dp != null)
// {
// holder.item1.setText(dp.getName());
// holder.item2.setText(format.format(dp.getCost()));
// }
return v;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return dpList.size();
}
#Override
public DataPoint getItem(int position) {
// TODO Auto-generated method stub
return dpList.get(position);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return dpList.size();
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
EDIT:
The solution involved the inflation explanation that Adam provided, but required a complete repopulation of dpList, the
dpList = db.allDataThisMonth();
that Anup suggested.
In your getView method of your adapter, you're checking if (convertView == null) and if it's null you're inflating a new view. If it's not null, you're just returning the non-null view that was supplied.
The convertView supplied to the getView method is a cached view that has already been displayed. You're supposed to re-use this (if it's a valid view - you may have multiple different views in your list), rather than inflating a new one. You're forgetting to update the content of it for the corresponding position.
So, how to fix it? Simply close your if (v == null) after inflation:
if (v == null)
{
LayoutInflater vi = activity.getLayoutInflater();
v = vi.inflate(R.layout.edit_grid_items, null);
}
Edit: As Anup points out, you also need to update your dpList variable or it will keep returning the same values for the given position. You can do this in your click listener:
delete.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
db.deleteRowByKey(dp);
dpList.remove((Integer)v.getTag());
((EditItemsActivity) activity).refreshList();
}
});
// Required so we know which index to remove from our dpList.
delete.setTag(position);
From your code, I can see that your adapter is populated by dplist. When you delete a row using db.deleteRowByKey(dp);you are updating the database but you are not updating your dplist.
You need to repopulate your dplist to match the database and only then will notifyDataSetChanged() work as expected.
A simply way to do this would be to change your refreshList() function to:
public void refreshList()
{
//reload dpList so that it can sync up with the database
dpList = db.allDataThisMonth();
//now notify adapter that the data set has changed so that it can update itself.
adapter.notifyDataSetChanged();
}

Categories

Resources