Skip to content

Instantly share code, notes, and snippets.

@nesquena
Last active December 25, 2015 20:29
Show Gist options
  • Save nesquena/58beb9c9fb324a6c8a04 to your computer and use it in GitHub Desktop.
Save nesquena/58beb9c9fb324a6c8a04 to your computer and use it in GitHub Desktop.
Project 3: Helpful Hints

Project 3 (Twitter Client) Helpful Hints

Here's a list of useful notes you may find helps save you time while developing the TwitterClient or running into problems:

  • Tip #1: Before using Twitter API, you need to register with the Twitter Developer and create an application. Be sure that a few settings are configured properly such as select Read and Write access, and specify a generic callback URL. You must specify a callback URL or the API will not work! Check this screen and make sure you application settings match.

  • Tip #2: This assignment is based on the RestClientTemplate which is a template for building rest clients that pulls together several popular open-source libraries and then also our integration layer called the android-oauth-handler for easy authentication. To import, after downloading the zip file, go to Eclipse and select File => Import... => Android => Existing Android Code and then make sure to give the project a better name before hitting Finish. If you have a compile error, try reimporting the project and/or restarting Eclipse. You can also try running Project => Clean....

  • Problem #1: Authentication fails when trying to connect with OAuth. Be sure to verify the following:

    • Check Tip #1 above and make sure your Twitter OAuth app is configured correctly with a callback specified
    • Make sure you have added the internet permission <uses-permission android:name="android.permission.INTERNET" /> to your manifest within the app.
    • Check the time on your emulator clock and verify the time matches the actual time. If the emulator clock time gets too far off from actual time, OAuth will stop working. Restart the emulator or go into settings to adjust the time.
    • Ensure the TwitterClient has a custom REST_CALLBACK_URL that matches the details within the AndroidManifest.xml. Check Step 1 from the rest-client-template.
    • Verify that the Twitter API Key (REST_CONSUMER_KEY) and Secret (REST_CONSUMER_SECRET) are properly specified within the TwitterClient. Double-check the key and secret values and that they were properly copied from your app to the client.
  • Problem #2: Can't get back a JSON Response from Twitter? A number of people always run into issues with their emulator and not being able to access the Twitter API. If you are pretty sure you have the code right and you can't seem to get any response back from the API, try these steps:

    • Check Problem #1 above and read the solutions listed there first to see if they are relevant
    • If you are getting "Unable to resolve host", Check your WiFi connection and then go to the browser on the phone and verify you can access the internet. If you cannot, try checking the wifi setting and turning it off and on until the internet works (you may need to restart the emulator)
    • Verify the API URL is correct especially if you get a "forbidden" message, ensure the base url in the client is set to https://api.twitter.com/1.1 and then each method uses getApiUrl when forming the endpoint requests.
    • Make sure you are using the new JsonHttpResponseHandler() (docs) in your AsyncHttpClient network call and make sure you are sending client.get(url, new JsonHttpResponseHandler() { ... })
    • Verify that the onSuccess signature is correct. The Twitter timeline API returns an array of JSON objects so make sure the onSuccess is using JSONArray and not JSONObject for the signature in this case. This is entirely dependent on whether a dictionary or array is the root object in the API response i.e public void onSuccess(JSONArray response)
    • Add an onFailure to the JsonHttpResponseHandler callbacks and log there to ensure that its not being hit or the API rate limit is not being exceeded (Error 429) which causes responses to stop working for a small period of time. Also, if no logging occurs, try to implement the handleFailureMessage(Throwable e, String responseBody) instead of onFailure.
    • Check your LogCat to make sure there are no specific error messages (and watch this debugging video for more tips), use filters to more easily read the log.
    • Uninstall the app from the emulator and allow it to be fully re-installed by relaunching it from within eclipse.
    • Restart the Emulator (close and relaunch)
    • Restart Eclipse (completely close and relaunch)
  • Problem #3: Call to post tweet API doesn't work. Similar to problem #2 but when you are sending an API call and not getting back a response check the following:

    • Am I using the correct request method (get, post, delete)? Make sure the API you are calling has the request method you expect. Make sure the code reads client.post(...).
    • Am I sending to the correct URL (check for typos)?
    • Am I correctly using the JsonHttpResponseHandler when constructing the callback for the request?
    • Am I passing the parameters into the request? Make sure you are passing the status parameter and that the RequestParams are being passed into the call i.e client.post(url, params, handler);
    • Does my onSuccess expect the correct object (JSONObject vs JSONArray)
  • Tip #3: Be sure to read through the API docs for this assignment. Review the available twitter endpoints in particular the one for getting timelines and posting statuses. Ask yourself which other endpoints are most important (i.e profile timeline for a user, mentions, etc) and review those as well.

  • Tip #4: Your home timeline should support pagination through "infinite scroll" as shown in the Endless Scrolling Guide. Implement that by creating a unified method used for the initial tweets load and then also for subsequent pagination. See the twitter working with timelines guide for a closer look at how to paginate. You can actually paginate either using the (deprecated) page parameter or by using the newer max_id approach that is now preferred.

  • Tip #5: Whenever sending a network request, be sure to handle the failure case as outlined in our cliffnotes. Not handling this case means your application is extremely brittle, take the time to properly notify the user and handle the behavior of the internet not being connected.

  • Tip #6: Twitter apps tend to display relative timestamps such as "1 hour ago" or "3 days ago" rather than absolute times. You can easily achieve this affect using the built-in getRelativeDateTimeString method for displaying relative times as shown here. Simple example of parsing dates can be found here. Or try out PrettyTime for an even better relative time.

  • Note #1: Make sure that after you post a tweet to the timeline that the new tweet shows up in the timeline. To do this, refreshing the timeline may not be enough because of the lag before the new tweet shows up in the timeline API call. You might be better off returning a tweet object as a result within the intent from the compose activity. After the tweet is successfully posted to twitter from within Compose, we can pass the Tweet back to the TimelineActivity and inject the created tweet directly into the adapter for the timeline from within onActivityResult. See the intents cliffnotes for how to return data back to the timeline activity.

  • Note #2: By default, your twitter client probably looks boring and uninteresting. Take a little time to spruce up your UI and add visual polish with this guide and by reviewing the cloning a screen tutorial and Q&A.

  • Problem #4: Using ActiveAndroid, got an error saying that there is no such table. This is because ActiveAndroid only generates the schema if there is no existing database file. In order to "regenerate" the schema after creating a new model, the easiest way is to uninstall the app from the emulator and allow it to be fully re-installed. This is because this clears the database file and triggers ActiveAndroid to recreate the tables based on the annotated models in the project.

  • Problem #5: Using ActiveAndroid, NullPointerException when trying to save. This is because ActiveAndroid needs you to save all objects separately. Before saving a tweet, be sure to save the associated user first. So user.save() before you call tweet.save() since storing the user requires the local id to be set and assigned as the foreign key.

  • Problem #6: Using ActiveAndroid, query always returns no results. If there is data and yet a data query always returns no results, make sure that every model has a default constructor that does not require any arguments.

  • Tip #7: One optional feature is displaying a character count for the twitter client as the user types their tweet. Each tweet can only be a maximum of 140 characters. To achieve this, you can add a TextView to your ComposeActivity and then attach a listener for when the user types text into the EditText. See the event handling cliffnotes to see how to use the addTextChangedListener to fire events whenever the user types into the text field. If the total characters exceeds 140, consider disabling the submit button or making the count red to indicate that the tweet isn't valid.

  • Problem #6: PullToRefreshView library doesn't compile properly. Make sure to follow the cliffnotes precisely following the install instructions and that the view namespace <eu.erikw.PullToRefreshListView for the ListView is used in your Activity XML. If you get a compile error or a build path error after importing, try reopening eclipse, also try cleaning the library project with Project => Clean.

  • Problem #7: java.io.NotSerializableException: org.json.JSONArray. If you encounter any issues passing an object (such as a tweet or user) into an intent, you may encounter serialization issues. These are caused by having fields that are not serializable defined in a model. For example JSONObject and JSONArray are not serializable types meaning you can't store these by default as member variables in a serializable class. If your Tweet or User extends from BaseModel as shown in the video, that contains a JSONObject and can't be serialized. You should refactor to remove the use of BaseModel and just follow the JSON to Models approach for deserialization instead to avoid keeping around the BaseModel. In any other case, if you really need to store JSON data in the raw, then you can this simple pattern to workaround the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment