I have a problem with my Android app for video games. The problem occurs when I make a call from static method to OkHttp to browse the game reviews.
When the OkHttp request was in the activity it worked fine, but when I moved it to another class in order to have cleaner code in the activity, the app is working strange.
Firstly, when I click the button to get reviews i get null data, but when I click again I get the data from previous click. If I open second game I get reviews from the first, if I open third game I get reviews from the second etc.
I have the same problem for all the API requests in the app.
Gif url from the strange behaviour:
https://thumbs.gfycat.com/OilyHardtofindDutchsmoushond-size_restricted.gif
Snippet of the static method in the Request class:
public class ReviewsRequests {
private static ArrayList<Review> reviews = new ArrayList<>();
private static Gson gson = new Gson();
public static ArrayList<Review> getReviews(int gameId){
OkHttpClient client = new OkHttpClient();
String bodyString = "fields *; where game = " + gameId + ";";
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
RequestBody requestBody = RequestBody.create(bodyString, JSON);
Request request = new Request.Builder()
.url("https://api-v3.igdb.com/private/reviews")
.addHeader("user-key", Helper.API_KEY)
.post(requestBody)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(#NotNull Call call, #NotNull IOException e) {
}
#Override
public void onResponse(#NotNull Call call, #NotNull Response response) throws IOException {
if (response.isSuccessful()) {
String jsonString = response.body().string();
Type listType = new TypeToken<ArrayList<Review>>(){}.getType();
reviews = gson.fromJson(jsonString, listType);
}
}
});
return reviews;
}
}
And this is the activity when I show the reviews in the recycler view:
public class ReviewsActivity extends AppCompatActivity {
ArrayList<Review> reviews = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_reviews);
Toolbar toolbar = findViewById(R.id.toolbar);
RecyclerView recyclerView = findViewById(R.id.reviews_recycler_view);
TextView noReviewsTV = findViewById(R.id.no_reviews_tv);
int gameId = getIntent().getIntExtra("game_id", 1);
String gameName = getIntent().getStringExtra("game_name");
setSupportActionBar(toolbar);
if(getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(gameName);
}
recyclerView.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false));
ReviewsAdapter adapter = new ReviewsAdapter(this);
recyclerView.setAdapter(adapter);
reviews = ReviewsRequests.getReviews(gameId);
if (reviews.size() != 0) {
adapter.setReviews(reviews);
adapter.notifyDataSetChanged();
} else noReviewsTV.setVisibility(View.VISIBLE);
}
}
You are getting a null value because you are storing the value of "reviews" while making the api call. At that time, the function will return null value for reviews as it might have not got the result from the api. Instead, you just have to call a method of Activity when you get results in the onResponse() method to set the value of "reviews".
Related
I am working on an e-commerce app.
I am using mysql database from siteground and retrieving data using Volley class. The problem is as I am filling any new data in my table, it should also reflect in my fragment as I re-open my fragment, but it is not happening.
I have to uninstall my app and then re-run the android code and then I can see the data updated in my recycler view. I am using String request class in to retrieve data. I don't know what is the problem; is it something that I am not able to close the fragment properly and it is loading the previous data until I don't uninstall it?
This is my fragment.
public class Fragment_Women_Apparels extends Fragment {
private View v;
private RecyclerView recyclerView;
ArrayList<String> id1,name,brand,gender,discount,desc,sellprice,markprice,rating,type,size,category,length,
image1,image2,image3,image4,image5,shop,color,stock,material;
//5cbytcuv57x4
ProgressBar progressBar;
Animation animation;
public Fragment_Women_Apparels() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.fragment_women__apparels_, container, false);
progressBar=v.findViewById(R.id.progress);
animation= AnimationUtils.loadAnimation(getActivity(),R.anim.rotate);
progressBar.startAnimation(animation);
id1=new ArrayList<>();
name=new ArrayList<>();
brand=new ArrayList<>();
gender=new ArrayList<>();
discount=new ArrayList<>();
desc=new ArrayList<>();
sellprice=new ArrayList<>();
markprice=new ArrayList<>();
rating=new ArrayList<>();
type=new ArrayList<>();
size=new ArrayList<>();
category=new ArrayList<>();
length=new ArrayList<>();
image1=new ArrayList<>();
image2=new ArrayList<>();
image3=new ArrayList<>();
image4=new ArrayList<>();
image5=new ArrayList<>();
shop=new ArrayList<>();
color=new ArrayList<>();
stock=new ArrayList<>();
material=new ArrayList<>();
recyclerView=v.findViewById(R.id.recycler);
// recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(),2,RecyclerView.VERTICAL,false);
recyclerView.setLayoutManager(gridLayoutManager); // set LayoutManager to RecyclerView
RequestQueue rq = Volley.newRequestQueue(getActivity());
String url = "-------------------MY-----API-----------------------";
StringRequest sr= new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jo = new JSONObject(response);
JSONArray ja = jo.getJSONArray("result");
for(int i =0;i<ja.length();i++)
{
JSONObject jo1 = ja.getJSONObject(i);
String ID=jo1.getString("ID");
String NAME=jo1.getString("NAME");
String BRAND=jo1.getString("BRAND");
String GENDER=jo1.getString("GENDER");
String DISCOUNT=jo1.getString("DISCOUNT");
String DESC=jo1.getString("DESCRIPTION");
String SELLPRICE=jo1.getString("SELLPRICE");
String MARKPRICE=jo1.getString("MARKPRICE");
String RATING=jo1.getString("RATING");
String TYPE=jo1.getString("TYPE");
String SIZE=jo1.getString("SIZE");
String CATEGORY=jo1.getString("CATEGORY");
String LENGTH=jo1.getString("LENGTH");
String IMAGE1=jo1.getString("IMAGE1");
String IMAGE2=jo1.getString("IMAGE2");
String IMAGE3=jo1.getString("IMAGE3");
String IMAGE4=jo1.getString("IMAGE4");
String IMAGE5=jo1.getString("IMAGE5");
String SHOP=jo1.getString("SHOP");
String COLOR=jo1.getString("COLOR");
String STOCK=jo1.getString("STOCK");
String MATERIAL=jo1.getString("MATERIAL");
id1.add(ID);
name.add(NAME);
brand.add(BRAND);
gender.add(GENDER);
discount.add(DISCOUNT);
desc.add(DESC);
sellprice.add(SELLPRICE);
markprice.add(MARKPRICE);
rating.add(RATING);
type.add(TYPE);
size.add(SIZE);
category.add(CATEGORY);
length.add(LENGTH);
image1.add(IMAGE1);
image2.add(IMAGE2);
image3.add(IMAGE3);
image4.add(IMAGE4);
image5.add(IMAGE5);
shop.add(SHOP);
color.add(COLOR);
stock.add(STOCK);
material.add(MATERIAL);
}
Log.d("abcde",id1.get(0));
progressBar.clearAnimation();
progressBar.setVisibility(View.INVISIBLE);
} catch (JSONException e) {
e.printStackTrace();
}
recyclerView.setAdapter(new RecyclerAdapter(getActivity(),id1,name,brand,gender,discount,desc,sellprice,markprice,
rating,type,size,category,length,image1,image2,image3,image4,image5,shop,color,stock,material));
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
progressBar.clearAnimation();
progressBar.setVisibility(View.INVISIBLE);
Toast.makeText(getActivity(),"Please check your internet connection...",Toast.LENGTH_LONG).show();
}
});
rq.add(sr);
return v;
}
}
I am receiving each element of JSONArray in an ArrayList and then passing the ArrayList in recyclerView.
The question is if I reload this fragment this should show the updated data in database but it is not happening
Finally I got the solution... The problem was that i was using Volley library which has a feature of caching enable by default.... So whenever I updated my database things were not reflected on the UI because of the cache that was saved for that particular API... So every time i had to clear the app cache to see the changes from database...
The solution is before adding the StringRequest to RequestQueue disable the caching feature by using the function of StringRequest class
sr.setShouldCache(false) ;
rq.add(sr) ;
where sr and rq are the objects of StringRequest and RequestQueue classes...
I am making a basic app that just reads RSS files from google and displays the headlines in a listview. The problem I am having is that the static ArrayList I am using in an IntentService is empty when I access it after I start the intent for the service. There could be something very basic I am missing here but tit used to work before I added more RSS links to the service. I tried commenting them out to see if there was some sort of overloading somewhere but nothing changed, which I guess means that I changed something else without realizing or remembering it.
Here is my relavent code, the ArrayList I am trying to access is the newsList variable in RSSsearcher. In the past I have logged the string values of the arraylist and confirmed that it was being populated in the RSSsearcher class, but empty in the MainActivity class.
Relevant code:
RSSsearcher:
public class RSSsearcher extends IntentService {
public static ArrayList<NewsCard> newsList = new ArrayList<>();
private static String TAG = "RSS";
public RSSsearcher() {
super("RSSsearcher");
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
parseNewsLists();
Log.i(TAG,"newsList in onHandleIntent" + newsList);
}
public static ArrayList<NewsCard> getNewsCards() {
return newsList;
}
//helper method to create all the RSSfeed objects
private void parseNewsLists() {
Log.i(TAG, "the service has been started");
//Creating the RSS feed objects
RSSfeed topStories = new RSSfeed("https://news.google.com/news?cf=all&hl=en&pz=1&ned=us&output=rss");
RSSfeed worldNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/WORLD?ned=us&hl=en");
RSSfeed usNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/NATION?ned=us&hl=en");
RSSfeed buisnessNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/BUSINESS?ned=us&hl=en");
RSSfeed technologyNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/TECHNOLOGY?ned=us&hl=en");
RSSfeed entertainmentNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/ENTERTAINMENT?ned=us&hl=en");
RSSfeed sportsNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/SPORTS?ned=us&hl=en");
RSSfeed scienceNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/SCIENCE?ned=us&hl=en");
RSSfeed healthNews = new RSSfeed("https://news.google.com/news/rss/headlines/section/topic/HEALTH?ned=us&hl=en");
try {
//getting RSS feeds
topStories.FileReader();
worldNews.FileReader();
usNews.FileReader();
buisnessNews.FileReader();
technologyNews.FileReader();
entertainmentNews.FileReader();
sportsNews.FileReader();
scienceNews.FileReader();
healthNews.FileReader();
} catch (Exception e) {
Log.i(TAG, Log.getStackTraceString(e));
}
//adding stories to main
newsList.addAll(topStories.getNews());
newsList.addAll(worldNews.getNews());
newsList.addAll(usNews.getNews());
newsList.addAll(buisnessNews.getNews());
newsList.addAll(technologyNews.getNews());
newsList.addAll(entertainmentNews.getNews());
newsList.addAll(sportsNews.getNews());
newsList.addAll(scienceNews.getNews());
newsList.addAll(healthNews.getNews());
}
}
MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//TODO remove and have actual tags show up
TagCard onecard = new TagCard("TestCard");
TagCard twocard = new TagCard("TestCard2");
dummyTags.add(onecard);
dummyTags.add(twocard);
mainListView = (ListView) findViewById(R.id.main_content_list);
drawerLayout = (DrawerLayout) findViewById(R.id.main_layout);
tagDrawerList = (ListView) findViewById(R.id.tag_drawer);
//setting an intent for the RSSsearcher to fetch the news
//TODO make this happen every 15 minutes or so
Intent intent = new Intent(this, RSSsearcher.class);
startService(intent);
NewsCard card = new NewsCard("Testing", "linkeroni");
//adding all the NewsCard objects to this classes newsList
newsList.addAll(RSSsearcher.getNewsCards());
MainAdapter adapter = new MainAdapter(this, newsList);
mainListView.setAdapter(adapter);
Log.i(TAG, "This is the array from main activity" + newsList.toString());
actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.open_drawer, R.string.close_drawer){
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
getActionBar().setTitle("Closed");
}
public void onDrawerOpened(View view){
super.onDrawerOpened(view);
getActionBar().setTitle("Open");
}
};
//TODO removed dummytags and add actual tag implementation
tagDrawerList.setAdapter(new TagAdapter(this,dummyTags));
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
}
Thank you in advance!
I think that when you call
newsList.addAll(RSSsearcher.getNewsCards());
The intent is still in execution
I've searched all the posts I can find, and none seem to help with my situation. I have an android project that uses web services to pull down hourly weather data and populate a listView with the results.
The weird problem I'm having is that when I debug the project on my android phone, the main activity is blank and the listView isn't populated. If I run the project from android studio with my phone locked, and then unlock my phone the app opens on my phone with all of the listView properly formatted and populated.
I feel like it's a race condition issue between the asynctask and the adapter, but I can't seem to resolve it. I tried making my asyncTask an inner private class and calling notifyDataSetChanged on the adapter inside the onPostExecute method, but to no avail. I feel it must be something simple, but I'm relatively new to Android dev, so I'm stuck.
I have three classes that I'll post the pertinent code from
MainActivity.java (onCreate)
public class MainActivity extends ActionBarActivity {
ArrayList<Weather> w = new ArrayList<Weather>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DownloadWeatherTask myTask = new DownloadWeatherTask(w);
WeatherAdapter myAdapter = new WeatherAdapter(this,w);
ListView l = (ListView) findViewById(R.id.weatherList);
l.setAdapter(myAdapter);
myTask.execute();
}
}
WeatherAdapter.java
public class WeatherAdapter extends ArrayAdapter<Weather>{
public WeatherAdapter(Context context, ArrayList<Weather> weather) {
super(context, R.layout.item_weather, weather);
}
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
Weather forecast = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_weather, parent, false);
}
// Lookup view for data population
TextView tvTime = (TextView) convertView.findViewById(R.id.listTime);
TextView tvDescr = (TextView) convertView.findViewById(R.id.listDescr);
TextView tvTemp = (TextView) convertView.findViewById(R.id.listTemp);
TextView tvHumid = (TextView) convertView.findViewById(R.id.listHumid);
ImageView ivWeather = (ImageView) convertView.findViewById(R.id.weatherImg);
// Populate the data into the template view using the data object
tvTime.setText(forecast.time);
tvDescr.setText(forecast.description);
tvTemp.setText(forecast.temperature+"°(F)");
tvHumid.setText(forecast.humidity+"% humidity");
ivWeather.setImageBitmap(forecast.weatherImg);
// Return the completed view to render on screen
return convertView;
}
}
DownloadWeatherTask.java
public class DownloadWeatherTask extends AsyncTask<Void,Void,Void>{
ArrayList<Weather> data;
public DownloadWeatherTask(ArrayList<Weather> a){
data = a;
}
public ArrayList<Weather> getData() {
return data;
}
protected Void doInBackground(Void...params) {
try {
String website = "http://api.wunderground.com/api/1111111111111/geolookup/q/autoip.json";
URL site = new URL(website);
HttpURLConnection weatherUnderground = (HttpURLConnection) site.openConnection();
weatherUnderground.connect();
JsonParser weatherParser = new com.google.gson.JsonParser();
JsonElement weatherJson = weatherParser.parse(new InputStreamReader((InputStream) weatherUnderground.getContent()));
JsonObject weatherObj = weatherJson.getAsJsonObject();
String zip = weatherObj.get("location").getAsJsonObject().get("zip").getAsString();
String city = weatherObj.get("location").getAsJsonObject().get("city").getAsString();
String state = weatherObj.get("location").getAsJsonObject().get("state").getAsString();
String hourly = "http://api.wunderground.com/api/111111111111/hourly/q/" + state + "/" + city + ".json";
URL hourlySite = new URL(hourly);
HttpURLConnection hourlyConnection = (HttpURLConnection) hourlySite.openConnection();
hourlyConnection.connect();
com.google.gson.JsonParser hourlyParser = new com.google.gson.JsonParser();
JsonElement hourlyWeatherJson = weatherParser.parse(new InputStreamReader((InputStream) hourlyConnection.getContent()));
JsonArray weatherArr = hourlyWeatherJson.getAsJsonObject().get("hourly_forecast").getAsJsonArray();
int l = weatherArr.size();
for (int i = 0; i < l; i++) {
String date = weatherArr.get(i).getAsJsonObject().get("FCTTIME").getAsJsonObject().get("pretty").getAsString();
String temp = weatherArr.get(i).getAsJsonObject().get("temp").getAsJsonObject().get("english").getAsString();
String condition = weatherArr.get(i).getAsJsonObject().get("condition").getAsString();
String humidity = weatherArr.get(i).getAsJsonObject().get("humidity").getAsString();
String iconUrl = weatherArr.get(i).getAsJsonObject().get("icon_url").getAsString();
Bitmap icon = getBitmapFromURL(iconUrl);
data.add(new Weather(date, condition, temp, humidity, icon));
}
} catch (IOException e) {
Log.e("Error: ",e.toString());
}
return null;
}
protected void onPostExecute(Void...params){
}
}
Below are links to my screenshots showing the app not populating the listView, and the app working properly when the program is run while the phone is initially locked.
Any help would be greatly appreciated!!
Thanks
In postExecute(), you need to update the adapter's List and then invoke its notifyDataSetChanged method. I suspect that you were forgetting to update the adapter's data.
The other option is to create a new adapter with the new data, and set the new adapter on the ListView.
I figured out what the issue was! I hadn't added #Override to my onPostExecute() method so it was never being called.
I added the notifyDataSetChanged to my onPostExecute as suggested, which worked once I added the #override to my method.
I am building an mobile app in where a user logs in and it outputs the contents of my database table which is named "announcements".
What I'm trying to do is to filter out these output based on the "department" column from the "accounts" table in which the users are stored.
The "announcements" table has the column named "receiver".
The contents will only show if the "department" column of the user logged in has the same value as the "receiver column" of the "announcements" column or if the value of the receiver is "all".
How do I do this?
My PHP script
<?php
$host="localhost"; //replace with database hostname
$username="root"; //replace with database username
$password=""; //replace with database password
$db_name="sunshinedb"; //replace with database name
$con=mysql_connect("$host", "$username", "$password")or die("cannot connect");
mysql_select_db("$db_name")or die("cannot select DB");
$sql = "select * from announcement";
$result = mysql_query($sql);
$json = array();
if(mysql_num_rows($result)){
while($row=mysql_fetch_assoc($result)){
$json['services'][]=$row;
}
}
mysql_close($con);
echo json_encode($json);
?>
Java class
JSONObject jsonobject;
JSONArray jsonarray;
ListView listview;
ArrayList<HashMap<String, String>> arraylist;
ProgressDialog mProgressDialog;
JSONParser jsonParser = new JSONParser();
String email;
String[] services;
private String url = "http://10.0.3.2/sunshine-ems/services.php";
String user_id;
// ALL JSON node names
private static final String TAG_TRANS_ID = "announcement_id";
private static final String TAG_DATE = "date";
private static final String TAG_SERVICES = "title";
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.videos_layout);
// get listview
ListView lv = getListView();
lv.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View view, int arg2,
long arg3) {
Intent i = new Intent(getApplicationContext(),
Single_List.class);
String transaction_id = ((TextView) view
.findViewById(R.id.transac_id)).getText().toString();
i.putExtra("announcement_id", transaction_id);
startActivity(i);
}
});
new DownloadJSON().execute();
}
// DownloadJSON AsyncTask
private class DownloadJSON extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Create a progressdialog
mProgressDialog = new ProgressDialog(VideosActivity.this);
// Set progressdialog title
mProgressDialog.setTitle("Loading Services");
// Set progressdialog message
mProgressDialog.setMessage("Loading...");
mProgressDialog.setIndeterminate(false);
// Show progressdialog
mProgressDialog.show();
}
#Override
protected String doInBackground(String... params) {
JSONObject json = JSONfunctions.getJSONfromURL(url);
// Check your log cat for JSON reponse
Log.d("Service history ", json.toString());
// Create the array
arraylist = new ArrayList<HashMap<String, String>>();
try {
// Locate the array name
jsonarray = json.getJSONArray("services");
for (int i = 0; i < jsonarray.length(); i++) {
HashMap<String, String> map = new HashMap<String, String>();
json = jsonarray.getJSONObject(i);
String transac_id = json.getString(TAG_TRANS_ID);
String date = json.getString(TAG_DATE);
String service = json.getString(TAG_SERVICES);
// Retrive JSON Objects
map.put(TAG_SERVICES, service);
map.put(TAG_DATE, date);
map.put(TAG_TRANS_ID, transac_id);
// Set the JSON Objects into the array
arraylist.add(map);
}
} catch (JSONException e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String file_url) {
mProgressDialog.dismiss();
// updating UI from Background Thread
runOnUiThread(new Runnable() {
public void run() {
/**
* Updating parsed JSON data into ListView
* */
ListAdapter adapter = new SimpleAdapter(
VideosActivity.this, arraylist,
R.layout.listview_services, new String[] {
TAG_TRANS_ID, TAG_SERVICES, TAG_DATE },
new int[] { R.id.transac_id, R.id.txt_service,
R.id.txt_date });
// updating listview
setListAdapter(adapter);
}
});
}
}
You are not making any filtering anywhere in your code...
The steps to do it should be these ones (in this order) :
Android side : Calling your webservice (PHP code) with the user's department (in GET or POST parameter)
WS side : Requesting your database with something like SELECT * FROM announcement WHERE receiver = '<department'> OR receiver = 'ALL' where department is the user's department
WS side : Construct the JSON response
Android side : Process the JSON response to display results
The advantages of making it like this :
Limit the number of data transfered (limit network consumption on the Android device and you limit the load on your PHP server)
Limit the number of data processed Android side (limit the load of the Android app : it's not a desktop app ! Never forgive it !)
PS : reading your post and your comment, I really think you should look into these points before starting to make your app : SQL request, PHP MySQL access (as pointed out by #Jay Blanchard), Web services and HTTP protocol, Android AsyncTask
While I would like to make everything programatically whenever I can, and leave XML blank, that is not possible where I work (designers will not work with raw program code...)
So, to that extend, almost every one of my activity that I work with or built contains a large block of findViewById at the start somewhere.
This is especially painful if I had to create it from scratch and I am now allowed to programatically create an array of buttons and add it to the layout... Thankfully they will let me do that if it gets to 10+ elements and they are all the same type.
Is there a way to avoid this? Or a way to make it automatically cast it into what I am assigning it to? So I don't need to type Button mButton = (Button) findview...
If there is some way to automagically generate java instances of buttons and what nots from the XML given the layout that would be great (esp if the names were nice and autocompleteable).
Try to use Android annotations
AndroidAnnotations is an Open Source framework that speeds up Android development. It takes care of the plumbing, and lets you concentrate on what's really important. By simplifying your code, it facilitates its maintenance.
Here is a simple example of how your code can dramatically shrink, and become much easier to understand:
Before Android Annotations
public class BookmarksToClipboardActivity extends Activity {
BookmarkAdapter adapter;
ListView bookmarkList;
EditText search;
BookmarkApplication application;
Animation fadeIn;
ClipboardManager clipboardManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN);
setContentView(R.layout.bookmarks);
bookmarkList = (ListView) findViewById(R.id.bookmarkList);
search = (EditText) findViewById(R.id.search);
application = (BookmarkApplication) getApplication();
fadeIn = AnimationUtils.loadAnimation(this, anim.fade_in);
clipboardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
View updateBookmarksButton1 = findViewById(R.id.updateBookmarksButton1);
updateBookmarksButton1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
updateBookmarksClicked();
}
});
View updateBookmarksButton2 = findViewById(R.id.updateBookmarksButton2);
updateBookmarksButton2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
updateBookmarksClicked();
}
});
bookmarkList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView p, View v, int pos, long id) {
Bookmark selectedBookmark = (Bookmark) p.getAdapter().getItem(pos);
bookmarkListItemClicked(selectedBookmark);
}
});
initBookmarkList();
}
void initBookmarkList() {
adapter = new BookmarkAdapter(this);
bookmarkList.setAdapter(adapter);
}
void updateBookmarksClicked() {
UpdateBookmarksTask task = new UpdateBookmarksTask();
task.execute(search.getText().toString(), application.getUserId());
}
private static final String BOOKMARK_URL = //
"http://www.bookmarks.com/bookmarks/{userId}?search={search}";
class UpdateBookmarksTask extends AsyncTask {
#Override
protected Bookmarks doInBackground(String... params) {
String searchString = params[0];
String userId = params[1];
RestTemplate client = new RestTemplate();
HashMap args = new HashMap();
args.put("search", searchString);
args.put("userId", userId);
HttpHeaders httpHeaders = new HttpHeaders();
HttpEntity request = new HttpEntity(httpHeaders);
ResponseEntity response = client.exchange( //
BOOKMARK_URL, HttpMethod.GET, request, Bookmarks.class, args);
Bookmarks bookmarks = response.getBody();
return bookmarks;
}
#Override
protected void onPostExecute(Bookmarks result) {
adapter.updateBookmarks(result);
bookmarkList.startAnimation(fadeIn);
}
}
void bookmarkListItemClicked(Bookmark selectedBookmark) {
clipboardManager.setText(selectedBookmark.getUrl());
}
}
After:
#NoTitle
#Fullscreen
#EActivity(R.layout.bookmarks)
public class BookmarksToClipboardActivity extends Activity {
BookmarkAdapter adapter;
#ViewById
ListView bookmarkList;
#ViewById
EditText search;
#App
BookmarkApplication application;
#RestService
BookmarkClient restClient;
#AnimationRes
Animation fadeIn;
#SystemService
ClipboardManager clipboardManager;
#AfterViews
void initBookmarkList() {
adapter = new BookmarkAdapter(this);
bookmarkList.setAdapter(adapter);
}
#Click({R.id.updateBookmarksButton1, R.id.updateBookmarksButton2})
void updateBookmarksClicked() {
searchAsync(search.getText().toString(), application.getUserId());
}
#Background
void searchAsync(String searchString, String userId) {
Bookmarks bookmarks = restClient.getBookmarks(searchString, userId);
updateBookmarks(bookmarks);
}
#UiThread
void updateBookmarks(Bookmarks bookmarks) {
adapter.updateBookmarks(bookmarks);
bookmarkList.startAnimation(fadeIn);
}
#ItemClick
void bookmarkListItemClicked(Bookmark selectedBookmark) {
clipboardManager.setText(selectedBookmark.getUrl());
}
}