2016年6月9日 星期四

App Engine Java Endpoints

App Engine Java Endpoints
Udacity project 3 ,after second revision



in this project still have some bug

Bug1:in the ona plan mode, when rotate the phone ,always will crash

reson:Because in the book detail fragment,when it rotate,the fragment lifecycle will run again,the onCreateView method will start the Loader,however, the Loader nay be finish the onCreateOptionsMenu,at that time, the shareActionProvider vairable is null at that time, so, when execute shareActionProvider.setShareIntent(shareIntent) at onLoadFinished will have error.

soultion:start the loader after shareActionProvider = (ShareActionProvider)
MenuItemCompat.getActionProvider(menuItem);


package it.jaschke.alexandria;

import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.ShareActionProvider;
import android.util.Log;
import android.util.Patterns;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import it.jaschke.alexandria.data.AlexandriaContract;
import it.jaschke.alexandria.services.BookService;
import it.jaschke.alexandria.services.DownloadImage;


public class BookDetail extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {

   public static final String EAN_KEY = "EAN";
   private final int LOADER_ID = 10;
   private View rootView;
   private String ean;
   private String bookTitle;
   private ShareActionProvider shareActionProvider;

   public BookDetail() {
   }

   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setHasOptionsMenu(true);
   }


   @Override
   public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       Log.d("BookDetail","onCreateView");

       Bundle arguments = getArguments();
       if (arguments != null) {
           ean = arguments.getString(BookDetail.EAN_KEY);
//            getLoaderManager().restartLoader(LOADER_ID, null, this);
       }

       rootView = inflater.inflate(R.layout.fragment_full_book, container, false);
       rootView.findViewById(R.id.delete_button).setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               Intent bookIntent = new Intent(getActivity(), BookService.class);
               bookIntent.putExtra(BookService.EAN, ean);
               bookIntent.setAction(BookService.DELETE_BOOK);
               getActivity().startService(bookIntent);
               getActivity().getSupportFragmentManager().popBackStack();
           }
       });
       return rootView;
   }


   @Override
   public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

       Log.d("BookDetail","onCreateOptionsMenu");
       inflater.inflate(R.menu.book_detail, menu);

       MenuItem menuItem = menu.findItem(R.id.action_share);
       shareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(menuItem);


       Bundle arguments = getArguments();
       if (arguments != null) {
//            ean = arguments.getString(BookDetail.EAN_KEY);
           getLoaderManager().restartLoader(LOADER_ID, null, this);
       }
   }

   @Override
   public android.support.v4.content.Loader<Cursor> onCreateLoader(int id, Bundle args) {
       return new CursorLoader(
               getActivity(),
               AlexandriaContract.BookEntry.buildFullBookUri(Long.parseLong(ean)),
               null,
               null,
               null,
               null
       );
   }

   @Override
   public void onLoadFinished(android.support.v4.content.Loader<Cursor> loader, Cursor data) {
       if (!data.moveToFirst()) {
           return;
       }

       bookTitle = data.getString(data.getColumnIndex(AlexandriaContract.BookEntry.TITLE));
       ((TextView) rootView.findViewById(R.id.fullBookTitle)).setText(bookTitle);

       Intent shareIntent = new Intent(Intent.ACTION_SEND);
       shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
       shareIntent.setType("text/plain");
       shareIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_text) + bookTitle);
       shareActionProvider.setShareIntent(shareIntent);

       String bookSubTitle = data.getString(data.getColumnIndex(AlexandriaContract.BookEntry.SUBTITLE));
       ((TextView) rootView.findViewById(R.id.fullBookSubTitle)).setText(bookSubTitle);

       String desc = data.getString(data.getColumnIndex(AlexandriaContract.BookEntry.DESC));
       ((TextView) rootView.findViewById(R.id.fullBookDesc)).setText(desc);

       String authors = data.getString(data.getColumnIndex(AlexandriaContract.AuthorEntry.AUTHOR));
       String[] authorsArr = null;
       if (authors == null) {
           authorsArr = new String[0];
       } else {
           authorsArr = authors.split(",");
       }

       ((TextView) rootView.findViewById(R.id.authors)).setLines(authorsArr.length);
       ((TextView) rootView.findViewById(R.id.authors)).setText(authors.replace(",", "\n"));
       String imgUrl = data.getString(data.getColumnIndex(AlexandriaContract.BookEntry.IMAGE_URL));
       if (Patterns.WEB_URL.matcher(imgUrl).matches()) {
           new DownloadImage((ImageView) rootView.findViewById(R.id.fullBookCover)).execute(imgUrl);
           rootView.findViewById(R.id.fullBookCover).setVisibility(View.VISIBLE);
       }

       String categories = data.getString(data.getColumnIndex(AlexandriaContract.CategoryEntry.CATEGORY));
       ((TextView) rootView.findViewById(R.id.categories)).setText(categories);

       if (rootView.findViewById(R.id.right_container) != null) {
           rootView.findViewById(R.id.backButton).setVisibility(View.INVISIBLE);
       }

   }

   @Override
   public void onLoaderReset(android.support.v4.content.Loader<Cursor> loader) {

   }

   @Override
   public void onPause() {
       super.onDestroyView();
       if (MainActivity.IS_TABLET && rootView.findViewById(R.id.right_container) == null) {
           getActivity().getSupportFragmentManager().popBackStack();
       }
   }
}


