Android: show server error message to user when add feed fails. The error message was being sent when non-premium users tried to search for feeds and was causing the App to crash.

This commit is contained in:
Lance Johnson 2013-03-30 00:58:23 -05:00
parent 33bd64f2a0
commit 6a72dff821
7 changed files with 133 additions and 23 deletions

View file

@ -1,19 +1,17 @@
package com.newsblur.activity;
import java.util.ArrayList;
import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
@ -24,12 +22,12 @@ import com.newsblur.R;
import com.newsblur.domain.FeedResult;
import com.newsblur.fragment.AddFeedFragment;
import com.newsblur.network.SearchAsyncTaskLoader;
import com.newsblur.network.SearchLoaderResponse;
public class SearchForFeeds extends SherlockFragmentActivity implements LoaderCallbacks<ArrayList<FeedResult>>, OnItemClickListener {
public class SearchForFeeds extends SherlockFragmentActivity implements LoaderCallbacks<SearchLoaderResponse>, OnItemClickListener {
private static final int LOADER_TWITTER_SEARCH = 0x01;
private Menu menu;
private ListView resultsList;
private Loader<ArrayList<FeedResult>> searchLoader;
private Loader<SearchLoaderResponse> searchLoader;
private FeedSearchResultAdapter adapter;
@Override
@ -57,7 +55,6 @@ public class SearchForFeeds extends SherlockFragmentActivity implements LoaderCa
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.search, menu);
this.menu = menu;
return true;
}
@ -94,20 +91,25 @@ public class SearchForFeeds extends SherlockFragmentActivity implements LoaderCa
}
@Override
public Loader<ArrayList<FeedResult>> onCreateLoader(int loaderId, Bundle bundle) {
public Loader<SearchLoaderResponse> onCreateLoader(int loaderId, Bundle bundle) {
String searchTerm = bundle.getString(SearchAsyncTaskLoader.SEARCH_TERM);
return new SearchAsyncTaskLoader(this, searchTerm);
}
@Override
public void onLoadFinished(Loader<ArrayList<FeedResult>> loader, ArrayList<FeedResult> results) {
adapter = new FeedSearchResultAdapter(this, 0, 0, results);
resultsList.setAdapter(adapter);
public void onLoadFinished(Loader<SearchLoaderResponse> loader, SearchLoaderResponse results) {
setSupportProgressBarIndeterminateVisibility(false);
if(!results.hasError()) {
adapter = new FeedSearchResultAdapter(this, 0, 0, results.getResults());
resultsList.setAdapter(adapter);
} else {
String message = results.getErrorMessage() == null ? "Error" : results.getErrorMessage();
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onLoaderReset(Loader<ArrayList<FeedResult>> loader) {
public void onLoaderReset(Loader<SearchLoaderResponse> loader) {
}

View file

@ -22,6 +22,10 @@ import android.webkit.CookieSyncManager;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.newsblur.database.DatabaseConstants;
import com.newsblur.database.FeedProvider;
import com.newsblur.domain.Classifier;
@ -38,6 +42,7 @@ import com.newsblur.network.domain.CategoriesResponse;
import com.newsblur.network.domain.FeedFolderResponse;
import com.newsblur.network.domain.FeedRefreshResponse;
import com.newsblur.network.domain.LoginResponse;
import com.newsblur.network.domain.Message;
import com.newsblur.network.domain.ProfileResponse;
import com.newsblur.network.domain.SocialFeedResponse;
import com.newsblur.network.domain.StoriesResponse;
@ -263,7 +268,7 @@ public class APIManager {
if (response.responseCode == HttpStatus.SC_OK && !response.hasRedirected) {
if (TextUtils.equals(pageNumber,"1")) {
Uri storyUri = FeedProvider.ALL_STORIES_URI;
int deleted = contentResolver.delete(storyUri, null, null);
contentResolver.delete(storyUri, null, null);
}
for (Story story : storiesResponse.stories) {
@ -678,15 +683,14 @@ public class APIManager {
return (response.responseCode == HttpStatus.SC_OK && !response.hasRedirected);
}
public FeedResult[] searchForFeed(String searchTerm) {
public FeedResult[] searchForFeed(String searchTerm) throws ServerErrorException {
final APIClient client = new APIClient(context);
ContentValues values = new ContentValues();
values.put(APIConstants.PARAMETER_FEED_SEARCH_TERM, searchTerm);
final APIResponse response = client.get(APIConstants.URL_FEED_AUTOCOMPLETE, values);
if (response.responseCode == HttpStatus.SC_OK && !response.hasRedirected) {
// TODO doesn't handle auto complete not supporting premium users only causing force close ?
return gson.fromJson(response.responseString, FeedResult[].class);
return fromJson(response.responseString, FeedResult[].class);
} else {
return null;
}
@ -703,4 +707,25 @@ public class APIManager {
return (response.responseCode == HttpStatus.SC_OK && !response.hasRedirected);
}
private <T> T fromJson(String json, Class<T> classOfT) throws ServerErrorException {
if(isServerMessage(json)) {
Message errorMessage = gson.fromJson(json, Message.class);
throw new ServerErrorException(errorMessage.message);
}
return gson.fromJson(json, classOfT);
}
private boolean isServerMessage(String json) {
// TODO find a better way to identify these failed responses
boolean isServerMessage = false;
JsonParser parser = new JsonParser();
JsonObject asJsonObject = parser.parse(json).getAsJsonObject();
if(asJsonObject.has("code")) {
JsonElement codeItem = asJsonObject.get("code");
int code = codeItem.getAsInt();
if(code == -1)
isServerMessage = true;
}
return isServerMessage;
}
}

View file

@ -0,0 +1,29 @@
package com.newsblur.network;
public abstract class BaseLoaderResponse {
protected String errorMessage;
protected boolean hasError;
public BaseLoaderResponse() {
}
/**
* Use if the loader had a problem that needs to be communicated back to
* user
*
* @param errorMessage
*/
public BaseLoaderResponse(String errorMessage) {
this.errorMessage = errorMessage;
this.hasError = true;
}
public String getErrorMessage() {
return errorMessage;
}
public boolean hasError() {
return hasError;
}
}

View file

@ -7,7 +7,7 @@ import android.support.v4.content.AsyncTaskLoader;
import com.newsblur.domain.FeedResult;
public class SearchAsyncTaskLoader extends AsyncTaskLoader<ArrayList<FeedResult>> {
public class SearchAsyncTaskLoader extends AsyncTaskLoader<SearchLoaderResponse> {
public static final String SEARCH_TERM = "searchTerm";
@ -21,13 +21,18 @@ public class SearchAsyncTaskLoader extends AsyncTaskLoader<ArrayList<FeedResult>
}
@Override
public ArrayList<FeedResult> loadInBackground() {
ArrayList<FeedResult> list = new ArrayList<FeedResult>();
for (FeedResult result : apiManager.searchForFeed(searchTerm)) {
list.add(result);
public SearchLoaderResponse loadInBackground() {
SearchLoaderResponse response;
try {
ArrayList<FeedResult> list = new ArrayList<FeedResult>();
for (FeedResult result : apiManager.searchForFeed(searchTerm)) {
list.add(result);
}
response = new SearchLoaderResponse(list);
} catch (ServerErrorException ex) {
response = new SearchLoaderResponse(ex.getMessage());
}
return list;
return response;
}
}

View file

@ -0,0 +1,30 @@
package com.newsblur.network;
import java.util.ArrayList;
import com.newsblur.domain.FeedResult;
public class SearchLoaderResponse extends BaseLoaderResponse {
private ArrayList<FeedResult> results;
/**
* Use to indicate there was a problem w/ the search
*
* @param errorMessage
*/
public SearchLoaderResponse(String errorMessage) {
super(errorMessage);
results = new ArrayList<FeedResult>(0);
}
public SearchLoaderResponse(ArrayList<FeedResult> results) {
this.results = results;
}
public ArrayList<FeedResult> getResults() {
return results;
}
}

View file

@ -0,0 +1,8 @@
package com.newsblur.network;
public class ServerErrorException extends Exception {
public ServerErrorException(String errorMessage) {
super(errorMessage);
}
}

View file

@ -0,0 +1,11 @@
package com.newsblur.network.domain;
public class Message {
// {"message": "Overloaded, no autocomplete results.", "code": -1, "authenticated": true, "result": "ok"}
public String message;
public int code;
public boolean authenticated;
public String result;
}