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 :