Bug2:search a book when the authorisempty(null) ,Book detail and add Book fragment also have the same problem
reson:because the string author=null
authors.replace(",", "\n") will error

soultion: String authors = data.getString(data.getColumnIndex(AlexandriaContract.AuthorEntry.AUTHOR));
       String[] authorsArr = null;
       if (authors == null) {
           authorsArr = new String[0];
       } else {
           authorsArr = authors.split(",");
           ((TextView) rootView.findViewById(R.id.authors)).setLines(authorsArr.length);
           ((TextView) rootView.findViewById(R.id.authors)).setText(authors.replace(",", "\n"));
       }

package it.jaschke.alexandria;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.util.Patterns;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import it.jaschke.alexandria.data.AlexandriaContract;
import it.jaschke.alexandria.services.BookService;
import it.jaschke.alexandria.services.DownloadImage;


public class AddBook extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
   public static final String BRODCAST_ACTION = "it.jaschke.alexandria.brodcastmessage";
   private static final String TAG = "INTENT_TO_SCAN_ACTIVITY";
   private static final String SCAN_FORMAT = "scanFormat";
   private static final String SCAN_CONTENTS = "scanContents";
   private final int LOADER_ID = 1;
   private final int BARCODE_SCANNER_REQUEST_CODE = 174;
   private final String EAN_CONTENT = "eanContent";
   private EditText ean;
   private View rootView;
   private String mScanFormat = "Format:";
   private String mScanContents = "Contents:";
   private Activity activity;


   public AddBook() {
   }

   @Override
   public void onSaveInstanceState(Bundle outState) {
       super.onSaveInstanceState(outState);
       if (ean != null) {
           outState.putString(EAN_CONTENT, ean.getText().toString());
       }
   }

   @Override
   public void onActivityResult(int requestCode, int resultCode, Intent data) {
       super.onActivityResult(requestCode, resultCode, data);
       if (requestCode == BARCODE_SCANNER_REQUEST_CODE) {
           //only for the ZXing app
           if (resultCode == activity.RESULT_OK) {
               String contents = data.getStringExtra("SCAN_RESULT");
               String format = data.getStringExtra("SCAN_RESULT_FORMAT");
               Log.d("onActivityResult", format + " : " + contents);
               ean.setText(contents);
           } else if (resultCode == activity.RESULT_CANCELED) {
               //  Handle cancel
               Toast.makeText(activity, getString(R.string.scan_cancel), Toast.LENGTH_SHORT).show();
           }
       }
   }

   @Override
   public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

       rootView = inflater.inflate(R.layout.fragment_add_book, container, false);
       ean = (EditText) rootView.findViewById(R.id.ean);
       if (savedInstanceState != null) {
           ean.setText(savedInstanceState.getString(EAN_CONTENT));
       }

       ean.addTextChangedListener(new TextWatcher() {
           @Override
           public void beforeTextChanged(CharSequence s, int start, int count, int after) {
               //no need
           }

           @Override
           public void onTextChanged(CharSequence s, int start, int before, int count) {
               //no need
           }

           @Override
           public void afterTextChanged(Editable s) {
               String ean = s.toString();
               //catch isbn10 numbers
               if (ean.length() == 10 && !ean.startsWith("978")) {
                   ean = "978" + ean;
               }
               if (ean.length() < 13) {
                   clearFields();
                   return;
               }
               //Once we have an ISBN, start a book intent

               Intent bookIntent = new Intent(getActivity(), BookService.class);
               bookIntent.putExtra(BookService.EAN, ean);
               bookIntent.setAction(BookService.FETCH_BOOK);
               //register the brodcast receiver
               MyBrodcastReceiver mybrodcastReceiver = new MyBrodcastReceiver();
               IntentFilter intentFilter = new IntentFilter(BRODCAST_ACTION);
               getActivity().registerReceiver(mybrodcastReceiver, intentFilter);
               //
               getActivity().startService(bookIntent);

           }
       });

       rootView.findViewById(R.id.scan_button).setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               // This is the callback method that the system will invoke when your button is
               // clicked. You might do this by launching another app or by including the
               //functionality directly in this app.
               // Hint: Use a Try/Catch block to handle the Intent dispatch gracefully, if you
               // are using an external app.
               //when you're done, remove the toast below.
               activity = getActivity();
