I have one Activity that uses startActivityForResult for Contact by ACTION_PICK. In first, my test is choice the contact and after check the contact selected.
public class ListaMensagemActivity extends ListActivity implements Transacao{
private List<Mensagem> mensagens;
private static final int CONTATO_SELECIONADO=1;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
TransacaoTask task = new TransacaoTask(this, this, R.string.aguarde);
task.execute();
}
#Override
public void executar() throws Exception {
// Busca as mensagens em uma thread
this.mensagens = new MensagemService(this).getMensagem();
}
#Override
public void atualizarView() {
// Atualiza as mensagens na thread principal
if (this.mensagens != null) {
this.setListAdapter(new MensagemAdapter(this, mensagens));
}
}
#Override
public void onListItemClick(ListView parent, View view, int posicao,
long id) {
super.onListItemClick(parent, view, posicao, id);
Intent contactIntent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(contactIntent,CONTATO_SELECIONADO);
}
}
atleast send the code that you wanted to test. this is the structure of unit testing in robotium.
your question is also not clear
public class SimpleActivityTest extends
ActivityInstrumentationTestCase2<SimpleActivity> {
private Solo solo;
public SimpleActivityTest() {
super(SimpleActivity.class);
}
public void setUp() throws Exception {
solo = new Solo(getInstrumentation(), getActivity());
}
#Override
public void tearDown() throws Exception {
solo.finishOpenedActivities();
}
public void testListItemClickShouldDisplayToast() throws Exception {
// check that we have the right activity
solo.assertCurrentActivity("wrong activity", SimpleActivity.class);
// Click a button which will start a new Activity
// Here we use the ID of the string to find the right button
solo.clickOnButton(solo
.getString(de.vogella.android.test.target.R.string.button1));
// assert that the current activity is the SimpleListActivity.class
solo.assertCurrentActivity("wrong activity", SimpleListActivity.class);
solo.clickInList(1);
// searchForText has a timeout of 5 seconds
assertTrue(solo.waitForText("Android")); // Assertion
solo.clickInList(2);
assertTrue(solo.waitForText("iPhone")); // Assertion
solo.clickInList(3);
assertTrue(solo.waitForText("Blackberry")); // Assertion
solo.goBack();
solo.clickOnButton("Button2");
solo.clickOnButton("Button3");
}
public void testListItemClickShouldDisplayToast() throws Exception {
// open the menu
solo.sendKey(Solo.MENU);
solo.clickOnText("Preferences");
solo.clickOnText("User");
solo.clearEditText(0);
Assert.assertTrue(solo.searchText(""));
solo.enterText(0, "http//:www.vogella.com");
Assert.assertTrue(solo.searchText("http//:www.vogella.com"));
solo.goBack();
}
}
The my question is a test to Intent.ACTION_PICK. In case, I have an action pick to choose a contact's number in view of android and get the contact's number.
Related
I wrote a code for performing test for the listview (i.e., we can check the position of the item in listview, display toast messame when we click on item in list). i want to move to another activity when we click on list item in android.
public class MainActivityTest {
#Rule
public ActivityTestRule<MainActivity> main = new ActivityTestRule<MainActivity>(MainActivity.class) {
#Override
protected void beforeActivityLaunched() {
Intents.init();
super.beforeActivityLaunched();
}
#Override
protected void afterActivityFinished() {
super.afterActivityFinished();
Intents.release();
}
};
}
here i write a test for counting the nomber of items in list
#Test
public void testShouldLaunchTheMainActivityAndFindItemsInTheList() throws Exception {
ListView listview = (ListView) main.getActivity().findViewById(R.id.PhoneVideoList);
assertThat((int) listview.getCount(), is(61));
}
here i write a test for performing on click in list item
#Test
public void testShouldTestTheItemNameInTheList() throws Exception {
ListView listview = (ListView) main.getActivity().findViewById(R.id.PhoneVideoList);
listview.performItemClick(listview.getChildAt(1), 1, listview.getAdapter().getItemId(1));
listview.performItemClick(listview.getChildAt(4), 4, listview.getAdapter().getItemId(4));
listview.performItemClick(listview.getChildAt(10), 10, listview.getAdapter().getItemId(10));
}
#Test
public void testShouldShowTheItemDetailWhenAnItemIsClicked() {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
final ListView listview = (ListView) main.getActivity().findViewById(R.id.PhoneVideoList);
instrumentation.runOnMainSync(new Runnable() {
#Override
public void run() {
int position = 0;
listview.performItemClick(listview.getChildAt(position), position, listview.getAdapter().getItemId(position));
Log.e("in on click", "on click");
}
});
Instrumentation.ActivityMonitor monitor = instrumentation.addMonitor(VideoPlay.class.getName(), null, false);
Activity itemDetailActivity = instrumentation.waitForMonitorWithTimeout(monitor, 5000);
/* TextView detailView = (TextView) itemDetailActivity.findViewById(R.id.item_detail);
assertThat(detailView.getText().toString(), is("Android"));*/
}
}
now i want to know how to move to next activity when we click on list item
Using robotium:
1. Add following dependencies in app gradle:
testCompile 'junit:junit:
androidTestCompile 'junit:junit:4.12'
androidTestCompile 'com.jayway.android.robotium:robotium:5.4.+'
2. Add click listener to the list item which starts new activity
3. Add following test
public class ListViewClickTest extends ActivityInstrumentationTestCase2<YourActivity> {
protected final CountDownLatch signal = new CountDownLatch (1);
protected Context context;
protected Activity activity;
protected Solo solo;
public ListViewClickTest () {
super (YourActivity.class);
}
#MediumTest
public void testListViewClick () {
waitForTime (4); //time to wait till your network request completes if data is being fetched from server, ignore otherwise
solo.clickInList (0); //position of list view item
waitForTime (50);
}
#Override
protected void setUp () throws Exception {
super.setUp ();
this.context = getInstrumentation ().getTargetContext ();
prepareTestData ();
activity = getActivity ();
solo = new Solo (getInstrumentation (), activity);
}
protected void waitForTime (long seconds) {
try {
signal.await (seconds, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
e.printStackTrace ();
}
}
protected void prepareTestData () {
//Prepare test data if any
}
}
I'm trying to use an AsyncTaskLoader to load data in the background to populate a detail view in response to a list item being chosen. I've gotten it mostly working but I'm still having one issue. If I choose a second item in the list and then rotate the device before the load for the first selected item has completed, then the onLoadFinished() call is reporting to the activity being stopped rather than the new activity. This works fine when choosing just a single item and then rotating.
Here is the code I'm using. Activity:
public final class DemoActivity extends Activity
implements NumberListFragment.RowTappedListener,
LoaderManager.LoaderCallbacks<String> {
private static final AtomicInteger activityCounter = new AtomicInteger(0);
private int myActivityId;
private ResultFragment resultFragment;
private Integer selectedNumber;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myActivityId = activityCounter.incrementAndGet();
Log.d("DemoActivity", "onCreate for " + myActivityId);
setContentView(R.layout.demo);
resultFragment = (ResultFragment) getFragmentManager().findFragmentById(R.id.result_fragment);
getLoaderManager().initLoader(0, null, this);
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.d("DemoActivity", "onDestroy for " + myActivityId);
}
#Override
public void onRowTapped(Integer number) {
selectedNumber = number;
resultFragment.setResultText("Fetching details for item " + number + "...");
getLoaderManager().restartLoader(0, null, this);
}
#Override
public Loader<String> onCreateLoader(int id, Bundle args) {
return new ResultLoader(this, selectedNumber);
}
#Override
public void onLoadFinished(Loader<String> loader, String data) {
Log.d("DemoActivity", "onLoadFinished reporting to activity " + myActivityId);
resultFragment.setResultText(data);
}
#Override
public void onLoaderReset(Loader<String> loader) {
}
static final class ResultLoader extends AsyncTaskLoader<String> {
private static final Random random = new Random();
private final Integer number;
private String result;
ResultLoader(Context context, Integer number) {
super(context);
this.number = number;
}
#Override
public String loadInBackground() {
// Simulate expensive Web call
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Item " + number + " - Price: $" + random.nextInt(500) + ".00, Number in stock: " + random.nextInt(10000);
}
#Override
public void deliverResult(String data) {
if (isReset()) {
// An async query came in while the loader is stopped
return;
}
result = data;
if (isStarted()) {
super.deliverResult(data);
}
}
#Override
protected void onStartLoading() {
if (result != null) {
deliverResult(result);
}
// Only do a load if we have a source to load from
if (number != null) {
forceLoad();
}
}
#Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
#Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
result = null;
}
}
}
List fragment:
public final class NumberListFragment extends ListFragment {
interface RowTappedListener {
void onRowTapped(Integer number);
}
private RowTappedListener rowTappedListener;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
rowTappedListener = (RowTappedListener) activity;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(getActivity(),
R.layout.simple_list_item_1,
Arrays.asList(1, 2, 3, 4, 5, 6));
setListAdapter(adapter);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
ArrayAdapter<Integer> adapter = (ArrayAdapter<Integer>) getListAdapter();
rowTappedListener.onRowTapped(adapter.getItem(position));
}
}
Result fragment:
public final class ResultFragment extends Fragment {
private TextView resultLabel;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.result_fragment, container, false);
resultLabel = (TextView) root.findViewById(R.id.result_label);
if (savedInstanceState != null) {
resultLabel.setText(savedInstanceState.getString("labelText", ""));
}
return root;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("labelText", resultLabel.getText().toString());
}
void setResultText(String resultText) {
resultLabel.setText(resultText);
}
}
I've been able to get this working using plain AsyncTasks but I'm trying to learn more about Loaders since they handle the configuration changes automatically.
EDIT: I think I may have tracked down the issue by looking at the source for LoaderManager. When initLoader is called after the configuration change, the LoaderInfo object has its mCallbacks field updated with the new activity as the implementation of LoaderCallbacks, as I would expect.
public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
LoaderInfo info = mLoaders.get(id);
if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
if (info == null) {
// Loader doesn't already exist; create.
info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
if (DEBUG) Log.v(TAG, " Created new loader " + info);
} else {
if (DEBUG) Log.v(TAG, " Re-using existing loader " + info);
info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
}
if (info.mHaveData && mStarted) {
// If the loader has already generated its data, report it now.
info.callOnLoadFinished(info.mLoader, info.mData);
}
return (Loader<D>)info.mLoader;
}
However, when there is a pending loader, the main LoaderInfo object also has an mPendingLoader field with a reference to a LoaderCallbacks as well, and this object is never updated with the new activity in the mCallbacks field. I would expect to see the code look like this instead:
// This line was already there
info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
// This line is not currently there
info.mPendingLoader.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
It appears to be because of this that the pending loader calls onLoadFinished on the old activity instance. If I breakpoint in this method and make the call that I feel is missing using the debugger, everything works as I expect.
The new question is: Have I found a bug, or is this the expected behavior?
In most cases you should just ignore such reports if Activity is already destroyed.
public void onLoadFinished(Loader<String> loader, String data) {
Log.d("DemoActivity", "onLoadFinished reporting to activity " + myActivityId);
if (isDestroyed()) {
Log.i("DemoActivity", "Activity already destroyed, report ignored: " + data);
return;
}
resultFragment.setResultText(data);
}
Also you should insert checking isDestroyed() in any inner classes. Runnable - is the most used case.
For example:
// UI thread
final Handler handler = new Handler();
Executor someExecutorService = ... ;
someExecutorService.execute(new Runnable() {
public void run() {
// some heavy operations
...
// notification to UI thread
handler.post(new Runnable() {
// this runnable can link to 'dead' activity or any outer instance
if (isDestroyed()) {
return;
}
// we are alive
onSomeHeavyOperationFinished();
});
}
});
But in such cases the best way is to avoid passing strong reference on Activity to another thread (AsynkTask, Loader, Executor, etc).
The most reliable solution is here:
// BackgroundExecutor.java
public class BackgroundExecutor {
private static final Executor instance = Executors.newSingleThreadExecutor();
public static void execute(Runnable command) {
instance.execute(command);
}
}
// MyActivity.java
public class MyActivity extends Activity {
// Some callback method from any button you want
public void onSomeButtonClicked() {
// Show toast or progress bar if needed
// Start your heavy operation
BackgroundExecutor.execute(new SomeHeavyOperation(this));
}
public void onSomeHeavyOperationFinished() {
if (isDestroyed()) {
return;
}
// Hide progress bar, update UI
}
}
// SomeHeavyOperation.java
public class SomeHeavyOperation implements Runnable {
private final WeakReference<MyActivity> ref;
public SomeHeavyOperation(MyActivity owner) {
// Unlike inner class we do not store strong reference to Activity here
this.ref = new WeakReference<MyActivity>(owner);
}
public void run() {
// Perform your heavy operation
// ...
// Done!
// It's time to notify Activity
final MyActivity owner = ref.get();
// Already died reference
if (owner == null) return;
// Perform notification in UI thread
owner.runOnUiThread(new Runnable() {
public void run() {
owner.onSomeHeavyOperationFinished();
}
});
}
}
Maybe not best solution but ...
This code restart loader every time, which is bad but only work around that works - if you want to used loader.
Loader l = getLoaderManager().getLoader(MY_LOADER);
if (l != null) {
getLoaderManager().restartLoader(MY_LOADER, null, this);
} else {
getLoaderManager().initLoader(MY_LOADER, null, this);
}
BTW. I am using Cursorloader ...
A possible solution is to start the AsyncTask in a custom singleton object and access the onFinished() result from the singleton within your Activity. Every time you rotate your screen, go onPause() or onResume(), the latest result will be used/accessed. If you still don't have a result in your singleton object, you know it is still busy or that you can relaunch the task.
Another approach is to work with a service bus like Otto, or to work with a Service.
Ok I'm trying to understand this excuse me if I misunderstood anything, but you are losing references to something when the device rotates.
Taking a stab...
would adding
android:configChanges="orientation|keyboardHidden|screenSize"
in your manifest for that activity fix your error? or prevent onLoadFinished() from saying the activity stopped?
Update1
activity:
public Integer _number = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
if (_number >0)
{
Log.d("onSuccessfulExecute", ""+_number);
}
else
{
Log.d("onSuccessfulExecute", "nope empty songs lists");
}
}
public int onSuccessfulExecute(int numberOfSongList) {
_number = numberOfSongList;
if (numberOfSongList >0)
{
Log.d("onSuccessfulExecute", ""+numberOfSongList);
}
else
{
Log.d("onSuccessfulExecute", "nope empty songs lists");
}
return numberOfSongList;
}
end Update1
UPDATE: AsynchTask has its own external class.
How to pass an value from AsyncTask onPostExecute()... to activity
my code does returning value from onPostExecute() and updating on UI but i am looking for a way to set the activity variable (NumberOfSongList) coming from AsynchTask.
AsyncTask class:
#Override
public void onPostExecute(asynctask.Payload payload)
{
AsyncTemplateActivity app = (AsyncTemplateActivity) payload.data[0];
//the below code DOES UPDATE the UI textView control
int answer = ((Integer) payload.result).intValue();
app.taskStatus.setText("Success: answer = "+answer);
//PROBLEM:
//i am trying to populate the value to an variable but does not seems like the way i am doing:
app.NumberOfSongList = payload.answer;
..............
..............
}
Activity:
public Integer NumberOfSongList;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Several UI Code
new ConnectingTask().execute();
Log.d("onCreate", ""+NumberOfSongList);
}
What about using a setter method? e.g.
private int _number;
public int setNumber(int number) {
_number = number;
}
UPDATE:
Please look at this code. This will do what you're trying to accomplish.
Activity class
public class TestActivity extends Activity {
public int Number;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
Button btnDisplay = (Button) findViewById(R.id.btnDisplay);
btnDisplay.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Toast toast = Toast.makeText(v.getContext(), "Generated number: " + String.valueOf(Number), Toast.LENGTH_LONG);
toast.show();
}
});
new TestTask(this).execute();
}
}
AsyncTask class
public class TestTask extends AsyncTask<Void, Void, Integer> {
private final Context _context;
private final String TAG = "TestTask";
private final Random _rnd;
public TestTask(Context context){
_context = context;
_rnd = new Random();
}
#Override
protected void onPreExecute() {
//TODO: Do task init.
super.onPreExecute();
}
#Override
protected Integer doInBackground(Void... params) {
//Simulate a long-running procedure.
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
Log.e(TAG, e.getMessage());
}
return _rnd.nextInt();
}
#Override
protected void onPostExecute(Integer result) {
TestActivity test = (TestActivity) _context;
test.Number = result;
super.onPostExecute(result);
}
}
Just a word of caution: Be very careful when attempting to hold a reference to an Activity instance in an AsyncTask - I found this out the hard way :). If the user happens to rotate the device while your background task is still running, your activity will be destroyed and recreated thus invalidating the reference being to the Activity.
Create a listener.
Make a new class file. Called it something like MyAsyncListener and make it look like this:
public interface MyAsyncListener() {
onSuccessfulExecute(int numberOfSongList);
}
Make your activity implement MyAsyncListener, ie,
public class myActivity extends Activity implements MyAsyncListener {
Add the listener to the constructor for your AsyncTask and set it to a global var in the Async class. Then call the listener's method in onPostExecute and pass the data.
public class MyCustomAsync extends AsyncTask<Void,Void,Void> {
MyAsyncListener mal;
public MyCustomAsync(MyAsyncListener listener) {
this.mal = listener;
}
#Override
public void onPostExecute(asynctask.Payload payload) {
\\update UI
mal.onSuccessfulExecute(int numberOfSongList);
}
}
Now, whenever your AsyncTask is done, it will call the method onSuccessfulExecute in your Activity class which should look like:
#Override
public void onSuccessfulExecute(int numberOfSongList) {
\\do whatever
}
Good luck.
This question already has answers here:
Can't create handler inside thread that has not called Looper.prepare()
(30 answers)
Closed 8 years ago.
This is my code. When I click on my app logo, after the splash screen, this is the class that is first called from an intent. But, after the tab is loaded, and onPreExecute() is once executed, the app crashes.
public class HomeActivity extends Activity{
private static final String dialog = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.user_main_tab_home);
new HomeDownloadPage().execute();
}
public class HomeDownloadPage extends AsyncTask<String,Void,String>{
private final ProgressDialog dialog = new ProgressDialog(HomeActivity.this);
protected void onPreExecute() {
this.dialog.setMessage("Have Paitence! ");
this.dialog.show();
}
#Override
protected String doInBackground(String... params) {
User user = null;
try {
user = new User("4eeb");
user.getList();
/*
* Custom adapter
* */
ArrayList<User> users = new ArrayList<User>();
for(User u : user.following){
users.add(u);
}
ListView lv = (ListView) findViewById(R.id.user_list);
final UserFollowingListAdapter csl = new UserFollowingListAdapter(HomeActivity.this,R.layout.user_list,users,this);
OnItemClickListener listener = new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
Object o = csl.getItem(position);
setTitle(parent.getItemAtPosition(position).toString());
}
};
lv.setAdapter(csl);
lv.setOnItemClickListener(listener);
/*
* Onclick listener
* */
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
Intent i = new Intent("com.list.SEARCH");
Toast.makeText(HomeActivity.this, "rowitem clicked", Toast.LENGTH_LONG).show();
// TODO Auto-generated method stub
}
});
} catch (Exception e) {
showError();
}
return null;
}
protected void onPostExecute(String result) {
// execution of result of Long time consuming operation
}
}
public void showError(){
new AlertDialog.Builder(HomeActivity.this)
.setTitle(" Oops , Server down :( ")
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
}
//
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Do nothing.
}
}).show();
}
}
Error I get is at the doInBackground() function.
Exact error: 01-19 19:03:01.264: E/AndroidRuntime(1138): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
What is the problem?
You are attempting to do things involving the UI (ListView lv = (ListView) findViewById(R.id.user_list);) within a background thread. You can not do this. You may process information in the background, then pass it back to the UI thread and update the UI
As pyrodante said, you're attempting to modify the UI while not on the UI thread. If you want modify the UI from a non-UI thread, you can use the runOnUiThread() function. That said, there's a better solution to your problem. You really should be using a Loader. They were basically designed to address exactly what you're trying to do. Note that even if you're designing an app that's pre-3.0, you can still access loaders via the Android Support package.
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);
}