-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add items from DD API feed #1
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,70 @@ | ||
package org.novinger.jason.demoreader; | ||
|
||
import android.os.StrictMode; | ||
import android.support.v7.app.AppCompatActivity; | ||
import android.os.Bundle; | ||
import android.util.Log; | ||
import android.view.Menu; | ||
import android.view.MenuItem; | ||
import android.view.View; | ||
import android.view.ViewPropertyAnimator; | ||
import android.widget.AdapterView; | ||
import android.widget.ArrayAdapter; | ||
import android.widget.ListView; | ||
|
||
import com.google.gson.Gson; | ||
|
||
import org.novinger.jason.demoreader.datamodels.Article; | ||
|
||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
|
||
import okhttp3.OkHttpClient; | ||
import okhttp3.Request; | ||
import okhttp3.Response; | ||
|
||
public class ListActivity extends AppCompatActivity { | ||
|
||
private final static int qty = 50; | ||
private final static String feedUrl = "http://www.dailydot.com/api/v1/content/article/"; | ||
|
||
@Override | ||
protected void onCreate(Bundle savedInstanceState) { | ||
super.onCreate(savedInstanceState); | ||
setContentView(R.layout.activity_list); | ||
|
||
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); | ||
StrictMode.setThreadPolicy(policy); | ||
Article[] articles; | ||
try { | ||
articles = getFeedItems(getFeedUrl()); | ||
} catch (IOException ex) { | ||
articles = new Article[0]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so this is technically fine, but FWIW primitive arrays are pretty uncommon nowadays, since they're kind of hard to work with - most people use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I absolutely agree, this is more of a quick "get it to display things" snippet that I expected to come back to at some point. FWIW, it comes from the fact that I'm deserializing an array of JSON objects. I'll see if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it does! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perfect There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sadly it does work when specifying a field on a POJO object, however, it does not work when calling [ I've refactored this into a standalone method as much as possible in a later PR, so punting for now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not sure what you mean here, but will wait and see for now... |
||
Log.d("Exception", ex.toString()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup, that shouldn't even be there anymore. |
||
} | ||
|
||
final ListView listview = (ListView) findViewById(R.id.listview); | ||
String[] values = new String[] { | ||
"Jason", "Cindy", "Hannah", "Leah", "Kirsten", "Matt", "Elle", "Trevor", "Alex", | ||
"Eli", "Danika", "Lori", "Wyatt", "Chad" | ||
}; | ||
final ArrayList<String> list = new ArrayList<String>(); | ||
Collections.addAll(list, values); | ||
final ArrayList<String> list = new ArrayList<>(); | ||
for (Article article : articles) { | ||
list.add(article.toString()); | ||
} | ||
|
||
final ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, list); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so for a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, I just got excited about seeing things on the screen. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. \o/ |
||
listview.setAdapter(adapter); | ||
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() { | ||
@Override | ||
public void onItemClick(AdapterView<?> parent, final View view, int position, long id) { | ||
final String item = (String) parent.getItemAtPosition(position); | ||
view.animate().setDuration(500).alpha(0) | ||
.withEndAction(new Runnable() { | ||
@Override | ||
public void run() { | ||
list.remove(item); | ||
adapter.notifyDataSetChanged(); | ||
view.setAlpha(1); | ||
} | ||
}); | ||
final ViewPropertyAnimator viewPropertyAnimator = view.animate().setDuration(100).alpha(0); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do you understand what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe it's making the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that's technically correct, but that's not why we're using it here. take it out and see what happens. or should i just tell you? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nope, let me play with it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hrm, I wasn't able to discern any difference in behavior. Please correct me if I'm wrong, but since it's just a local variable (on the method), there's no other interesting behavior, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. incorrect! you didn't see any different behavior when interacting with your ListView? |
||
viewPropertyAnimator.withEndAction(new Runnable() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is fine but is super high-level, i think API 19 or 21. i'd say the most reasonable you could go back would be 16, anything after that will exclude too many devices. a nice feature in android docs is you can set the API level, and it'll gray out anything for later APIs There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree and I didn't like it at the time. Partly because I'm not a fan of the chain-able style anymore, but partly because I didn't completely understand what I was doing or why I needed it. Unsurprisingly, that bit came from a tutorial I was looking at as I did it. This is removed in a subsequent PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fwiw you can just set a listener to do the same thing...
something like that ^ which is not exactly right but shows the basic idea... this also brings up a kind of common pattern. so the post back if that doesn't make sense There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah gotcha, that makes sense. |
||
@Override | ||
public void run() { | ||
list.remove(item); | ||
list.trimToSize(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Derp, didn't mean to commit this. Was experimenting, trying to understand why used memory was increasing when a click was handled and an item removed. I'm guessing it has something to do with GC not needing to run and new, anonymous There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, I upped the number of articles to load by default to force a larger allocation and then interacted with the activity to force more usage. As soon as it ran out of memory, it GC'd and was happy again. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can force a GC with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, good to know. I think just having access to the view of memory in use excited me. This is the same behavior I'd expect in Python, I just don't usually work with the tooling to watch memory usage in real time. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah that's exactly when i use System.gc - lets say I'm doing some crazy bitmap manipulations, but i think I'm managing memory correctly - say we're on a modern tablet with a large heap - we decode the bitmap (memory), scale it (memory, memory, memory), then we made a BitmapRegionDecode (because we only want to show a part of it) (MEMORY!!!), then we return the small piece we want to show (memory), then we exit the stack (end of function, as we that all said, even if we do get to reclaim it, there's still heap limits for devices: http://stackoverflow.com/a/9940415/429430, so while we may think "oh this is temporary (on the stack), no problem", if we actually run out of memory before we're done, we'll crash - even if we There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, this is awesome, thanks! I've always wanted to work in more constrained environments. I think this will be a fun challenge at times and a good way to set any app I do apart from others in (from a quality perspective). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agree |
||
adapter.notifyDataSetChanged(); | ||
view.setAlpha(1); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
|
@@ -67,4 +90,22 @@ public boolean onOptionsItemSelected(MenuItem item) { | |
|
||
return super.onOptionsItemSelected(item); | ||
} | ||
|
||
private Article[] getFeedItems(String url) throws IOException { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. again, ref the note above about primitive arrays - they might be appropriate here, and if it's a deliberate choice, +100, but understand the limits vs Personally, I use |
||
OkHttpClient client = new OkHttpClient(); | ||
|
||
Request request = new Request.Builder().url(url).build(); | ||
Response response = client.newCall(request).execute(); | ||
String json = response.body().string(); | ||
Gson gson = new Gson(); | ||
return gson.fromJson(json, Article[].class); | ||
} | ||
|
||
private String getFeedUrl() { | ||
if(qty > 0) { | ||
return feedUrl + "?quantity=" + Integer.toString(qty); | ||
} | ||
|
||
return feedUrl; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package org.novinger.jason.demoreader.datamodels; | ||
|
||
/** | ||
* Created by jason on 4/27/16. | ||
*/ | ||
public class Article { | ||
private String id; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so the convention here is private members use the
What's nice about that too is that the private There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, interesting. I think I misunderstood the |
||
private int realId; | ||
private String headline; | ||
private String slug; | ||
private Author[] authors; | ||
private String summary; | ||
private String url; | ||
|
||
public Article() {} | ||
|
||
public Article(String id, String headline, String slug, Author[] authors, String url, String summary) { | ||
this.id = id; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i personally never use while this guide is for contributors, not just anyone writing android, we used it at the Dot, and we use it at O'Reilly, and i use it personally: https://source.android.com/source/code-style.html There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can also use annotations with Gson for naming styles There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since this is a Gson class i might actually just do what you did... i tend to let Gso POJOs be ugly :/ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That was kind of my thought as well. Is the separate package, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes. i do that too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool, I'll get the private member renamed in a subsequent PR since I've already branched from here (twice, :\ ). |
||
this.realId = mungeId(id); | ||
this.headline = headline; | ||
this.slug = slug; | ||
this.authors = authors; | ||
this.url = url; | ||
this.summary = summary; | ||
} | ||
|
||
private int mungeId(String id) { | ||
String[] parts = id.split("."); | ||
return Integer.parseInt(parts[2]); | ||
} | ||
|
||
public String toString() { | ||
return getHeadline() + " — " + getPrimaryAuthor().getName(); | ||
} | ||
|
||
public int getId() { | ||
return realId; | ||
} | ||
|
||
public String getHeadline() { | ||
return headline; | ||
} | ||
|
||
public String getSlug() { | ||
return slug; | ||
} | ||
|
||
public Author[] getAuthors() { | ||
return authors; | ||
} | ||
|
||
public Author getPrimaryAuthor() { | ||
if (authors.length > 0) { | ||
return authors[0]; | ||
} | ||
|
||
return new Author(); | ||
} | ||
|
||
public String getSummary() { | ||
return summary; | ||
} | ||
|
||
public String getUrl() { | ||
return url; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package org.novinger.jason.demoreader.datamodels; | ||
|
||
/** | ||
* Created by jason on 4/27/16. | ||
*/ | ||
public class ArticleFeed { | ||
private int count; | ||
private String next; | ||
private String previous; | ||
private Article[] results; | ||
|
||
public ArticleFeed() {} | ||
|
||
public ArticleFeed(int count, String next, String previous, Article[] results) { | ||
this.count = count; | ||
this.next = next; | ||
this.previous = previous; | ||
this.results = results; | ||
} | ||
|
||
public Article[] getResults() { | ||
return results; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package org.novinger.jason.demoreader.datamodels; | ||
|
||
/** | ||
* Created by jason on 4/27/16. | ||
*/ | ||
public class Author { | ||
private String name; | ||
private String url; | ||
private String slug; | ||
|
||
public Author() {} | ||
|
||
public Author(String name, String url, String slug) { | ||
this.name = name; | ||
this.url = url; | ||
this.slug = slug; | ||
} | ||
|
||
public String toString() { | ||
return name; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public String getUrl() { | ||
return url; | ||
} | ||
|
||
public String getSlug() { | ||
return slug; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package org.novinger.jason.demoreader.datamodels; | ||
|
||
/** | ||
* Created by jason on 4/27/16. | ||
*/ | ||
public class Headline { | ||
private Boolean headline; | ||
private Boolean title; | ||
private Boolean social; | ||
private String text; | ||
|
||
public Headline() {} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ORLY? I had to Google for this when I was getting exceptions about the network not working. Is there some other way I could have accomplished that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
generally you check network state explicitly... http://developer.android.com/training/monitoring-device-state/connectivity-monitoring.html
the StrictMode stuff will just alert you so i don't think is useful for production