//                CharSequence text = "This button should let you scan a book for its barcode!";
//                int duration = Toast.LENGTH_SHORT;
//
//                Toast toast = Toast.makeText(context, text, duration);
//                toast.show();

               try {
                   Intent intent = new Intent("com.google.zxing.client.android.SCAN");
                   intent.setPackage("com.google.zxing.client.android");
                   intent.putExtra("SCAN_MODE", "QR_CODE_MODE");
                   startActivityForResult(intent, BARCODE_SCANNER_REQUEST_CODE);
               } catch (Exception e) {
//                    not install the zxing
//                    go to the market download
                   startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + "com.google.zxing.client.android")));

               }

           }
       });


       rootView.findViewById(R.id.save_button).setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               ean.setText("");
           }
       });

       rootView.findViewById(R.id.delete_button).setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               Intent bookIntent = new Intent(getActivity(), BookService.class);
               bookIntent.putExtra(BookService.EAN, ean.getText().toString());
               bookIntent.setAction(BookService.DELETE_BOOK);
               getActivity().startService(bookIntent);
               ean.setText("");
           }
       });

       if (savedInstanceState != null) {
           ean.setText(savedInstanceState.getString(EAN_CONTENT));
           ean.setHint("");
       }

       return rootView;
   }

   private void restartLoader() {
       getLoaderManager().restartLoader(LOADER_ID, null, this);
   }

   @Override
   public android.support.v4.content.Loader<Cursor> onCreateLoader(int id, Bundle args) {
       if (ean.getText().length() == 0) {
           return null;
       }
       String eanStr = ean.getText().toString();
       if (eanStr.length() == 10 && !eanStr.startsWith("978")) {
           eanStr = "978" + eanStr;
       }
       return new CursorLoader(
               getActivity(),
               AlexandriaContract.BookEntry.buildFullBookUri(Long.parseLong(eanStr)),
               null,
               null,
               null,
               null
       );
   }

   @Override
   public void onLoadFinished(android.support.v4.content.Loader<Cursor> loader, Cursor data) {
       if (!data.moveToFirst()) {
           return;
       }

       String bookTitle = data.getString(data.getColumnIndex(AlexandriaContract.BookEntry.TITLE));
       ((TextView) rootView.findViewById(R.id.bookTitle)).setText(bookTitle);

       String bookSubTitle = data.getString(data.getColumnIndex(AlexandriaContract.BookEntry.SUBTITLE));
       ((TextView) rootView.findViewById(R.id.bookSubTitle)).setText(bookSubTitle);

       String authors = data.getString(data.getColumnIndex(AlexandriaContract.AuthorEntry.AUTHOR));
       String[] authorsArr = null;
       if (authors == null) {
           authorsArr = new String[0];
       } else {
           authorsArr = authors.split(",");
           ((TextView) rootView.findViewById(R.id.authors)).setLines(authorsArr.length);
           ((TextView) rootView.findViewById(R.id.authors)).setText(authors.replace(",", "\n"));
       }


       String imgUrl = data.getString(data.getColumnIndex(AlexandriaContract.BookEntry.IMAGE_URL));
       if (Patterns.WEB_URL.matcher(imgUrl).matches()) {
           new DownloadImage((ImageView) rootView.findViewById(R.id.bookCover)).execute(imgUrl);
           rootView.findViewById(R.id.bookCover).setVisibility(View.VISIBLE);
       }

       String categories = data.getString(data.getColumnIndex(AlexandriaContract.CategoryEntry.CATEGORY));
       ((TextView) rootView.findViewById(R.id.categories)).setText(categories);

       rootView.findViewById(R.id.save_button).setVisibility(View.VISIBLE);
       rootView.findViewById(R.id.delete_button).setVisibility(View.VISIBLE);
   }

   @Override
   public void onLoaderReset(android.support.v4.content.Loader<Cursor> loader) {

   }

   private void clearFields() {
       ((TextView) rootView.findViewById(R.id.bookTitle)).setText("");
       ((TextView) rootView.findViewById(R.id.bookSubTitle)).setText("");
       ((TextView) rootView.findViewById(R.id.authors)).setText("");
       ((TextView) rootView.findViewById(R.id.categories)).setText("");
       rootView.findViewById(R.id.bookCover).setVisibility(View.INVISIBLE);
       rootView.findViewById(R.id.save_button).setVisibility(View.INVISIBLE);
       rootView.findViewById(R.id.delete_button).setVisibility(View.INVISIBLE);
   }

   @Override
   public void onAttach(Activity activity) {
       super.onAttach(activity);
       activity.setTitle(R.string.scan);
   }

   private class MyBrodcastReceiver extends BroadcastReceiver {
       @Override
       public void onReceive(Context context, Intent intent) {
           //when receive the message(Service finish),start the Cursor Loader.
           AddBook.this.restartLoader();
       }
   }
}




problem3:the custome back button
Remove any custom back buttons as per Android Guidelines :