I'm trying to implement a facebook app according to the example in the facebook-android-sdk .
I'm changing it a little bit and I'm having a difficult about someting which is very basic.
I'm having my main activity which shows the facebook places near me.
thats the code at mainActivity.java
private void getFBPlaces()
{
fbObject.fetchPlaces();
// NOW I want to fill my listview with the results.....
// someting like
placesList = (ListView) findViewById(R.id.places_list);
placesList.setOnItemClickListener(Places.this);
placesList.setAdapter(new PlacesListAdapter(Places.this));
}
this is the relevant code from FBObject.java see the TODO
private void fetchPlaces() {
/*
* Source tag: fetch_places_tag
*/
Bundle params = new Bundle();
params.putString("type", "place");
try {
params.putString("center",
location.getString("latitude") + "," + location.getString("longitude"));
} catch (JSONException e) {
showToast("No places fetched.");
return;
}
params.putString("distance", "1000");
Utility.mAsyncRunner.request("search", params, new placesRequestListener());
}
/*
* Callback after places are fetched.
*/
public class placesRequestListener extends BaseRequestListener {
#Override
public void onComplete(final String response, final Object state) {
Log.d("Facebook-FbAPIs", "Got response: " + response);
dialog.dismiss();
try {
jsonArray = new JSONObject(response).getJSONArray("data");
if (jsonArray == null) {
showToast("Error: nearby places could not be fetched");
return;
}
} catch (JSONException e) {
showToast("Error: " + e.getMessage());
return;
}
mHandler.post(new Runnable() {
#Override
public void run() {
// TODO: I want to return the result to main activity
.....
}
});
}
got any idea?
thanks
The way I'd do this is passing the activity instance to the PlacesRequestListener and, in the complete callback, do something like "activity.findViewById(R.id.places_list)" to get the list. From here you can set the adapter.
Of course that the method needs to be running on the main thread in order to be able to manipulate the UI
You should consider using the new v3.0b of the Android SDK. In particular, it has a built-in place picker that will help accelerate what you are trying to do here.
You'll find it at http://developers.facebook.com/android
Related
I am building an application that is pretty dependent on async requests to function.
I have the main Activity called MainActivity. This really doesn't do much apart from contain layouts, however it does have a recycleviewer.
I then have a couple of http requests that are done to populate the recycle viewer.
To do this I have wrote a java class as follows:
public class dataforUi extends AsyncTask<String, String, JsonObject> {
private ArrayList<UiElements> els;
protected void onPreExecute() {
progressDialog.setMessage("Downloading your data...");
progressDialog.show();
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface arg0) {
RedditRequests.this.cancel(true);
}
});
}
protected JsonObject doInBackground(String... params) {
Do the http request here, get the result and populate uiElements with it
}
#Override
protected void onPostExecute(JsonObject jsonObject) {
super.onPostExecute(jsonObject);
progressDialog.hide();
}
I have a few more classes like this but hopefully it serves as an example of what I'm trying to do.
Then back in Main Activity, I have this code:
public void getUiElements() {
dataforUi ui = new dataforUi(findViewById(android.R.id.content));
try {
ui.execute("https://t").get();
ArrayList<UiElements> r = ui.getEls();
Log.d("MainFeedScreen", "Size of r is:" + r.size());
UiAdapter = new UiAdapter(r);
mRecyclerView.setAdapter(UiAdapter);
} catch (Exception e) {
}
}
This works fine, but it is very jolty due to the use of .get() on execute to make it blocking. If i remove .get() the progress bar shows up and disappears when the task is done, but my ui thread has progressed past this and ha tried to populate my view with an Empty Array and therefore nothing shows.
I have done a bit of looking into it but cant find a conclusive way of managing the notification of the UI thread that an activity is done.
Would really appericiate any advice on this one.
You need to fix your design.
On post execute, use local broadcast to notify your MainActivity that the AsyncTask is done.
Try using a separate thread to process your data. I use a ListView in stead of a RecyclerView, but the principle is the same.
I have no problems with jolting views.
protected void onPostExecute(String result) {
final String value = result;
// dismiss the dialog after getting all data
progressDialog.dismiss();
if (!value.isEmpty()) {
// updating UI from a new thread
runOnUiThread(new Runnable() {
public void run() {
// ListData is my custom class that holds my data
ArrayList<ListData> arrayDriverListData = new ArrayList<ListData>();
ListDataAdapter adapter = new ListDataAdapter(ListActivity.this, arrayListData);
ListData data;
boolean b = true;
try {
// My data is from a Json source from node 'history'
JSONObject object = new JSONObject(value);
JSONArray array = object.getJSONArray("history");
int len = array.length();
if (len > 0) {
for (int i = 0; i < len; i++) {
final JSONObject o = array.getJSONObject(i);
// Parse my data and add it to my adapter
adapter.add(data);
}
}
} catch (JSONException jex) {
Log.e(TAG, "" + jex.getMessage());
}
// setListAdapter is my call to update my list view
setListAdapter(adapter);
}
});
}
}
Now just update the UI thread
private void setListAdapter(ListDataAdapter adapter){
// my ListView
lvHistory.setAdapter(adapter);
}
I want to have a Splash screen that has an inderteminate ProgressDialog and its progress gets updated by async calls from within a Presenter class (from MVP architecture).
I have a number of API calls to make to my BaaS server and for every successfull call, I would like to update the progress bar.
What's the best way to accomplish this?
I have been trying using EventBus to send notifications to my SplashActivity but it seems that all the API calls are first completed and only then the bus notifications are getting consumed and updating the UI.
What I have done so far is:
SplashActivity:
#Subscribe(threadMode = ThreadMode.MAIN)
public void onProgressBar(String event) {
Timber.d("onProgressBar");
if(event.contains("Done")) {
roundCornerProgressBar.setProgress(100);
} else {
roundCornerProgressBar.setProgress(roundCornerProgressBar.getProgress() + 10);
}
textViewTips.setText(event);
}
Presenter:
InstanceID iid = InstanceID.getInstance(ctx);
String id = iid.getId();
mDataManager.getPreferencesHelper().putInstanceId(id);
GSUtil.instance().deviceAuthentication(id, "android", mDataManager);
GSUtil.instance().getPropertySetRequest("PRTSET", mDataManager);
GSUtil:
public void deviceAuthentication(String deviceId, String deviceOS, final DataManager mDataManager) {
gs.getRequestBuilder().createDeviceAuthenticationRequest()
.setDeviceId(deviceId)
.setDeviceOS(deviceOS)
.send(new GSEventConsumer<GSResponseBuilder.AuthenticationResponse>() {
#Override
public void onEvent(GSResponseBuilder.AuthenticationResponse authenticationResponse) {
if(mDataManager != null) {
mDataManager.getPreferencesHelper().putGameSparksUserId(authenticationResponse.getUserId());
}
EventBus.getDefault().post("Reading player data");
}
});
}
public void getPropertySetRequest(String propertySetShortCode, final DataManager mDataManager) {
gs.getRequestBuilder().createGetPropertySetRequest()
.setPropertySetShortCode(propertySetShortCode)
.send(new GSEventConsumer<GSResponseBuilder.GetPropertySetResponse>() {
#Override
public void onEvent(GSResponseBuilder.GetPropertySetResponse getPropertySetResponse) {
GSData propertySet = getPropertySetResponse.getPropertySet();
GSData scriptData = getPropertySetResponse.getScriptData();
try {
JSONObject jObject = new JSONObject(propertySet.getAttribute("max_tickets").toString());
mDataManager.getPreferencesHelper().putGameDataMaxTickets(jObject.getInt("max_tickets"));
jObject = new JSONObject(propertySet.getAttribute("tickets_refresh_time").toString());
mDataManager.getPreferencesHelper().putGameDataTicketsRefreshTime(jObject.getLong("refresh_time"));
} catch (JSONException e) {
e.printStackTrace();
}
EventBus.getDefault().post("Game data ready");
EventBus.getDefault().post("Done!");
}
});
}
Right now I am just showing you 2 API calls, but I will need another 2.
Thank you
I found the answer! It's easier that I thought, which is unfortunate as I spend about 4 hours on this:
First, I created two new methods on my MVPView interface:
public interface SplashMvpView extends MvpView {
void updateProgressBarWithTips(float prog, String tip);
void gameDataLoaded();
}
Then, in the presenter itself, I call every API call and for every call, I update the View with the updateProgressBarWithTips method and when everything is completed, I finalise it so I can move from Splash screen to Main screen:
private void doGSData(String id) {
getMvpView().updateProgressBarWithTips(10, "Synced player data");
GSAndroidPlatform.gs().getRequestBuilder().createDeviceAuthenticationRequest()
.setDeviceId(id)
.setDeviceOS("android")
.send(new GSEventConsumer<GSResponseBuilder.AuthenticationResponse>() {
#Override
public void onEvent(GSResponseBuilder.AuthenticationResponse authenticationResponse) {
if(mDataManager != null) {
mDataManager.getPreferencesHelper().putGameSparksUserId(authenticationResponse.getUserId());
}
getMvpView().updateProgressBarWithTips(10, "Synced game data");
GSAndroidPlatform.gs().getRequestBuilder().createGetPropertySetRequest()
.setPropertySetShortCode("PRTSET")
.send(new GSEventConsumer<GSResponseBuilder.GetPropertySetResponse>() {
#Override
public void onEvent(GSResponseBuilder.GetPropertySetResponse getPropertySetResponse) {
GSData propertySet = getPropertySetResponse.getPropertySet();
GSData scriptData = getPropertySetResponse.getScriptData();
try {
JSONObject jObject = new JSONObject(propertySet.getAttribute("max_tickets").toString());
mDataManager.getPreferencesHelper().putGameDataMaxTickets(jObject.getInt("max_tickets"));
jObject = new JSONObject(propertySet.getAttribute("tickets_refresh_time").toString());
mDataManager.getPreferencesHelper().putGameDataTicketsRefreshTime(jObject.getLong("refresh_time"));
} catch (JSONException e) {
e.printStackTrace();
}
getMvpView().gameDataLoaded();
}
});
}
});
}
I hope this helps someone, if you're using MVP architecture.
Cheers
I am writing here because this is my last solution of understanding this type of programming.The problem is that I got stuck on what to use to handle the connection to a server and log-in. Should I use async task, handler or thread ? I didn't find a concrete answer stating which one to use, only found that async task is used to download images or other download stuffs.
Until now I have used a thread to connect to the server. The problem I encountered was when I catch the exception ( Putting invalid username/password ) and try to log-in again. ( I needed to "close" the last thread and start one again )
After this I started to use async task but I don't really understand how it should work and I am stuck on a toast of invalid username/password.
private class connectStorage extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
try {
api = DefaultClientFactory.create(host, getUser, getPassword);
if (api.getAuthToken().trim().length() > 3) {
//TO DO LAYOUT CHANGE;
}
} catch (StorageApiException e) {
e.printStackTrace();
Log.i("TEST", "" + e.getMessage());
}
return null;
}
Also, I am 100% sure that calling inflate in the doInBackground method won't work too ( there I wanted to change the activity ).
I am starting the async task on a button press.
When you are using asynctask
You have doInBackground and onPostExecute
So basically get a json or string or boolean as a result from doinbackground
and in onpostexecute check if the login in succesful or not if its succesful save the data from server and start an intent to go to another activity or toast the user that that user login details are wrong and try again.
So your asynctask can be an inner class of your activity class which is login and onClickSubmit button call the asynctask class and on post execute parse the json and according to the result decide what to do
Example:
public class SignInAsycTask extends AsyncTask<RequestParams, Void, String> {
#Override
protected String doInBackground(RequestParams... params) {
return new HttpManager().sendUserData(params[0]);
}
#Override
protected void onPostExecute(String result) {
String[] details = parseJsonObject(result);
if (details != null) {
user.setUser_id(Integer.valueOf(details[0]));
user.setName(details[1]);
if (details.length > 2) {
user.setProfilePic(details[2]);
}
setSharedPreferences();
startActivity(new Intent(Signin.this, MainActivity.class));
finish();
} else {
Toast.makeText(Signin.this, "please try again",
Toast.LENGTH_LONG).show();
}
}
}
public String[] parseJsonObject(String result) {
JSONObject obj = null;
try {
obj = new JSONObject(result);
if (obj.has("success")) {
if (obj.getInt("success") == 1) {
if (obj.has("user_pic")) {
return new String[] {
String.valueOf(obj.getInt("user_id")),
obj.getString("user_name"),
obj.getString("user_pic") };
} else {
return new String[] {
String.valueOf(obj.getInt("user_id")),
obj.getString("user_name"), };
}
} else {
return null;
}
} else {
return null;
}
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
here my RequestParams are just a object where I stored all the details like url parameters to send etc and the output of the doinbackground is a String and I am parsing it in my postexecute method
I have a list called statusses and among it the text needed which are the tweets called status. I want to set the status to listview.
public class MainActivity extends Activity {
ListView i;
List<Status> statusess;
ConfigurationBuilder cb;
twitter4j.Status status3;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
i = (ListView) findViewById(R.id.listView1);
new LongOperation().execute("");
}
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
TwitterFactory tf = new TwitterFactory(cb.build());
Twitter twitter = tf.getInstance();
String[] srch = new String[] {"Obama"};
ResponseList<User> users = null;
try {
users = twitter.lookupUsers(srch);
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (User user : users) {
System.out.println("Friend's Name " + user.getName()); // this print my friends name
if (user.getStatus() != null)
{
System.out.println("Friend timeline");
try {
statusess = twitter.getUserTimeline(user.getName());
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (twitter4j.Status status3 : statusess)
{
System.out.println(status3.getText());
}
}
}
return null;
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
now this System.out.println(status3.getText()); works 100%, the tweets are showing in the console. but how do I get them to the listview in onPostExecute?
I tried
i.setAdapter(new ArrayAdapter<twitter4j.Status>(MainActivity.this,
android.R.layout.simple_list_item_1, statusess));
But I get a lot of text not needed, I need only status3 which is text(tweet), this displays a lot of stuff like tweet id, retweet, followers, etc ..
I also tried this
#Override
protected void onPostExecute(String result) {
for (twitter4j.Status status3 : statusess)
{
i.setAdapter(new ArrayAdapter<statusess>(MainActivity.this,
android.R.layout.simple_list_item_1, status3.getText()));
}
}
but didn't work, a lot of red line xD
users = twitter.lookupUsers(srch);
This gives you a list of users. You are running a for-loop to iterate through the list, changing statuses on each iteration. When the for-loop ends, statuses holds the status list(returned by twitter.getUserTimeline(user.getName())) of the last user. Is this really what you want?
For example, you can display the user list that is returned using twitter.lookupUsers(srch), in the ListView. And, on a item click event, display the status list for that user.
Once you decide on the user for whom you need the status list, do the following:
// Declare an ArrayList with class scope
ArrayList<String> statusListTextOnly;
// Initialize it in doInBackground()
#Override
protected String doInBackground(String... params) {
....
....
statusListTextOnly = new ArrayList<String>();
// Initialize 'statuses' for the user that you have decided on
statusess = twitter.getUserTimeline(user.getName());
// Run a for-loop to fill 'statusListTextOnly'
// We will use 'statusListTextOnly' with the ArrayAdapter
for (twitter4j.Status status3 : statusess) {
statusListTextOnly.add(status3.getText());
}
}
// Initialize/reset ArrayAdapter
#Override
protected void onPostExecute(String result) {
i.setAdapter(new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_list_item_1, statusListTextOnly));
}
The problem with your code lies here:
i.setAdapter(new ArrayAdapter<twitter4j.Status>(MainActivity.this,
android.R.layout.simple_list_item_1, statusess));
Objects passed to an ArrayAdapter are displayed using the toString() method. Now, toString() is mostly overriden for custom objects and serves the purpose of providing a meaningful description of the object itself. It can be overriden to provide literally any kind of information in a String format. In case of Status objects, toString() returns a bit more than what you need. So, we extract the relevant info using Status#getText() and store it in a separate ArrayList.
Your second attempt has problems as well:
#Override
protected void onPostExecute(String result) {
for (twitter4j.Status status3 : statusess) {
i.setAdapter(new ArrayAdapter<statusess>(MainActivity.this,
android.R.layout.simple_list_item_1, status3.getText()));
}
}
Here, you are setting the generic parameter of ArrayAdapter to a variable('statuses'): the generic parameter should be a class. Next, you pass a String as the last argument, whereas an ArrayAdapter's constructor can either take an array of objects, or an ArrayList. Third, you are creating a new instance of your ArrayAdapter and setting it to the ListView on each iteration of the for-loop. This is logically incorrect. You need one instance of an ArrayAdapter and you only need to set it once.
What else can you do:
Create a custom ArrayAdapter that affords new functionality, for example: showing of images along with text.
Dig into BaseAdapter: Highly customizable, all-purpose adapter.
package com.example.twitterdemo;
import java.util.List;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
public final class GetTimeLines {
*//**
* Usage: java twitter4j.examples.GetTimelines ID Password
* #param args String[]
*//*
public static void main(String[] args) {
Twitter unauthenticatedTwitter = new TwitterFactory()
.getInstance();
System.out.println("Showing public timeline.");
try {
List<Status> statuses = unauthenticatedTwitter
.getUserTimeline();
for (Status status : statuses) {
System.out.println(status.getUser().getName() + ":"
+ status.getText());
}
if (args.length < 2) {
System.out
.println("You need to specify TwitterID/Password combination to show UserTimelines.");
System.out
.println("Usage: java twitter4j.examples.GetTimelines ID Password");
System.exit(0);
}
// Other methods require authentication
Twitter twitter = new TwitterFactory().getInstance();
statuses = twitter.getUserTimeline();
System.out.println("------------------------------");
System.out.println("Showing " + args[0]
+ "'s friends timeline.");
for (Status status : statuses) {
System.out.println(status.getUser().getName() + ":"
+ status.getText());
}
statuses = twitter.getUserTimeline();
System.out.println("------------------------------");
System.out.println("Showing " + args[0] + "'s timeline.");
for (Status status : statuses) {
System.out.println(status.getUser().getName() + ":"
+ status.getText());
}
Status status = twitter.showStatus(81642112l);
System.out.println("------------------------------");
System.out.println("Showing " + status.getUser().getName()
+ "'s status updated at " + status.getCreatedAt());
System.out.println(status.getText());
System.exit(0);
} catch (TwitterException te) {
System.out.println("Failed to get timeline: "
+ te.getMessage());
System.exit(-1);
}
}
}
This question already has answers here:
AsyncTask and error handling on Android
(12 answers)
Closed 9 years ago.
Currently I'm working on implementing network communication layer. And I thought it's good to consult with more experienced Android developers first.
I have a class called WebApiController which is responsible for: making requests and parsing responses, and storing them in the models. WebApiController methods execute on the main thread, so I wrap them in AsyncTasks to take the load out of the main thread. WebApiController methods potentially throws exceptions such as ServerBadResponseException, XmlParserException, etc. And I want to be able to handle them accordingly to the type of error (i.e. show different error messages based on the type of error). So, what would be the best way to notify the onPostExecute about the error type, and nicely handle it there.
Or this:
class SomeTask extends AsyncTask<Void, Void, Params> {
#Override
protected Params doInBackground(Void... voids) {
Params params = new Params();
try {
.....
params._result = .....
} catch (Throwable e) {
params._error = e;
}
return params;
}
#Override
protected void onPostExecute(Params params) {
if(params._error != null){
....
} else {
....
}
}
}
class Params {
public Throwable _error;
public Object _result;
}
Basically the easiest way is to set a return code like "SUCCESS", "FAILURE_XY" and process that in your onPostExecute(). This works also, when you normally would return data...
doInBackground() {
try {
// code
return data;
} catch (Exception e) {
Log.e(TAG, "error description", e);
resultCode = FAILURE;
return null;
}
}
onPostExecute(Data data) {
if (data == null) {
// check resultCode!
} else {
// work with your data
}
}
You can try this (in doInBackgroung method):
try {
........
} catch (final Throwable e) {
runOnUiThread(new Runnable() {
public void run() {
Log.e(TAG, e.getMessage(), e);
Toast.makeText(......).show();
}
});
}