Im having trouble adding a spinner in place of the application name in my action bar.
im sure this question has been asked before but all the answers are pretty much the same either a simple one line correction and then a reference to thiers a lovely example at the google dev site here: http://developer.android.com/guide/topics/ui/actionbar.html#Dropdown
the android docs but for a beginner I find it ashumes to much and leaves out tiny peices of key information.
public class MainProgram extends Activity implements OnNavigationListener {
/**
* Mobile Service Client reference
*/
private MobileServiceClient mClient;
private ConnectWithService service;
/**
* Progress spinner to use for table operations
*/
private ProgressBar mProgressBar;
/**
* Sensor stuff
*/
SensorManager mSensor;
Detection orientation;
//Spinner Listener
mOnNavigationListener = new OnNavigationListener() {
// Get the same strings provided for the drop-down's ArrayAdapter
String[] strings = getResources().getStringArray(R.array.action_list);
#Override
public boolean onNavigationItemSelected(int position, long itemId) {
//toast
Toast toast = Toast.makeText(this, "whoop whoop!", toast.LENGTH_SHORT);
toast.show();
}
};
/**
* Initializes the activity
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_program);
//Load progress bar view
mProgressBar = (ProgressBar) findViewById(R.id.loadingProgressBar);
// Initialize the progress bar
mProgressBar.setVisibility(ProgressBar.GONE);
//Spinner Adapter
setNavigationMode(NAVIGATION_MODE_LIST);
SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(this, R.array.action_list,
android.R.layout.simple_spinner_dropdown_item);
//innitialize Sensor Manager
mSensor = (SensorManager)getSystemService(SENSOR_SERVICE);
//signin
try {
// Create the Mobile Service Client instance, using the provided
// Mobile Service URL and key
mClient = new MobileServiceClient(
"secret",
"secret",
this).withFilter(new ProgressFilter());
} catch (MalformedURLException e) {
createAndShowDialog(new Exception("There was an error creating the Mobile Service. Verify the URL"), "Error");
}
authenticate();
}
/**
* Initializes the activity menu
*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
/**
* Select an option from the menu
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menu_refresh) {
}
return true;
}
/**
* Creates a dialog and shows it
*
* #param exception
* The exception to show in the dialog
* #param title
* The dialog title
*/
private void createAndShowDialog(Exception exception, String title) {
createAndShowDialog(exception.toString(), title);
}
/**
* Creates a dialog and shows it
*
* #param message
* The dialog message
* #param title
* The dialog title
*/
private void createAndShowDialog(String message, String title) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(message);
builder.setTitle(title);
builder.create().show();
}
private class ProgressFilter implements ServiceFilter {
#Override
public void handleRequest(ServiceFilterRequest request, NextServiceFilterCallback nextServiceFilterCallback,
final ServiceFilterResponseCallback responseCallback) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (mProgressBar != null) mProgressBar.setVisibility(ProgressBar.VISIBLE);
}
});
nextServiceFilterCallback.onNext(request, new ServiceFilterResponseCallback() {
#Override
public void onResponse(ServiceFilterResponse response, Exception exception) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (mProgressBar != null) mProgressBar.setVisibility(ProgressBar.GONE);
}
});
if (responseCallback != null) responseCallback.onResponse(response, exception);
}
});
}
}
private void authenticate() {
// Login using the Google provider.
mClient.login(MobileServiceAuthenticationProvider.MicrosoftAccount,
new UserAuthenticationCallback() {
#Override
public void onCompleted(MobileServiceUser user,
Exception exception, ServiceFilterResponse response) {
if (exception == null) {
createAndShowDialog(String.format(
"You are now logged in - %1$2s",
user.getUserId()), "Success");
service = new ConnectWithService(mClient,user.getUserId());
orientation = new Detection(mSensor);
} else {
createAndShowDialog("You must log in. Login Required", "Error");
}
}
});
}
//start sensors camera etc if needed
protected void onResume() {
super.onResume();
if(orientation!=null)
orientation.startSensorsListening();
}
// stop sensors etc
protected void onPause() {
super.onPause();
orientation.stopSensorListening();
}
}
theres at least two errors i think mOnNavigationListener should be somewhere else
setnavigationMode() has an error
don't use OnNavigationListener with (ActionBar.NAVIGATION_MODE_LIST)
use:
final ActionBar bar = getActionBar();
bar.setDisplayShowCustomEnabled(true);
bar.setCustomView(R.layout.action_bar_custom);
then all as normal.
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?>....
Related
Hi i have a function to get users from website database
my function
private void get_users() {
try {
url = "my address";
dbGetData3 = new DbGetData();
new Thread(new Runnable() {
public void run() {
data = dbGetData3.getDataFromDB(url);
runOnUiThread(new Runnable() {
#Override
public void run() {
userha = parseJSON3(data);
}
});
}
}).start();
Toast.makeText(context, "please wait ", Toast.LENGTH_LONG)
.show();
} catch (Exception e) {
toast(9);
}
Now i want add a loading progress bar while fetch data finished.
I use AsyncTask like this:
private class LongOperation extends AsyncTask<String, Void, String> {
protected void onPreExecute() {
progressDialog = new ProgressDialog(Login.this);
progressDialog.setTitle("Processing...");
progressDialog.setMessage("Please wait...");
progressDialog.setCancelable(true);
progressDialog.show();
}
protected String doInBackground(String... params) {
try {
get_users();
} catch (Exception e) {
}
return null;
}
protected void onPostExecute(String result) {
progressDialog.dismiss();
}
}
and i use this code for excute
mytask = new LongOperation();
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB)
mytask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
mytask.execute();
imageView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
onCreate(savedInstanceState);
}
});
but progress dialog dose not show for me (get user worked)
i change my code like this:
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){
mytask.onPreExecute();
mytask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
else
{
mytask.onPreExecute();
mytask.execute();
}
then my progress dialog allways show
i test other code in stackoverflow like
AsyncTask doInBackground does not run
AsyncTask called from Handler will not execute doInBackground
Android SDK AsyncTask doInBackground not running (subclass)
but that not work for me
please help me tankyou
Consdier using a LoaderManager and an AsyncTaskLoader for this sort of stuff.
AsyncTasks are a pain in the ass as because you have to manage their lifecycle with screen-rotations etc. With a LoaderManager all of that is in the past.
Below is an example of a loader which loads a list of "items".
public class ItemsLoader extends AsyncTaskLoader<List<Item>> {
private static final String TAG = "ItemsLoader";
private List<Item> mItems;
private ItemUpdatedReceiver mObserver;
private int mSomeParam;
public static class ItemUpdatedReceiver extends BroadcastReceiver {
private static final String TAG = "ItemLoader";
final ItemsLoader mLoader;
public ItemUpdatedReceiver(ItemsLoader mLoader) {
this.mLoader = mLoader;
// listen for changes to the account we're using
IntentFilter filter = new IntentFilter(GlobalConstants.ACTION_ITEMS_UPDATED);
LocalBroadcastManager.getInstance(mLoader.getContext()).registerReceiver(this, filter);
}
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (GlobalConstants.ACTION_ITEMS_UPDATED.equals(action)) {
mLoader.onContentChanged();
}
}
}
public void setSomeParam(int someParam){
mSomeParam = someParam;
onContentChanged();
}
public ItemsLoader(Context context, int someParam) {
super(context);
mSomeParam = someParam;
onContentChanged();
}
#Override
public List<Item> loadInBackground() {
// do whatever you need to do here
ArrayList<Item> Items = new ArrayList<>();
return Items;
}
/**
* Called when there is new data to deliever to the client.
*
* #param data
*/
#Override
public void deliverResult(List<Item> data) {
if (isReset()) {
// an async query came in while the loader is stopped, we don't need the result
//release resources if needed
onReleaseResources(data);
}
List<Item> oldItems = mItems;
mItems = data;
if (isStarted()) {
// If the Loader is currently started, we can immediately
// deliver its results.
super.deliverResult(mItems);
}
// At this point we can release the resources associated with
// 'oldApps' if needed; now that the new result is delivered we
// know that it is no longer in use.
if (oldItems != null) {
onReleaseResources(oldItems);
}
}
#Override
protected void onStartLoading() {
super.onStartLoading();
if (mItems != null) {
// If we currently have a result available, deliver it
// immediately.
deliverResult(mItems);
}
// start listening for changes
if (mObserver == null) {
mObserver = new ItemUpdatedReceiver(this);
}
if (takeContentChanged() || mItems == null) {
// If the data has changed since the last time it was loaded
// or is not currently available, start a load.
forceLoad();
}
}
/**
* Handles a request to stop the Loader.
*/
#Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Handles a request to cancel a load.
*/
#Override
public void onCanceled(List<Item> items) {
super.onCanceled(items);
// At this point we can release the resources associated with 'profile'
// if needed.
onReleaseResources(items);
}
#Override
protected void onReset() {
super.onReset();
// Ensure the laoder is stopped
onStopLoading();
// At this point we can release the resources if needed.
if (mItems != null) {
onReleaseResources(mItems);
mItems = null;
}
// Stop monitoring for changes.
if (mObserver != null) {
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mObserver);
mObserver = null;
}
}
/**
* Helper function to take care of releasing resources associated
* with an actively loaded data set.
*/
private void onReleaseResources(List<Item> data) {
// For a simple List<> there is nothing to do. For something
// like a Cursor, we would close it here.
}
}
To use this class, in your activity you must extend LoaderManager.LoaderCallbacks> and override the methods:
public Loader<List<Item>> onCreateLoader(int id, Bundle args) {
// This is called when a new Loader needs to be created. This
// sample only has one Loader, so we don't care about the ID.
// start the loading dialog here
return new ItemsLoader(context);
}
public void onLoadFinished(Loader<List<Item>> loader, List<Item>data) {
// do something with your data, hide the progress dialog
}
public void onLoaderReset(Loader<Cursor> loader) {
// set the old data to null
}
To actually start loading:
getLoaderManager().initLoader(LOADER_ID, null, this);
I have one big problem that is bugging me for a couple of days right now. In the application I am working on, I have couple of activities, and one of them is central (BaseActivity) from which the app goes to other Activities and in each of them it works with Volley Library to fetch data from the API.
So for instance, if I go from BaseActivity to SelectionActivity, in SelectionActivity I receive my recycle view with all the necessary data. That is quite alright, that's what I need.
However, when I finish the activity either by clicking back button or home button on the toolbar, and then want to return back to the SelectionActivity again, the data is not being loaded again. It doesn't state any exception, just doesn't load anything.
I have been searching all over the Internet but I can't seem to find the solution.
EDIT: OK further when I investigated with the debugger. It seems like everything should work because it goes through the response, and through everything. However, instead of RecyclerView filled with data, I don't see anything.
SelectionController Method:
public void getAllJobs()
{
queue = VolleyRequestHandler.getInstance(false).getQueue();
JsonArrayRequest jobsRequest = new JsonArrayRequest(Request.Method.GET,makeAllJobsRequest(),
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
List<Job> jobs = new ArrayList<>();
Job job;
try
{
for (int i=0; i<response.length(); i++)
{
JSONObject dbJob = response.getJSONObject(i);
job = new Job();
job.setId(dbJob.getLong("JobId"));
job.setName(dbJob.getString("JobText"));
job.setCustName(dbJob.getString("CustomerName"));
jobs.add(job);
}
// Entries are being sorted!
Collections.sort(jobs, new CustomerComparator());
injection.onGettingAllJobs(jobs);
}
catch (JSONException e)
{
e.printStackTrace();
injection.onErrorSelection(e.getMessage());
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
injection.onErrorSelection(error.getMessage());
}
});
jobsRequest.setTag(injection.GET_JOBS_TAG);
jobsRequest.setRetryPolicy(new DefaultRetryPolicy(
(int) TimeUnit.SECONDS.toMillis(10),//time out in 10second
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,//DEFAULT_MAX_RETRIES = 1;
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
queue.add(jobsRequest);
}
SelectionInjection interface:
public interface SelectionInjection
{
public static final String GET_JOBS_TAG = "SELECTION_GET_JOBS_TAG";
public static final String GET_TASKS_TAG = "SELECTION_GET_TASKS_TAG";
public static final String SAVE_ENTRY_TAG ="SELECTION_SAVE_ENTRY_TAG";
public void onGettingAllJobs(List<Job> jobs);
public void onGettingTasksForJob(List<Task> tasks);
public void onSavedEntry(TimeEntry savedEntry);
public void onErrorSelection(String message);
}
SelectionActivity:
public class SelectionActivity extends ActionBarActivity implements SelectionInjection {
private static final String TAG = SelectionActivity.class.getName();
/*
* Init variables for Recycler Views
* */
private LinearLayoutManager mLayoutManager;
private SelectJobAdapter mJobsAdapter;
private StickyHeadersItemDecoration headers;
private SelectTaskAdapter mSelectTaskAdapter;
/*
* Lists used for adapter and for storing information from server
* */
private List<Job> mJobs;
private List<Task> mTasks;
private SelectionController controller;
private Job selectedJob;
// Inject Views with ButterKnife
#InjectView(R.id.select_job_recyclerview) SuperRecyclerView mJobSuperRecyclerView;
#InjectView(R.id.select_task_recyclerview) SuperRecyclerView mTaskSuperRecyclerView;
#InjectView(R.id.job_view)FrameLayout mJobView;
#InjectView(R.id.task_view) FrameLayout mTaskView;
#InjectView(R.id.toolbar_actionbar) Toolbar mToolbarAction;
private int mAnimDuration;
// private SelectionTask mFetchingTask; // Is it a good idea to Init it here? -> Nej
// private SaveSelectionTask mSavingTask;
// TODO: Figure out why after coming back again to this activity, there is only a loading wheel and nothing shows up
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_selection);
ButterKnife.inject(this);
/*
* Setting up stuff for ViewSwitching
* */
mTaskView.setVisibility(View.GONE); // Also set in XMl but just in case :D
mAnimDuration = getResources()
.getInteger(android.R.integer.config_mediumAnimTime);
/*
* Setting Up Action Bar
* */
mToolbarAction.setTitle(getString(R.string.select_job_title));
setSupportActionBar(mToolbarAction);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true); // Hierarchical activity
if (mJobs == null) {
// provifing dummy test data
Log.v(TAG, "mJobs are are null");
// mJobs = new ArrayList<Job>();
// List<Task> taskList = new ArrayList<Task>();
// taskList.add(
// new Task(88,"Task Name Doh")
// );
// taskList.add(
// new Task(99,"Another Task Name Doh")
// );
// mJobs.add(
// new Job(
// 10,
// "Test Job",
// 1337,
// "Fake Customer",
// taskList
// ));
fetchJobs();
}
else
{
setUpJobRecyclerView();
}
}
private void fetchJobs() {
Log.v(TAG,"fetchJobs();");
// mFetchingTask = new SelectionTask();
// mFetchingTask.execute(); // No PAram, get all the jobs
controller = SelectionController.getInstance(BaseActivity.currentUser,this);
controller.getAllJobs();
}
private void fetchTasks(Job job){
Log.v(TAG,"fetchTAsks()");
try{
// mFetchingTask = new SelectionTask();
// mFetchingTask.execute(job);
controller = SelectionController.getInstance(BaseActivity.currentUser,this);
controller.getTasksForJob(job);
}catch (Exception e){
Log.v(TAG,"There was an error fetching tasks");
e.printStackTrace();
Toast.makeText(this,"There was error fetching tasks",Toast.LENGTH_LONG).show();
}
}
/**
* Method for setting up Job Recycler View
*/
private void setUpJobRecyclerView(){
/*
* Setting up Jobs Recycler View
* */
mJobsAdapter = new SelectJobAdapter(mJobs);
mJobsAdapter.setHasStableIds(true);
headers = new StickyHeadersBuilder()
.setAdapter(mJobsAdapter)
.setRecyclerView(mJobSuperRecyclerView.getRecyclerView())
.setStickyHeadersAdapter(new SelectJobHeaderAdapter(mJobs))
.build();
mJobSuperRecyclerView.setAdapter(mJobsAdapter);
mJobSuperRecyclerView.addItemDecoration(headers);
mLayoutManager = new LinearLayoutManager(this);
mJobSuperRecyclerView.setLayoutManager(mLayoutManager);
// Setting up onClickListener
mJobSuperRecyclerView.
addOnItemTouchListener(
new RecyclerUtils.RecyclerItemClickListener(
this,
new RecyclerUtils.RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
selectedJob = mJobs.get(position);
showMaterialDialog(position);
}
}));
}
/**
* Method used for settigng up and initalising all the adapters
* for TaskRecyclerView
* */
private void setUpTaskRecyclerView() {
mLayoutManager = new LinearLayoutManager(this);
mTaskSuperRecyclerView.setLayoutManager(mLayoutManager);
mSelectTaskAdapter = new SelectTaskAdapter(mTasks);
mSelectTaskAdapter.setHasStableIds(true);
headers = new StickyHeadersBuilder()
.setAdapter(mSelectTaskAdapter)
.setRecyclerView(mTaskSuperRecyclerView.getRecyclerView())
.setStickyHeadersAdapter(new SelectTaskHeaderAdapter(mTasks))
.build();
mTaskSuperRecyclerView.setAdapter(mSelectTaskAdapter);
mTaskSuperRecyclerView.addItemDecoration(headers);
mTaskSuperRecyclerView.
addOnItemTouchListener(
new RecyclerUtils.RecyclerItemClickListener(
this,
new RecyclerUtils.RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
Log.v(TAG,"TaskRecyclerView onItemClick");
Toast.makeText(getApplicationContext(),"The Task has been added",Toast.LENGTH_LONG).show();
// mSavingTask = new SaveSelectionTask();
// mSavingTask.execute(mTasks.get(position));
}
}));
}
/**
* A method that starts a corssfade Animation between JobView and TaskView
*
*/
private void crossfadeViews(final View fromView, View toView){
// Set the Task view to 0% opacity but visible, so that it is visible
// (but fully transparent) during the animation.
toView.setAlpha(0f);
toView.setVisibility(View.VISIBLE);
// Animate the Task view to 100% opacity, and clear any animation
// listener set on the view.
toView.animate()
.alpha(1f)
.setDuration(mAnimDuration)
.setListener(null);
// Animate the Job view to 0% opacity. After the animation ends,
// set its visibility to GONE as an optimization step (it won't
// participate in layout passes, etc.)
fromView.animate()
.alpha(0f)
.setDuration(mAnimDuration)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
fromView.setVisibility(View.GONE);
}
});
}
/**
* Method that creates and shows a Dialog
* and executes fetchTasks() if given option is picked.
*/
private void showMaterialDialog(final int position){
// TODO: Consider starting running he Async Task straight away as
// it might be likely that the user will pick "Pcik A Task" option
// and this might speed up the process
Log.v(TAG,"showMAterialDialog");
new MaterialDialog.Builder(this)
.title("Choose Action")
.positiveText("Add Job")
.negativeText("Pick A Task")
.neutralText("CANCEL")
.callback(new MaterialDialog.ButtonCallback(){
#Override
public void onPositive(MaterialDialog dialog) {
// Add Job
Log.v(TAG,"Adding the whole Job");
// mSavingTask = new SaveSelectionTask();
// mSavingTask.execute();
controller = SelectionController.getInstance(BaseActivity.currentUser,SelectionActivity.this);
controller.saveNewTimeEntry(BaseActivity.selectedDate,selectedJob,null);
}
#Override
public void onNegative(MaterialDialog dialog) {
/**
*Pick a Task
*/
fetchTasks(mJobs.get(position));
Log.v(TAG, "Switching Views");
crossfadeViews(mJobView, mTaskView);
}
#Override
public void onNeutral(MaterialDialog dialog) {
Log.v(TAG,"Cancelling the Dialog Choice");
}
}).show();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.global, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
try
{
switch(id)
{
case R.id.action_settings:
return true;
case android.R.id.home:
if (mTaskView.getVisibility() == View.VISIBLE)
{
crossfadeViews(mTaskView,mJobView);
}
else
{
finish();
}
return true;
default:
throw new Exception();
}
}
catch (Exception e)
{
e.printStackTrace();
return super.onOptionsItemSelected(item);
}
}
#Override
public void onSavedEntry(TimeEntry savedEntry)
{
Log.v("SAVED ENTRY", "TRUE");
System.out.println(savedEntry.toString());
controller.closeQueue(SAVE_ENTRY_TAG);
}
#Override
public void onGettingAllJobs(List<Job> jobs) {
mJobs = jobs;
setUpJobRecyclerView();
controller.closeQueue(GET_JOBS_TAG);
}
#Override
public void onGettingTasksForJob(List<Task> tasks) {
mTasks = tasks;
setUpTaskRecyclerView();
controller.closeQueue(GET_TASKS_TAG);
}
#Override
public void onErrorSelection(String message) {
Log.v(TAG,"onErrorJobTask");
}
}
So after a lot of debugging, I have come across to the solution:
It seemed like the way I was making Controllers and Injections didn't really fit into the Android development so I have restructured the code back into the activities and fragments and all works now.
EDIT:
Finally I have figured out what the ACTUAL problem is. When I was passing the Context to the Controller.. I only did so when I actually instantiated them. And because Controllers are singletons in my case, I have been using the old context when reentering Activity.
I can't believe how I did not get that. :)
Following is my setup.
I have a livecard service class which does an async task to get weather and weatherforecast data externally.
It also starts a Pendingintent with two menu-items being "ShowForecast" & "Stop"
The weather data is shown on the main screen when it arrives.
However the forecast data takes a bit longer. I would like to hide the ShowForecast menu until the async task completes successfully.
What is the best way to implement this? I've read something about global variables, or through intent.putextra or updating the card menu directly.
What I am thinking about now is to use a boolean value in my activity class that gets checked in onPrepareOptionsMenu and hides/ shows the menu.
But how do I set this boolean from the Service class when async task completes?
Below are the class snippets. All advise welcome pls! :)
public class LiveCardMenuActivity extends Activity {
private static final String TAG = LiveCardMenuActivity.class.getSimpleName();
// default disabled menu
private boolean menu_showForecast = false;
#Override
// in this method we hide/ show forecast menu, depending if the service has gotten the data
public boolean onPrepareOptionsMenu(Menu menu) {
if(!menu_showForecast) {
menu.findItem(R.id.action_show_forecast).setVisible(false);
}
return super.onPrepareOptionsMenu(menu);
...
And is the service class with the async task
public class LiveCardService extends Service {
private static final String TAG = LiveCardService.class.getSimpleName();
private static final String LIVE_CARD_TAG = "LiveCardService";
private LiveCard mLiveCard;
private RemoteViews mLiveCardView;
private final Handler mHandler = new Handler();
private final UpdateLiveCardRunnable mUpdateLiveCardRunnable = new UpdateLiveCardRunnable();
private static final long DELAY_MILLIS = 1000;
// keep the weather info central, due to reuse and forecast cards
private Weather weather = new Weather();
private WeatherForecast weatherForecast = new WeatherForecast();
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
// and get the weather data & icon, async call
String loc = "id=2755420";
JSONWeatherTask task = new JSONWeatherTask();
task.execute(new String[]{loc});
// including the weather forecast
JSONWeatherForecastTask taskForecast = new JSONWeatherForecastTask();
taskForecast.execute(new String[]{loc});
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mLiveCard == null) {
// Get an instance of a live card
mLiveCard = new LiveCard(this, LIVE_CARD_TAG);
// setup live card views
mLiveCardView = new RemoteViews(getPackageName(), R.layout.live_card);
mLiveCard.setViews(mLiveCardView);
// Display the options menu when the live card is tapped.
Intent menuIntent = new Intent(this, LiveCardMenuActivity.class);
mLiveCard.setAction(PendingIntent.getActivity(this, 0, menuIntent, 0));
mLiveCard.publish(PublishMode.REVEAL);
// Queue the update text runnable
mHandler.post(mUpdateLiveCardRunnable);
} else {
mLiveCard.navigate();
}
return START_STICKY;
}
...
private class JSONWeatherForecastTask extends AsyncTask<String, Void, WeatherForecast> {
#Override
protected WeatherForecast doInBackground(String... params) {
//
String data = ( (new WeatherHttpClient()).getWeatherForecastData(params[0]));
try {
weatherForecast = JSONWeatherForecastParser.getWeatherForecast(data);
} catch (JSONException e) {
e.printStackTrace();
}
return weatherForecast;
}
#Override
protected void onPostExecute(WeatherForecast weatherForecast) {
super.onPostExecute(weatherForecast);
// there is no showing of data yet, except voor enabling the forecast menu
Weather[] weatherForecastArray = weatherForecast.getWeatherForecastArray();
int count = weatherForecastArray.length;
if(count > 0){
//mLiveCard menu update or boolean update?
}
}
}
The Timer sample's menu Activity has some logic to dynamically change its options menu according to the state of the running Timer:
In the MenuActivity's onCreate callback: bind to the TimerService.
Once the Service is bound, retrieve information about the current Timer.
Once all states are satisfied (Activity has been attached to a Window, Timer information has been retrieved): open the options menu.
Here are snippets of code from the MenuActivity class:
/**
* This activity manages the options menu that appears when the user taps on the timer's live
* card or says "ok glass" while the live card is settled.
*/
public class MenuActivity extends Activity {
private Timer mTimer;
private boolean mAttachedToWindow;
private boolean mIsMenuClosed;
private boolean mPreparePanelCalled;
private boolean mIsSettingTimer;
private boolean mFromLiveCardVoice;
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (service instanceof TimerService.TimerBinder) {
mTimer = ((TimerService.TimerBinder) service).getTimer();
openMenu();
}
// No need to keep the service bound.
unbindService(this);
}
#Override
public void onServiceDisconnected(ComponentName name) {
// Nothing to do here.
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mFromLiveCardVoice = getIntent().getBooleanExtra(LiveCard.EXTRA_FROM_LIVECARD_VOICE, false);
if (mFromLiveCardVoice) {
// When activated by voice from a live card, enable voice commands. The menu
// will automatically "jump" ahead to the items (skipping the guard phrase
// that was already said at the live card).
getWindow().requestFeature(WindowUtils.FEATURE_VOICE_COMMANDS);
}
// Bind to the Timer service to retrive the current timer's data.
Intent serviceIntent = new Intent(this, TimerService.class);
serviceIntent.putExtra(
TimerService.EXTRA_TIMER_HASH_CODE,
getIntent().getIntExtra(TimerService.EXTRA_TIMER_HASH_CODE, 0));
serviceIntent.setData(getIntent().getData());
bindService(serviceIntent, mConnection, 0);
}
#Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
mAttachedToWindow = true;
openMenu();
}
#Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
mAttachedToWindow = false;
}
#Override
public boolean onCreatePanelMenu(int featureId, Menu menu) {
if (isMyMenu(featureId)) {
getMenuInflater().inflate(R.menu.timer, menu);
return true;
}
return super.onCreatePanelMenu(featureId, menu);
}
#Override
public boolean onPreparePanel(int featureId, View view, Menu menu) {
mPreparePanelCalled = true;
if (isMyMenu(featureId)) {
if (mTimer == null) {
// Can't prepare the menu as we're not yet bound to a timer.
return false;
} else {
// Disable or enable menu item depending on the Timer's state.
// Don't reopen menu once we are finishing. This is necessary
// since voice menus reopen themselves while in focus.
return !mIsMenuClosed;
}
}
return super.onPreparePanel(featureId, view, menu);
}
#Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
if (!isMyMenu(featureId)) {
return super.onMenuItemSelected(featureId, item);
}
// Handle item selection.
}
#Override
public void onPanelClosed(int featureId, Menu menu) {
super.onPanelClosed(featureId, menu);
if (isMyMenu(featureId)) {
mIsMenuClosed = true;
if (!mIsSettingTimer) {
// Nothing else to do, closing the Activity.
finish();
}
}
}
/**
* Opens the touch or voice menu iff all the conditions are satifisfied.
*/
private void openMenu() {
if (mAttachedToWindow && mTimer != null) {
if (mFromLiveCardVoice) {
if (mPreparePanelCalled) {
// Invalidates the previously prepared voice menu now that we can properly
// prepare it.
getWindow().invalidatePanelMenu(WindowUtils.FEATURE_VOICE_COMMANDS);
}
} else {
// Open the options menu for the touch flow.
openOptionsMenu();
}
}
}
/**
* Returns {#code true} when the {#code featureId} belongs to the options menu or voice
* menu that are controlled by this menu activity.
*/
private boolean isMyMenu(int featureId) {
return featureId == Window.FEATURE_OPTIONS_PANEL ||
featureId == WindowUtils.FEATURE_VOICE_COMMANDS;
}
}
I am trying to implement this tutorial, for handling Configuration changes while running background tasks. Everything works fine, and the app does not crash after a configuration change. In the tutorial, a progress bar is used to display progress. But in my own implementation i want to use a Progress Dialog.
I have used progress Dialog's lots of times, so calling it and getting to appear is not the problem. My problem is that unlike the progress Bar, the progress dialog gets dismissed on configuration change. Just like that.
Here is my code:
My MainActivity:
private TaskFragment mTaskFragment;
private ProgressDialog mProgressDialog;
private TextView mPercent;
private Button mButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate(Bundle)");
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Initialize views
mButton = (Button) findViewById(R.id.task_button);
mButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (mTaskFragment.isRunning()) {
mTaskFragment.cancel();
} else {
mTaskFragment.start();
}
}
});
mProgressBar = new ProgressDialog(this);
FragmentManager fm = getSupportFragmentManager();
mTaskFragment = (TaskFragment) fm.findFragmentByTag("task");
// If the Fragment is non-null, then it is currently being
// retained across a configuration change.
if (mTaskFragment == null) {
mTaskFragment = new TaskFragment();
fm.beginTransaction().add(mTaskFragment, "task").commit();
}
if (mTaskFragment.isRunning()) {
mButton.setText(getString(R.string.cancel));
} else {
mButton.setText(getString(R.string.start));
}
}
/****************************/
/***** CALLBACK METHODS *****/
/****************************/
#Override
public void onPreExecute() {
Log.i(TAG, "onPreExecute()");
mProgressBar.setTitle("Wacky");
mProgressBar.setMessage("wack");
mProgressBar.setIndeterminate(true);
mProgressBar.show();
mButton.setText(getString(R.string.cancel));
mButton.setText(getString(R.string.cancel));
Toast.makeText(this, R.string.task_started_msg, Toast.LENGTH_SHORT).show();
}
#Override
public void onProgressUpdate(int percent) {
//Log.i(TAG, "onProgressUpdate(" + percent + "%)");
}
#Override
public void onCancelled() {
Log.i(TAG, "onCancelled()");
mButton.setText(getString(R.string.start));
Toast.makeText(this, R.string.task_cancelled_msg, Toast.LENGTH_SHORT).show();
}
#Override
public void onPostExecute() {
Log.i(TAG, "onPostExecute()");
mButton.setText(getString(R.string.start));
Toast.makeText(this, R.string.task_complete_msg, Toast.LENGTH_SHORT).show();
}
My headless Fragment that holds my asyncTask
/**
* This Fragment manages a single background task and retains itself across
* configuration changes.
*/
public class TaskFragment extends Fragment {
public static final String TAG = TaskFragment.class.getSimpleName();
/**
* Callback interface through which the fragment can report the task's
* progress and results back to the Activity.
*/
public static interface TaskCallbacks {
public void onPreExecute();
public void onProgressUpdate(int percent);
public void onCancelled();
public void onPostExecute();
}
public TaskCallbacks mCallbacks;
public DummyTask mTask;
public boolean mRunning;
/**
* Android passes us a reference to the newly created Activity by calling this
* method after each configuration change.
*/
#Override
public void onAttach(Activity activity) {
Log.i(TAG, "onAttach(Activity)");
super.onAttach(activity);
if (!(activity instanceof TaskCallbacks)) {
throw new IllegalStateException("Activity must implement the TaskCallbacks interface.");
}
// Hold a reference to the parent Activity so we can report back the task's
// current progress and results.
mCallbacks = (TaskCallbacks) activity;
}
/**
* This method is called only once when the Fragment is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate(Bundle)");
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
/**
* This method is <em>not</em> called when the Fragment is being retained
* across Activity instances.
*/
#Override
public void onDestroy() {
Log.i(TAG, "onDestroy()");
super.onDestroy();
cancel();
}
/*****************************/
/***** TASK FRAGMENT API *****/
/*****************************/
/**
* Start the background task.
*/
public void start() {
if (!mRunning) {
mTask = new DummyTask(this, mCallbacks);
mTask.execute();
mRunning = true;
}
}
/**
* Cancel the background task.
*/
public void cancel() {
if (mRunning) {
mTask.cancel(false);
mTask = null;
mRunning = false;
}
}
/**
* Returns the current state of the background task.
*/
public boolean isRunning() {
return mRunning;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
Log.i(TAG, "onActivityCreated(Bundle)");
super.onActivityCreated(savedInstanceState);
}
}
My Background Task (in a seperate outer class)
/**
* A dummy task that performs some (dumb) background work and proxies progress
* updates and results back to the Activity.
*/
public class DummyTask extends AsyncTask<Void, Integer, Void> {
private TaskFragment fragment;
private TaskCallbacks callbacks;
private ProgressDialog mProgressBar;
MainActivity activity;
public DummyTask(TaskFragment taskFragment, TaskCallbacks mCallbacks) {
// TODO Auto-generated constructor stub
this.fragment = taskFragment;
this.callbacks = mCallbacks;
}
#Override
protected void onPreExecute() {
// Proxy the call to the Activity
fragment.mCallbacks.onPreExecute();
fragment.mRunning = true;
}
#Override
protected Void doInBackground(Void... ignore) {
for (int i = 0; !isCancelled() && i < 100; i++) {
//Log.i(TAG, "publishProgress(" + i + "%)");
SystemClock.sleep(100);
publishProgress(i);
}
return null;
}
#Override
protected void onProgressUpdate(Integer... percent) {
// Proxy the call to the Activity
fragment.mCallbacks.onProgressUpdate(percent[0]);
}
#Override
protected void onCancelled() {
// Proxy the call to the Activity
fragment.mCallbacks.onCancelled();
fragment.mRunning = false;
}
#Override
protected void onPostExecute(Void ignore) {
// Proxy the call to the Activity
fragment.mCallbacks.onPostExecute();
fragment.mRunning = false;
}
}
I am thinking it is the context which i am passing the progress dialog in the onCreate method of my Main Activity. Thanks for your help.
First, Activity is subclass of Context, you should know this already. Second, if Activity is destroyed, it is don't have a window anymore. Third, Dialog uses Context (read Activity) not because it wants so, but because it uses window associated with Activity to display itself.
It should be perfectly understandable, why after destroying activity during configuration change, Dialog no longer visible to you.
Method of preserving objects you using is good, but it can't preserve anything that would be destroyed during configuration change, such as any object that related to non-application Context, all this objects you need create manually every time Context changes.
You should use onSaveInstanceState(Bundle) to store state of ProgressDialog (shown or not) and show it again in your onCreate(Bunde) using value stored in Bundle.
Just an example
#Override
protected void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putBoolean("SHOW_DIALOG", mProgressBar.isShowing());
}
//...
#Override
protected void onCreate(Bundle savedInstanceState) {
//...
if (savedInstanceState != null){
if (savedInstanceState.getBoolean("SHOW_DIALOG") && mTaskFragment.isRunning()){
mProgressBar.setTitle("Wacky");
mProgressBar.setMessage("wack");
mProgressBar.setIndeterminate(true);
mProgressBar.show();
}
}
//...
Hi I am trying to make a app that will pull a list the logged in users friends from facebook into my application I am using the facebook SDK the code compiles and seems to work but hangs on the spinner animation when I select the get friends option from the menu! here is the code I am using bellow
public static final String APP_ID = "IDHERE";
private static final String[] PERMISSIONS =
new String[]{ "offline_access", "read_stream",
"publish_stream","create_event","user_events","friends_events",
"publish_checkins", "friends_checkins" };
private TextView mText;
private Handler mHandler = new Handler();
private ProgressDialog mSpinner;
private final ArrayList<Friend> friends = new ArrayList<Friend>();
private FriendsArrayAdapter friendsArrayAdapter;
private ListView listView;
private Facebook mFacebook;
private AsyncFacebookRunner mAsyncRunner;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Make sure the app client_app has been set
if (APP_ID == null) {
Util.showAlert(this,
"Warning", "Facebook Applicaton ID must be set...");
}
// Initialize the content view
setContentView(R.layout.main);
// Get the status text line resource
mText = (TextView) workdammit.this.findViewById(R.id.txt);
// Setup the ListView Adapter that is loaded when selecting "get friends"
listView = (ListView) findViewById(R.id.friendsview);
friendsArrayAdapter = new FriendsArrayAdapter(this, R.layout.rowlayout, friends);
listView.setAdapter(friendsArrayAdapter);
// Define a spinner used when loading the friends over the network
mSpinner = new ProgressDialog(listView.getContext());
mSpinner.requestWindowFeature(Window.FEATURE_NO_TITLE);
mSpinner.setMessage("Loading...");
// Initialize the Facebook session
mFacebook = new Facebook(APP_ID);
mAsyncRunner = new AsyncFacebookRunner(mFacebook);
}
//////////////////////////////////////////////////////////////////////
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d("FB Sample App", "onActivityResult(): " + requestCode);
mFacebook.authorizeCallback(requestCode, resultCode, data);
}
//////////////////////////////////////////////////////////////////////
// Get Friends request listener
//////////////////////////////////////////////////////////////////////
/**
* FriendsRequestListener implements a request lister/callback
* for "get friends" requests
*/
public class FriendsRequestListener implements
com.facebook.android.AsyncFacebookRunner.RequestListener {
/**
* Called when the request to get friends has been completed.
* Retrieve and parse and display the JSON stream.
*/
public void onComplete(final String response) {
mSpinner.dismiss();
try {
// process the response here: executed in background thread
Log.d("Facebook-Example-Friends Request", "response.length(): " + response.length());
Log.d("Facebook-Example-Friends Request", "Response: " + response);
final JSONObject json = new JSONObject(response);
JSONArray d = json.getJSONArray("data");
int l = (d != null ? d.length() : 0);
Log.d("Facebook-Example-Friends Request", "d.length(): " + l);
for (int i=0; i<l; i++) {
JSONObject o = d.getJSONObject(i);
String n = o.getString("name");
String id = o.getString("id");
Friend f = new Friend();
f.id = id;
f.name = n;
friends.add(f);
}
// Only the original owner thread can touch its views
workdammit.this.runOnUiThread(new Runnable() {
public void run() {
friendsArrayAdapter = new FriendsArrayAdapter(
workdammit.this, R.layout.rowlayout, friends);
listView.setAdapter(friendsArrayAdapter);
friendsArrayAdapter.notifyDataSetChanged();
}
});
} catch (JSONException e) {
Log.w("Facebook-Example", "JSON Error in response");
}
}
#Override
public void onComplete(String response, Object state) {
mSpinner.dismiss();
}
#Override
public void onIOException(IOException e, Object state) {
mSpinner.dismiss();
}
#Override
public void onFileNotFoundException(FileNotFoundException e,
Object state) {
mSpinner.dismiss();
}
#Override
public void onMalformedURLException(MalformedURLException e,
Object state) {
mSpinner.dismiss();
}
#Override
public void onFacebookError(FacebookError e, Object state) {
mSpinner.dismiss();
}
}
//////////////////////////////////////////////////////////////////////
// Wall Post request listener
//////////////////////////////////////////////////////////////////////
/**
* WallPostRequestListener implements a request lister/callback
* for "wall post requests"
*/
public class WallPostRequestListener implements
com.facebook.android.AsyncFacebookRunner.RequestListener {
/**
* Called when the wall post request has completed
*/
public void onComplete(final String response) {
Log.d("Facebook-Example", "Got response: " + response);
}
#Override
public void onComplete(String response, Object state) {
// TODO Auto-generated method stub
}
#Override
public void onIOException(IOException e, Object state) {
// TODO Auto-generated method stub
}
#Override
public void onFileNotFoundException(FileNotFoundException e,
Object state) {
// TODO Auto-generated method stub
}
#Override
public void onMalformedURLException(MalformedURLException e,
Object state) {
// TODO Auto-generated method stub
}
#Override
public void onFacebookError(FacebookError e, Object state) {
// TODO Auto-generated method stub
}
}
//////////////////////////////////////////////////////////////////////
// Wall post dialog completion listener
//////////////////////////////////////////////////////////////////////
/**
* WallPostDialogListener implements a dialog lister/callback
*/
public class WallPostDialogListener implements
com.facebook.android.Facebook.DialogListener {
/**
* Called when the dialog has completed successfully
*/
public void onComplete(Bundle values) {
final String postId = values.getString("post_id");
if (postId != null) {
Log.d("FB Sample App", "Dialog Success! post_id=" + postId);
mAsyncRunner.request(postId, new WallPostRequestListener());
} else {
Log.d("FB Sample App", "No wall post made");
}
}
#Override
public void onCancel() {
// No special processing if dialog has been canceled
}
#Override
public void onError(DialogError e) {
// No special processing if dialog has been canceled
}
#Override
public void onFacebookError(FacebookError e) {
// No special processing if dialog has been canceled
}
}
/////////////////////////////////////////////////////////
// Login / Logout Listeners
/////////////////////////////////////////////////////////
/**
* Listener for login dialog completion status
*/
private final class LoginDialogListener implements
com.facebook.android.Facebook.DialogListener {
/**
* Called when the dialog has completed successfully
*/
public void onComplete(Bundle values) {
// Process onComplete
Log.d("FB Sample App", "LoginDialogListener.onComplete()");
// Dispatch on its own thread
mHandler.post(new Runnable() {
public void run() {
mText.setText("Facebook login successful. Press Menu...");
}
});
}
/**
*
*/
public void onFacebookError(FacebookError error) {
// Process error
Log.d("FB Sample App", "LoginDialogListener.onFacebookError()");
}
/**
*
*/
public void onError(DialogError error) {
// Process error message
Log.d("FB Sample App", "LoginDialogListener.onError()");
}
/**
*
*/
public void onCancel() {
// Process cancel message
Log.d("FB Sample App", "LoginDialogListener.onCancel()");
}
}
/**
* Listener for logout status message
*/
private class LogoutRequestListener implements RequestListener {
/** Called when the request completes w/o error */
public void onComplete(String response) {
// Only the original owner thread can touch its views
workdammit.this.runOnUiThread(new Runnable() {
public void run() {
mText.setText("Thanks for using FB Sample App. Bye bye...");
friends.clear();
friendsArrayAdapter.notifyDataSetChanged();
}
});
// Dispatch on its own thread
mHandler.post(new Runnable() {
public void run() {
}
});
}
#Override
public void onComplete(String response, Object state) {
// TODO Auto-generated method stub
}
#Override
public void onIOException(IOException e, Object state) {
// TODO Auto-generated method stub
}
#Override
public void onFileNotFoundException(FileNotFoundException e,
Object state) {
// TODO Auto-generated method stub
}
#Override
public void onMalformedURLException(MalformedURLException e,
Object state) {
// TODO Auto-generated method stub
}
#Override
public void onFacebookError(FacebookError e, Object state) {
// TODO Auto-generated method stub
}
}
///////////////////////////////////////////////////////////////////
// Menu handlers
///////////////////////////////////////////////////////////////////
/**
* Invoked at the time to create the menu
* #param menu is the menu to create
*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
/**
* Invoked when preparing to display the menu
* #param menu is the menu to prepare
*/
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem loginItem = menu.findItem(R.id.login);
MenuItem postItem = menu.findItem(R.id.wallpost);
MenuItem getfriendsItem = menu.findItem(R.id.getfriends);
if (mFacebook.isSessionValid()) {
loginItem.setTitle("Logout");
postItem.setEnabled(true);
getfriendsItem.setEnabled(true);
} else {
loginItem.setTitle("Login");
postItem.setEnabled(false);
getfriendsItem.setEnabled(false);
}
loginItem.setEnabled(true);
return super.onPrepareOptionsMenu(menu);
}
/**
* Invoked when a menu item has been selected
* #param item is the selected menu items
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Login/logout toggle
case R.id.login:
// Toggle the button state.
// If coming from login transition to logout.
if (mFacebook.isSessionValid()) {
AsyncFacebookRunner asyncRunner = new AsyncFacebookRunner(mFacebook);
asyncRunner.logout(this.getBaseContext(), new LogoutRequestListener());
} else {
// Toggle the button state.
// If coming from logout transition to login (authorize).
mFacebook.authorize(this, PERMISSIONS, new LoginDialogListener());
}
break;
// Wall Post
case R.id.wallpost: // Wall Post
mFacebook.dialog(workdammit.this, "stream.publish", new WallPostDialogListener());
break;
// Get Friend's List
case R.id.getfriends: // Wall Post
// Get the authenticated user's friends
mSpinner.show();
mAsyncRunner.request("me/friends", new FriendsRequestListener());
break;
default:
return false;
}
return true;
}
}
there are also two other classes that work with the application the code for these are bellow also
/**
* ListView Friends ArrayAdapter
*/
public class FriendsArrayAdapter extends ArrayAdapter {
private final Activity context;
private final ArrayList friends;
private int resourceId;
/**
* Constructor
* #param context the application content
* #param resourceId the ID of the resource/view
* #param friends the bound ArrayList
*/
public FriendsArrayAdapter(
Activity context,
int resourceId,
ArrayList<Friend> friends) {
super(context, resourceId, friends);
this.context = context;
this.friends = friends;
this.resourceId = resourceId;
}
/**
* Updates the view
* #param position the ArrayList position to update
* #param convertView the view to update/inflate if needed
* #param parent the groups parent view
*/
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
if (rowView == null) {
LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = vi.inflate(resourceId, null);
}
Friend f = friends.get(position);
TextView rowTxt = (TextView) rowView.findViewById(R.id.rowtext_top);
rowTxt.setText(f.name);
return rowView;
}
}
public class Friend {
public String id;
public String name;
public byte[] picture;
public Bitmap pictureBitmap;;
}
any help would be great :D
Code looks good!
Here is one thing to try... check to see if your "#Override" onComplete() method is being called and do something there.
Eg.
public class FriendsRequestListener implements
com.facebook.android.AsyncFacebookRunner.RequestListener {
...
...
#Override
public void onComplete(String response, Object state) {
mSpinner.dismiss();
// Got a response... now process it
onComplete(response);
}