Java tutorial
package com.metaphyze.hackernewsfrontpage; /* * Copyright (C) 2014 Robert Ryan Brown * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.util.ArrayList; import java.util.Date; import org.json.JSONObject; import android.app.ActionBar; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.graphics.Bitmap; import android.os.Bundle; import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.JsonObjectRequest; import com.android.volley.toolbox.Volley; import com.google.gson.Gson; public class HackerNewsFrontPageActivity extends Activity { private RequestQueue requestQueue = null; private Gson gson = new Gson(); private DrawerLayout drawerLayout; private WebView webView; private ListView drawerList; private ActionBarDrawerToggle drawerToggle; private View loadingView; private TextView location; private String bookFileName; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_hacker_news_front_page); bookFileName = getFilesDir() + File.separator + "bookmarked_posts.js"; drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); drawerList = (ListView) findViewById(R.id.drawer); location = (TextView) findViewById(R.id.location); webView = (WebView) findViewById(R.id.content_frame); webView.getSettings().setJavaScriptEnabled(true); webView.getSettings().setDomStorageEnabled(true); webView.getSettings().setAppCacheEnabled(true); loadingView = findViewById(R.id.loading); ProgressBar progressBar = ((ProgressBar) findViewById(R.id.progress_bar)); progressBar.setIndeterminate(true); drawerList.setAdapter(new HackerNewsAdapter(HackerNewsFrontPageActivity.this, R.layout.post_item, new ArrayList<HackerNewsPost>(), true)); getActionBar().setTitle("Hacker News Front Page (Loading Live Stream...)"); drawerList.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { HackerNewsPost post = (HackerNewsPost) parent.getItemAtPosition(position); webView.loadUrl(post.getUrl()); webView.setWebViewClient(new WebViewClient() { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); loadingView.setVisibility(View.VISIBLE); location.setText("LOADING......" + url); } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); loadingView.setVisibility(View.INVISIBLE); location.setText(url); } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { loadingView.setVisibility(View.INVISIBLE); location.setText("ERROR LOADING PAGE"); view.loadUrl("file:///android_asset/failed_to_load_page.html"); } }); drawerLayout.closeDrawer(drawerList); } }); drawerList.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { final HackerNewsPost clonedPost = ((HackerNewsPost) parent.getItemAtPosition(position)).clone(); clonedPost.setPostedAgo(new Date().toString()); AlertDialog.Builder builder = new AlertDialog.Builder(HackerNewsFrontPageActivity.this); if (((HackerNewsAdapter) parent.getAdapter()).isLive()) { builder.setTitle("Bookmark?"); builder.setMessage("Do you want to bookmark the post\n" + clonedPost.getTitle()); builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { try { HackerNewsFrontPageContents contents = readContentsFromBookmarksFile(); if (contents == null) { showError("ERROR", "Failed to read bookmark file"); dialog.dismiss(); return; } if (!contents.addPost(clonedPost)) { showError("Already Exists", "Not added becasue bookmark already exists"); dialog.dismiss(); return; } if (!saveContentsToBookmarksFile(contents)) { showError("ERROR", "Failed to save bookmark"); dialog.dismiss(); } } catch (Exception ex) { ex.printStackTrace(); showError("ERROR", "Internal error: " + ex); } } }).setNegativeButton("No", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); } else { builder.setTitle("Delete?"); builder.setMessage("Do you want to delete the bookmarked post:\n" + clonedPost.getTitle()); builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { try { HackerNewsFrontPageContents contents = readContentsFromBookmarksFile(); if (contents == null) { showError("ERROR", "Unable to find or generate bookmarks file"); dialog.dismiss(); return; } if (!contents.removePost(clonedPost)) { showError("Not Removed", "Does not exist? How's that possible?"); dialog.dismiss(); return; } if (saveContentsToBookmarksFile(contents)) { if (contents.getItems().size() > 0) { drawerList .setAdapter(new HackerNewsAdapter(HackerNewsFrontPageActivity.this, R.layout.post_item, contents.getItems(), false)); } else { showError("No more bookmarks", "Reverting to live stream"); loadLiveStream(); } } else { showError("ERROR", "Failed to save bookmark deletion"); } dialog.dismiss(); } catch (Exception ex) { ex.printStackTrace(); showError("ERROR", "Internal Error: " + ex); } } }).setNegativeButton("No", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); } builder.setCancelable(true); builder.create().show(); return false; } }); drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.drawable.drawer_icon, 0, 0); drawerLayout.setDrawerListener(drawerToggle); ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); // actionBar.setHomeButtonEnabled(true); requestQueue = Volley.newRequestQueue(this); loadLiveStream(); } private void showError(String title, String error) { AlertDialog.Builder builder = new AlertDialog.Builder(HackerNewsFrontPageActivity.this); builder.setTitle(title); builder.setMessage(error); builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.create().show(); } private HackerNewsFrontPageContents readContentsFromBookmarksFile() { File bookmarksFile = new File(bookFileName); HackerNewsFrontPageContents contents = null; try { if (bookmarksFile.exists()) { contents = gson.fromJson(new FileReader(bookmarksFile), HackerNewsFrontPageContents.class); } else { contents = new HackerNewsFrontPageContents("N/A", "N/A", "N/A"); } return contents; } catch (Exception ex) { ex.printStackTrace(); return null; } } private boolean saveContentsToBookmarksFile(HackerNewsFrontPageContents contents) { String fileContent = gson.toJson(contents); File bookmarksFile = new File(bookFileName); FileOutputStream outputStream; try { outputStream = new FileOutputStream(bookmarksFile); outputStream.write(fileContent.getBytes()); outputStream.close(); return true; } catch (Exception e) { e.printStackTrace(); return false; } } private void loadLiveStream() { JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.GET, "http://api.ihackernews.com/page", null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { try { String responseText = response.toString(); HackerNewsFrontPageContents reply = gson.fromJson(responseText, HackerNewsFrontPageContents.class); drawerList.setAdapter(new HackerNewsAdapter(HackerNewsFrontPageActivity.this, R.layout.post_item, reply.getItems(), true)); getActionBar().setTitle("Hacker News Front Page (Live)"); drawerLayout.openDrawer(GravityCompat.START); } catch (Exception ex) { ex.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { showError("Error loading live feed", "There was a problem contacting the site"); getActionBar().setTitle("Hacker News Front Page (ERROR LOADING Live Stream)"); } }); requestQueue.cancelAll(null); requestQueue.add(jsObjRequest); } private void loadBookmarks() { try { HackerNewsFrontPageContents contents = readContentsFromBookmarksFile(); if (contents == null) { showError("ERROR", "Error laoding bookmark file. Returning to live stream."); loadLiveStream(); return; } if (contents.getItems().size() == 0) { showError("No Bookmarks", "Returning to live stream."); loadLiveStream(); return; } drawerList.setAdapter(new HackerNewsAdapter(HackerNewsFrontPageActivity.this, R.layout.post_item, contents.getItems(), false)); getActionBar().setTitle("Bookmarks"); drawerLayout.openDrawer(GravityCompat.START); } catch (Exception ex) { File bookmarksFile = new File(bookFileName); if (!bookmarksFile.exists()) { showError("No Bookmarks Yet", "Returning to Live Stream"); loadLiveStream(); } else { ex.printStackTrace(); showError("ERROR", "Error loading bookmarks file: " + ex); drawerList.setAdapter(new HackerNewsAdapter(HackerNewsFrontPageActivity.this, R.layout.post_item, new ArrayList<HackerNewsPost>(), false)); getActionBar().setTitle("Bookmarks (Error Loading Bookmarks)"); drawerLayout.openDrawer(GravityCompat.START); } } } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); drawerToggle.syncState(); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if (drawerToggle.onOptionsItemSelected(item)) { return true; } switch (item.getItemId()) { case R.id.live_stream: loadLiveStream(); break; case R.id.archived_items: loadBookmarks(); break; } return super.onOptionsItemSelected(item); } }