In my Android application, I am having Barcode scanning functionality. For this functionality I am using Android https://github.com/dm77/barcodescanner library for scanning Barcodes. It is working good, But if I scanned repeatedly in my project, sometimes it is returning a wrong value(not the actual value) of the barcode.I would like to know why it is happening and how to resolve this issue. I have googled but unfortunately I didn't find any better solution.Anyone please guide me to fix the issue.
note: I am using latest version 1.8.4
SimpleScannerActivity.java
import com.google.zxing.Result;
import me.dm7.barcodescanner.core.IViewFinder;
import me.dm7.barcodescanner.core.ViewFinderView;
import me.dm7.barcodescanner.zxing.ZXingScannerView;
public class SimpleScannerActivity extends BaseScannerActivity implements ZXingScannerView.ResultHandler {
private ZXingScannerView mScannerView;
LoadingFlowScreen loadingFlowScreen;
NextScanScreen nextScanScreen;
String shipmentin,locationin;
#Override
public void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.activity_simple_scanner);
setupToolbar();
loadingFlowScreen = new LoadingFlowScreen();
nextScanScreen = new NextScanScreen();
ViewGroup contentFrame = (ViewGroup) findViewById(R.id.content_frame);
mScannerView = new ZXingScannerView(this) {
#Override
protected IViewFinder createViewFinderView(Context context) {
return new CustomViewFinderView(context);
}
};
contentFrame.addView(mScannerView);
}
#Override
public void onResume() {
super.onResume();
mScannerView.setResultHandler(this);
mScannerView.startCamera();
}
#Override
public void onPause() {
super.onPause();
mScannerView.stopCamera();
}
#Override
public void handleResult(Result rawResult) {
Intent in = new Intent(SimpleScannerActivity.this, NextScreen.class);//forwaring to another activity once scanned the barcode
in.putExtra("scannedText",rawResult.getText());//storing the value in prefernce
startActivity(in);
finish();
mScannerView.resumeCameraPreview(SimpleScannerActivity.this);
}
private static class CustomViewFinderView extends ViewFinderView {
public static final String TRADE_MARK_TEXT = "";
public static final int TRADE_MARK_TEXT_SIZE_SP = 40;
public final Paint PAINT = new Paint();
public CustomViewFinderView(Context context) {
super(context);
init();
}
public CustomViewFinderView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
PAINT.setColor(Color.WHITE);
PAINT.setAntiAlias(true);
float textPixelSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
TRADE_MARK_TEXT_SIZE_SP, getResources().getDisplayMetrics());
PAINT.setTextSize(textPixelSize);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawTradeMark(canvas);
}
private void drawTradeMark(Canvas canvas) {
Rect framingRect = getFramingRect();
float tradeMarkTop;
float tradeMarkLeft;
if (framingRect != null) {
tradeMarkTop = framingRect.bottom + PAINT.getTextSize() + 10;
tradeMarkLeft = framingRect.left;
} else {
tradeMarkTop = 10;
tradeMarkLeft = canvas.getHeight() - PAINT.getTextSize() - 10;
}
canvas.drawText(TRADE_MARK_TEXT, tradeMarkLeft, tradeMarkTop, PAINT);
}
}
}
BaseScannerActivity.java
public class BaseScannerActivity extends AppCompatActivity {
public void setupToolbar() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final ActionBar ab = getSupportActionBar();
if(ab != null) {
ab.setDisplayHomeAsUpEnabled(true);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}
I would suggest you to use Zbar (from same repo).
We had some performance issues with Zxing and had to switch to Zbar.
Using in production for like 2 years - no issues.
Related
I am trying to use a custom Item Animator for animating an itemview after clicking a button. After clicking the add button, the new item appear, but the desired animation does not happen. It just appears suddenly. I have tried everything, please help.
viewholder_add_anim
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration = "500"
android:fromXScale="0%"
android:fromYScale="0%"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="100%"
android:toYScale="100%"/>
</set>
CustomItemAnimator
import android.view.animation.AnimationUtils;
import com.example.bookui.R;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.RecyclerView;
public class CustomItemAnimator extends DefaultItemAnimator {
#Override
public boolean animateRemove(RecyclerView.ViewHolder holder) {
return super.animateRemove(holder);
}
#Override
public boolean animateAdd(RecyclerView.ViewHolder holder) {
holder.itemView.setAnimation(AnimationUtils.loadAnimation(holder.itemView.getContext(),
R.anim.viewholder_add_anim));
return super.animateAdd(holder);
}
}
Main Activity
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerViewBooks;
private BookAdapter bookAdapter;
private List<Book> mdata;
private Button addButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
initmdataBooks();
setUpBookAdapter();
}
private void initViews() {
addButton = findViewById(R.id.add_btn);
recyclerViewBooks = findViewById(R.id.recyclerView);
recyclerViewBooks.setHasFixedSize(true);
recyclerViewBooks.setItemAnimator(new CustomItemAnimator());
addButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
addBook();
}
});
}
private void initmdataBooks() {
mdata = new ArrayList<>();
mdata.add(new Book(R.drawable.book1));
mdata.add(new Book(R.drawable.book2));
mdata.add(new Book(R.drawable.book3));
mdata.add(new Book(R.drawable.book2));
mdata.add(new Book(R.drawable.book4));
mdata.add(new Book(R.drawable.book5));
mdata.add(new Book(R.drawable.book1));
mdata.add(new Book(R.drawable.book1));
mdata.add(new Book(R.drawable.book5));
}
private void setUpBookAdapter() {
bookAdapter = new BookAdapter(mdata);
recyclerViewBooks.setAdapter(bookAdapter);
}
private void addBook() {
Book book = new Book(R.drawable.book4);
mdata.add(1, book);
bookAdapter.notifyDataSetChanged();
}
}
You have to properly fullfill ItemAnimator contract instead of blindly overriding animateAdd:
Don't call through to super.animateAdd(holder) - you're just going to run into conflict with default fade in animation.
You have to keep track of this animation and call dispatchAddStarting(holder) / dispatchAddFinished(holder) to inform super implementation of current animation state.
You have to override few more methods (in code below) that must be aware of whether your animations are running and provide cancellation option
Sample DefaultItemAnimator overriden to run a scale up animation on newly added items:
public class AddRecAnimator extends DefaultItemAnimator {
private final static String TAG = "AddRecAnimator";
// must keep track of all pending/ongoing animations.
private final ArrayList<AddHolder> pending = new ArrayList<>();
private final HashMap<RecyclerView.ViewHolder, AddHolder> additions = new HashMap<>();
#Override
public boolean animateAdd(RecyclerView.ViewHolder holder) {
pending.add(new AddHolder(holder));
return true; // return true to receive call to runPendingAnimations
}
#Override
public void runPendingAnimations() {
for (AddHolder ah : pending) {
ah.start();
}
pending.clear();
super.runPendingAnimations();
}
#Override
public void endAnimation(RecyclerView.ViewHolder item) {
AddHolder ah = additions.get(item);
if (ah != null) {
ah.endAnimation();
}
super.endAnimation(item);
}
#Override
public void endAnimations() {
for (AddHolder ah : pending) {
ah.resetViewHolderState();
dispatchAddFinished(ah.holder);
}
for (AddHolder ah : additions.values()) {
ah.resetViewHolderState();
dispatchAddFinished(ah.holder);
}
pending.clear();
additions.clear();
super.endAnimations();
}
#Override
public boolean isRunning() {
return super.isRunning() &&
!pending.isEmpty() &&
!additions.isEmpty();
}
/**
* This is container for addition animation. It's also end listener for it.
*/
private final class AddHolder implements Animation.AnimationListener {
private final RecyclerView.ViewHolder holder;
private AddHolder(RecyclerView.ViewHolder holder) {
this.holder = holder;
Animation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(500);
anim.setAnimationListener(this);
holder.itemView.setAnimation(anim);
dispatchAddStarting(holder);
}
void start() {
View itemView = holder.itemView;
Animation a = itemView.getAnimation();
if (a != null) {
a.start();
additions.put(holder, this);
} else {
endAnimation(); // invalid state, animation missing
}
}
private void resetViewHolderState() {
// reset state as if no animation was ran
Animation a = holder.itemView.getAnimation();
if (a != null) {
a.setAnimationListener(null);
a.cancel();
holder.itemView.clearAnimation();
}
holder.itemView.setScaleX(1f);
holder.itemView.setScaleY(1f);
}
// called when animation ends or is manually cancelled
protected void endAnimation(){
additions.remove(holder);
resetViewHolderState();
dispatchAddFinished(holder);
// if all animations in animator are done dispatch they're finished
if (!isRunning()) dispatchAnimationsFinished();
}
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
endAnimation();
}
#Override
public void onAnimationRepeat(Animation animation) {
}
}
}
I've been facing issues with my MoviesApp for a while now and I feel that I've exhausted all my knowledge on this; I am quite new with Android so bear with me :-)
MoviesApp is a simple movie listing app, in which the user can scroll through the list of films, see details for each one and save their favorites in an SQLite DB.
I use SharedPreference to sort movies based by popularity, rating and favorites (the only list saved in the database), but when I change through each one, the UI is not updating at all.
I am really stuck and honestly, I could do with another pair of eyes, because, even if the answer is staring me in the face, I wouldn't be able to see it 😫😫😫
I pasted the link to the project below:
https://drive.google.com/file/d/1SweLpwfo5RntXrbtLPP3N_xS1bVs32Ze/view?usp=sharing
Thank you!!
Update: I believe the problem would in the MainActivity class, where the RecyclerView Loader is declared - specifically in onLoadFinished().
#SuppressWarnings({"WeakerAccess", "unused", "CanBeFinal"})
public class MainActivity extends AppCompatActivity implements
LoaderManager.LoaderCallbacks,
MovieAdapter.MovieDetailClickHandler, SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = MainActivity.class.getSimpleName();
public static final String MOVIE_ID = "movieId";
private final static String LIFECYCLE_CALLBACKS_LAYOUT_MANAGER_KEY = "KeyForLayoutManagerState";
Parcelable savedLayoutManagerState;
public RecyclerView movieListRV;
private GridLayoutManager gridLayoutManager =
new GridLayoutManager(this, 1);
Context context = this;
// Loader IDs for loading the main API and the poster API, respectively
private static final int ID_LOADER_LIST_MOVIES = 1;
private static final int ID_LOADER_CURSOR = 2;
// adapter
private MovieAdapter adapter;
// detect internet connection
NetworkDetection networkDetection;
// swipe to refresh
SwipeRefreshLayout swipeRefreshLayout;
// sortOption
String sortOption = null;
// movie projection
private final String[] projection = new String[]{
MoviesContract.MovieEntry.COLUMN_MOVIE_POSTER,
MoviesContract.MovieEntry.COLUMN_MOVIE_ID
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Stetho.initializeWithDefaults(this);
Toolbar toolbar = findViewById(R.id.settings_activity_toolbar);
setSupportActionBar(toolbar);
toolbar.setTitleTextColor(Color.WHITE);
networkDetection = new NetworkDetection(this);
swipeRefreshLayout = findViewById(R.id.discover_swipe_refresh);
swipeRefreshLayout.setOnRefreshListener(MainActivity.this);
swipeRefreshLayout.setColorScheme(android.R.color.holo_red_dark);
movieListRV = findViewById(R.id.recycler_view_movies);
movieListRV.setLayoutManager(gridLayoutManager);
movieListRV.setHasFixedSize(true);
ViewTreeObserver viewTreeObserver = movieListRV.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
calculateSize();
}
});
adapter = new MovieAdapter(this, this);
movieListRV.setAdapter(adapter);
RecyclerViewItemDecorator itemDecorator = new RecyclerViewItemDecorator(context,
R.dimen.item_offset);
movieListRV.addItemDecoration(itemDecorator);
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences
(context);
SharedPreferences.OnSharedPreferenceChangeListener preferenceChangeListener = new
SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
adapter.deleteItemsInList();
onRefresh();
if (key.equals(getString(R.string.pref_sort_by_key))) {
initializeloader();
}
}
};
preferences.registerOnSharedPreferenceChangeListener(preferenceChangeListener);
initializeloader();
}
private static final int sColumnWidth = 200;
private void calculateSize() {
int spanCount = (int) Math.floor(movieListRV.getWidth() / convertDPToPixels(sColumnWidth));
((GridLayoutManager) movieListRV.getLayoutManager()).setSpanCount(spanCount);
}
#SuppressWarnings("SameParameterValue")
private float convertDPToPixels(int dp) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
float logicalDensity = metrics.density;
return dp * logicalDensity;
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(LIFECYCLE_CALLBACKS_LAYOUT_MANAGER_KEY, gridLayoutManager
.onSaveInstanceState());
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null) {
savedLayoutManagerState = savedInstanceState.getParcelable
(LIFECYCLE_CALLBACKS_LAYOUT_MANAGER_KEY);
movieListRV.getLayoutManager().onRestoreInstanceState(savedLayoutManagerState);
}
}
#Override
public Loader onCreateLoader(int id, Bundle args) {
adapter.deleteItemsInList();
String urlMovieActivity;
switch (id) {
case ID_LOADER_CURSOR:
return new CursorLoader(context, MoviesContract.MovieEntry.MOVIES_CONTENT_URI,
projection, null, null, null);
case ID_LOADER_LIST_MOVIES:
urlMovieActivity = NetworkUtils.buildUrlMovieActivity(context, sortOption);
return new MovieLoader(this, urlMovieActivity);
default:
return null;
}
}
#Override
public void onLoadFinished(Loader loader, Object data) {
adapter.deleteItemsInList();
TextView noMoviesMessage = findViewById(R.id.no_movies_found_tv);
switch (loader.getId()) {
case ID_LOADER_CURSOR:
adapter.InsertList(data);
break;
case ID_LOADER_LIST_MOVIES:
//noinspection unchecked
List<MovieItem> movieItems = (List<MovieItem>) data;
if (networkDetection.isConnected()) {
noMoviesMessage.setVisibility(View.GONE);
adapter.InsertList(movieItems);
movieListRV.getLayoutManager().onRestoreInstanceState(savedLayoutManagerState);
} else {
noMoviesMessage.setVisibility(View.VISIBLE);
}
break;
}
adapter.notifyDataSetChanged();
}
#Override
public void onLoaderReset(Loader loader) {
switch (loader.getId()) {
case ID_LOADER_CURSOR:
adapter.InsertList(null);
break;
case ID_LOADER_LIST_MOVIES:
adapter.InsertList(null);
break;
}
}
#Override
public void onPostResume(Loader loader) {
super.onPostResume();
getLoaderManager().initLoader(ID_LOADER_CURSOR, null, this);
}
#Override
public void onSelectedItem(int movieId) {
Intent goToDetailActivity = new Intent(this, DetailMovieActivity.class);
goToDetailActivity.putExtra(MOVIE_ID, movieId);
startActivity(goToDetailActivity);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_general, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
int id = menuItem.getItemId();
if (id == R.id.action_general_settings) {
Intent goToSetting = new Intent(this, SettingsActivity.class);
startActivity(goToSetting);
return true;
} else if (id == R.id.action_refresh) {
onRefresh();
}
return super.onOptionsItemSelected(menuItem);
}
/**
* Called when a swipe gesture triggers a refresh.
*/
#Override
public void onRefresh() {
adapter.deleteItemsInList();
swipeRefreshLayout.setRefreshing(false);
restartloader();
adapter.notifyDataSetChanged();
}
private void restartloader() {
adapter.deleteItemsInList();
if (MoviePreferences.getSortByPreference(context).equals(getString(R.string
.pref_sort_by_favourite))) {
getLoaderManager().restartLoader(ID_LOADER_CURSOR, null, MainActivity
.this);
}
if (MoviePreferences.getSortByPreference(context).equals(getString(R.string
.pref_sort_by_popularity))) {
sortOption = NetworkUtils.MOST_POPULAR_PARAM;
getLoaderManager().restartLoader(ID_LOADER_LIST_MOVIES, null,
MainActivity.this);
}
if (MoviePreferences.getSortByPreference(context).equals(getString(R.string
.pref_sort_by_rating))) {
sortOption = NetworkUtils.TOP_RATED_PARAM;
getLoaderManager().restartLoader(ID_LOADER_LIST_MOVIES, null,
MainActivity.this);
}
adapter.notifyDataSetChanged();
}
public void initializeloader() {
restartloader();
if (MoviePreferences.getSortByPreference(context).equals(getString(R.string
.pref_sort_by_favourite))) {
getLoaderManager().initLoader(ID_LOADER_CURSOR, null, MainActivity
.this);
}
if (MoviePreferences.getSortByPreference(context).equals(getString(R.string
.pref_sort_by_popularity))) {
onRefresh();
sortOption = NetworkUtils.MOST_POPULAR_PARAM;
getLoaderManager().initLoader(ID_LOADER_LIST_MOVIES, null,
MainActivity.this);
}
if (MoviePreferences.getSortByPreference(context).equals(getString(R.string
.pref_sort_by_rating))) {
onRefresh();
sortOption = NetworkUtils.TOP_RATED_PARAM;
getLoaderManager().initLoader(ID_LOADER_LIST_MOVIES, null,
MainActivity.this);
}
adapter.notifyDataSetChanged();
}
}
In my activity A, this view called twice, but in my activity B, there is no problem.
Activity A is very simple layout with a few linearLayout. I'm about to go crazy, what can be the problem?
Here is I have my AdBannerView:
public class AdBannerView extends LinearLayout {
public ImageView adIcon, adInstall;
public TextView_ adTitle, adDesc;
public ProgressBar adProgress;
RelativeLayout adWrapperLay;
private boolean impSent, adLoaded = false;
public AdBannerView(Context context) {
super(context);
}
public AdBannerView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public AdBannerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void init(Context context) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View wrapper = inflater.inflate(R.layout.view_ad_banner, this, true);
adIcon = (ImageView) wrapper.findViewById(R.id.adIcon);
adInstall = (ImageView) wrapper.findViewById(R.id.adInstall);
adTitle = (TextView_) wrapper.findViewById(R.id.adTitle);
adDesc = (TextView_) wrapper.findViewById(R.id.adDesc);
adProgress = (ProgressBar) wrapper.findViewById(R.id.adProgress);
adWrapperLay = (RelativeLayout) wrapper.findViewById(R.id.adWrapperLay);
Log.d("AdBannerView", "before loadAd()");
if(NativeAdManager.getInstance().isAdEnabled)
loadAd();
}
public void loadAd(){
if(adLoaded)
return;
adLoaded = true;
Log.d("AdBannerView", "loadAd() request");
NativeAdManager.getInstance().getAd(getContext(), new NativeAdManager.AdListener() {
#Override
public void adLoaded(final NativeAdResponse.Ads[] ads) {
/* load img */
Picasso
.with(getContext())
.load(ads[0].adIc)
.into(adIcon);
/* load title */
adTitle.setText(""+ads[0].adTit);
adDesc.setText(""+ads[0].adDesc);
/* click listener */
adInstall.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
App app = (App) getContext().getApplicationContext();
app.getUiController().loadUrlWithoutAdBlocker(ads[0].adClk);
}
});
/* show this layout */
showAd(ads[0].adBeacons);
Log.d("AdBannerView", "loaded with size = " + ads.length);
}
});
}
private void showAd(final NativeAdResponse.adBeacons[] adBeacons) {
adProgress.setVisibility(GONE);
adIcon.setVisibility(VISIBLE);
}
}
I'm including to layout like this:
<.... AdBannerView match_parent etc />
Logs that proves drawing twice:
10-29 20:28:19.219 6698-6698/pack D/AdBannerView﹕ before loadAd()
10-29 20:28:19.219 6698-6698/pack D/AdBannerView﹕ loadAd() request
10-29 20:28:19.295 6698-6698/pack D/AdBannerView﹕ before loadAd()
10-29 20:28:19.295 6698-6698/pack D/AdBannerView﹕ loadAd() request
10-29 20:28:19.636 6698-6698/pack D/AdBannerView﹕ loaded with size = 1
10-29 20:28:19.852 6698-6698/pack D/AdBannerView﹕ loaded with size = 1
Problematic activity A:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<package.AdManager.AdBannerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="40dp"
/>
</RelativeLayout>
Activity A.java (I deleted everything in layout and class except of AdBannerView but still same):
package package.Activity;
public class NewsRead extends Base {
ToolBarView toolBarView;
RelativeLayout backgroundLayForMainBgColor;
ImageView imageView;
TextView_ titleText, contentText, sourceText;
LinearLayout wrapperLay /* for homeViewRowBg */, relatedNewsLay;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutResourceId());
/*
this.toolBarView = (ToolBarView) findViewById(R.id.toolBarView);
this.backgroundLayForMainBgColor = (RelativeLayout) findViewById(R.id.backgroundLayForMainBgColor);
this.imageView = (ImageView) findViewById(R.id.imageView);
this.titleText = (TextView_) findViewById(R.id.titleText);
this.contentText = (TextView_) findViewById(R.id.contentText);
this.sourceText = (TextView_) findViewById(R.id.sourceText);
this.wrapperLay = (LinearLayout) findViewById(R.id.wrapperLay);
changeTheme();
toolBarView.hideDeleteButton().setToolBarClickListener(new ToolBarView.ToolBarClickListener() {
#Override
public void backButtonClick() {
finish();
}
#Override
public void deleteButtonClick() {
}
});
Intent intent = getIntent();
if(intent == null)
return;
loadNewsDetail(intent);
*/
}
private void loadNewsDetail(Intent intent) {
String neTi = intent.getStringExtra("neTi");
String neCo = intent.getStringExtra("neCo");
String neSi = intent.getStringExtra("neSi");
String neIm = intent.getStringExtra("neIm");
String neUr = intent.getStringExtra("neUr");
/**/
Picasso
.with(this)
.load(neIm)
//.placeholder(R.drawable.icon_placeholder)
.into(imageView);
titleText.setText(neTi);
contentText.setText(neCo);
sourceText.setText("Source: "+ Html.fromHtml("<u>"+neSi+"</u>"));
}
private void changeTheme() {
ThemeModel curTheme = ThemeController.getInstance().getCurrentTheme();
if(curTheme.hasBgImage()) {
backgroundLayForMainBgColor.setBackground(curTheme.mainBgDrawable);
} else {
backgroundLayForMainBgColor.setBackgroundColor(Color.parseColor(ThemeController.getInstance().getCurrentTheme().mainBgColor));
}
wrapperLay.setBackgroundColor(Color.parseColor(curTheme.homeViewRowBg));
}
protected int getLayoutResourceId() {
return R.layout.activity_news_read;
}
#Override
protected void onSoftInputShown() {
}
#Override
protected void onSoftInputHidden() {
}
#Override
protected String getActivityName() {
return "news_read";
}
#Override
public void onBackPressed(){
super.onBackPressed();
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
}
Base:
public abstract class Base extends Activity {
private boolean isKeyboardOpened;
#Override
public void onCreate(Bundle b) {
super.onCreate(b);
setContentView(getLayoutResourceId());
keyBoardListener();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
TrackingController.onActivityOpen(getActivityName());
}
}, 50);
}
#Override
public void onDestroy() {
super.onDestroy();
}
protected abstract int getLayoutResourceId();
public void Toast(String str) {
Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
}
public void Log(String str) {
Log.d("act_name:"+getActivityName(), str);
}
private void keyBoardListener(){
final View activityRootView = getWindow().getDecorView().findViewById(android.R.id.content);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
if (heightDiff > 100 ) { // 99% of the time the height diff will be due to a keyboard.
if(isKeyboardOpened == false){
onSoftInputShown();
}
isKeyboardOpened = true;
}else if(isKeyboardOpened == true){
onSoftInputHidden();
isKeyboardOpened = false;
}
}
});
}
public String getString_(int resId){
return getResources().getString(resId);
}
protected abstract void onSoftInputShown();
protected abstract void onSoftInputHidden();
protected abstract String getActivityName();
}
Here's your bug :) Hopefully
You have in your base a call to setContentView and then in your deriving class you have call to super create (which calls the setContentView [which creates the adElement]) but after that you call again setContentView(getLayoutResourceId()); (this time from your derived class which overrides the layout but even if it didn't it's calling actually the same content I imagine so that's why it looks normal :)
So the fix should be easy - remove the setContentView(getLayoutResourceId()) from your activity A because it's already called from the base activity
I am using QRCodeReaderView https://github.com/dlazaro66/QRCodeReaderView for implementing my own QR Code Scanner and it works well but the camera still starts slow (3-4 seconds) and I came up with the idea to pre start previewing the camera before using (keeping the camera open when the focus is on the fragment that has the button to start scanning so it could be opened right away when needed) and I tried everything but it seems like I don't understand the concept and it still starts slow.
Here is the code for the QRCodeReaderView:
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.FormatException;
import com.google.zxing.NotFoundException;
import com.google.zxing.PlanarYUVLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
import com.google.zxing.client.android.camera.open.CameraManager;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import java.io.IOException;
public class QRCodeReaderView extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback {
public interface OnQRCodeReadListener {
public void onQRCodeRead(String text, PointF[] points);
public void cameraNotFound();
public void QRCodeNotFoundOnCamImage();
}
private OnQRCodeReadListener mOnQRCodeReadListener;
private static final String TAG = QRCodeReaderView.class.getName();
private QRCodeReader mQRCodeReader;
private int mPreviewWidth;
private int mPreviewHeight;
private SurfaceHolder mHolder;
private CameraManager mCameraManager;
public QRCodeReaderView(Context context) {
super(context);
init();
}
public QRCodeReaderView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public void setOnQRCodeReadListener(OnQRCodeReadListener onQRCodeReadListener) {
mOnQRCodeReadListener = onQRCodeReadListener;
}
public CameraManager getCameraManager() {
return mCameraManager;
}
#SuppressWarnings("deprecation")
private void init() {
if (checkCameraHardware(getContext())) {
mCameraManager = new CameraManager(getContext());
mHolder = this.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // Need to set this flag despite it's deprecated
} else {
Log.e(TAG, "Error: Camera not found");
if (mOnQRCodeReadListener != null) {
mOnQRCodeReadListener.cameraNotFound();
}
}
}
/**
* *************************************************
* SurfaceHolder.Callback,Camera.PreviewCallback
* **************************************************
*/
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
// Indicate camera, our View dimensions
mCameraManager.openDriver(holder, this.getWidth(), this.getHeight());
} catch (IOException e) {
Log.w(TAG, "Can not openDriver: " + e.getMessage());
mCameraManager.closeDriver();
}
try {
mQRCodeReader = new QRCodeReader();
mCameraManager.startPreview();
} catch (Exception e) {
Log.e(TAG, "Exception: " + e.getMessage());
mCameraManager.closeDriver();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "surfaceDestroyed");
mCameraManager.getCamera().setPreviewCallback(null);
mCameraManager.getCamera().stopPreview();
mCameraManager.getCamera().release();
mCameraManager.closeDriver();
}
// Called when camera take a frame
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
PlanarYUVLuminanceSource source = mCameraManager.buildLuminanceSource(data, mPreviewWidth, mPreviewHeight);
HybridBinarizer hybBin = new HybridBinarizer(source);
BinaryBitmap bitmap = new BinaryBitmap(hybBin);
try {
Result result = mQRCodeReader.decode(bitmap);
// Notify we found a QRCode
if (mOnQRCodeReadListener != null) {
// Transform resultPoints to View coordinates
PointF[] transformedPoints = transformToViewCoordinates(result.getResultPoints());
mOnQRCodeReadListener.onQRCodeRead(result.getText(), transformedPoints);
}
} catch (ChecksumException e) {
Log.d(TAG, "ChecksumException");
e.printStackTrace();
} catch (NotFoundException e) {
// Notify QR not found
if (mOnQRCodeReadListener != null) {
mOnQRCodeReadListener.QRCodeNotFoundOnCamImage();
}
} catch (FormatException e) {
Log.d(TAG, "FormatException");
e.printStackTrace();
} finally {
mQRCodeReader.reset();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.d(TAG, "surfaceChanged");
if (mHolder.getSurface() == null) {
Log.e(TAG, "Error: preview surface does not exist");
return;
}
//preview_width = width;
//preview_height = height;
mPreviewWidth = mCameraManager.getPreviewSize().x;
mPreviewHeight = mCameraManager.getPreviewSize().y;
mCameraManager.stopPreview();
mCameraManager.getCamera().setPreviewCallback(this);
mCameraManager.getCamera().setDisplayOrientation(90); // Portrait mode
mCameraManager.startPreview();
}
/**
* Transform result to surfaceView coordinates
* <p/>
* This method is needed because coordinates are given in landscape camera coordinates.
* Now is working but transform operations aren't very explained
* <p/>
* TODO re-write this method explaining each single value
*
* #return a new PointF array with transformed points
*/
private PointF[] transformToViewCoordinates(ResultPoint[] resultPoints) {
PointF[] transformedPoints = new PointF[resultPoints.length];
int index = 0;
if (resultPoints != null) {
float previewX = mCameraManager.getPreviewSize().x;
float previewY = mCameraManager.getPreviewSize().y;
float scaleX = this.getWidth() / previewY;
float scaleY = this.getHeight() / previewX;
for (ResultPoint point : resultPoints) {
PointF tmppoint = new PointF((previewY - point.getY()) * scaleX, point.getX() * scaleY);
transformedPoints[index] = tmppoint;
index++;
}
}
return transformedPoints;
}
/**
* Check if this device has a camera
*/
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
// this device has a camera
return true;
} else if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
// this device has a front camera
return true;
} else if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) {
// this device has any camera
return true;
} else {
// no camera on this device
return false;
}
}
}
and here is my fragment that uses it:
package com.breadwallet.presenter.fragments;
import com.breadwallet.R;
import com.breadwallet.presenter.activities.ScanResultActivity;
import com.breadwallet.tools.animation.SpringAnimator;
import com.breadwallet.tools.qrcode.QRCodeReaderView;
public class MainFragmentDecoder extends Fragment implements QRCodeReaderView.OnQRCodeReadListener {
public static final String TAG = "MainFragmentDecoder";
private boolean accessGranted = true;
private TextView myTextView;
private static QRCodeReaderView mydecoderview;
private ImageView camera_guide_image;
private Intent intent;
public static MainFragmentDecoder mainFragmentDecoder;
private RelativeLayout layout;
public MainFragmentDecoder() {
mainFragmentDecoder = this;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_decoder, container, false);
intent = new Intent(getActivity(), ScanResultActivity.class);
myTextView = (TextView) rootView.findViewById(R.id.exampleTextView);
camera_guide_image = (ImageView) rootView.findViewById(R.id.camera_guide_image);
SpringAnimator.showExpandCameraGuide(camera_guide_image);
// Inflate the layout for this fragment
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
layout = (RelativeLayout) getView().findViewById(R.id.fragment_decoder_layout);
mydecoderview = new QRCodeReaderView(getActivity().getApplicationContext());
mydecoderview.setOnQRCodeReadListener(mainFragmentDecoder);
if (mydecoderview != null)
mydecoderview.getCameraManager().startPreview();
}
/**
* Called when a QR is decoded
* "text" : the text encoded in QR
* "points" : points where QR control points are placed
*/
#Override
public void onQRCodeRead(String text, PointF[] points) {
synchronized (this) {
if (accessGranted) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
accessGranted = true;
}
}, 300);
accessGranted = false;
// Log.e(TAG, "Activity STARTED!!!!!");
intent.putExtra("result", text);
startActivity(intent);
}
}
}
// Called when your device have no camera
#Override
public void cameraNotFound() {
Log.d(TAG, "No Camera found!");
}
// Called when there's no QR codes in the camera preview image
#Override
public void QRCodeNotFoundOnCamImage() {
// Log.d(TAG, "No QR Code found!");
}
#Override
public void onResume() {
super.onResume();
new CameraOpenerTask().execute();
}
#Override
public void onPause() {
super.onPause();
Log.e(TAG, "In onPause");
mydecoderview.getCameraManager().stopPreview();
layout.removeView(mydecoderview);
}
private class CameraOpenerTask extends AsyncTask {
#Override
protected Object doInBackground(Object[] params) {
return null;
}
#Override
protected void onPostExecute(Object o) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
layout.addView(mydecoderview, 0);
}
}, 1300);
Log.e(TAG, "The camera started");
}
}
public void stopCamera() {
if (mydecoderview != null) {
mydecoderview.getCameraManager().stopPreview();
}
mydecoderview = null;
}
}
I tried:
camera.StartPreview() earlier than using it.
pre-create the mydecoderview and then simply make it visible when
pressing the button but it still takes 3-4 seconds to start it.
You could try photo app in CyanogenMod (11 version) firmware, maybe this is just that you're searching for?
Download from somewhere it source and add its to your code.
I'm doing an activity to measure how long it takes a person to do an exercise, but it has a bug that I couldn't resolve yet...
The TrainingFragment shows a list of exercises that the user can click and then my ExerciseActivity is launched and runs until the variable "remainingsSets" is setted to 0.
When I click in the first time at any exercise, everything works fine, the ExerciseActivity works correctly end return to the TrainingFragment. But then, if I try to click in another exercise, the ExerciseActivity is just closed.
In my debug, I could see that the variable "remainingSets" comes with it's right value (remainingSets = getIntent().getIntExtra("remaining_sets", 3)), but when the startButton is clicked, I don't know why the variable "remainingSets" is setted to 0 and then the activity is closed because this condition: if (remainingSets > 0){...}.
Here is my TrainingFragment:
public class TrainingFragment extends Fragment {
private final static int START_EXERCISE = 1;
private Training training;
private String lastItemClicked;
private String[] values;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Bundle bundle = getArguments();
if (bundle != null) {
training = bundle.getParcelable("training");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return (ScrollView) inflater.inflate(R.layout.template_exercises, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
LinearLayout exercisesContainer = (LinearLayout) getView().findViewById(R.id.exercises);
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
List<Exercise> exercises = training.getExercises();
values = new String[exercises.size()];
if (savedInstanceState != null) {
values = savedInstanceState.getStringArray("values");
}
for (int i = 0; i < exercises.size(); i++) {
final View exerciseView = inflater.inflate(R.layout.template_exercise, null);
exerciseView.setTag(String.valueOf(i));
TextView remainingSets = (TextView) exerciseView.findViewById(R.id.remaining_sets);
if (savedInstanceState != null) {
remainingSets.setText(values[i]);
} else {
String sets = exercises.get(i).getSets();
remainingSets.setText(sets);
values[i] = sets;
}
exerciseView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), ExerciseActivity.class);
intent.putExtra("remaining_sets",
Integer.valueOf(((TextView) v.findViewById(R.id.remaining_sets)).getText().toString()));
lastItemClicked = v.getTag().toString();
startActivityForResult(intent, START_EXERCISE);
}
});
exercisesContainer.addView(exerciseView);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putStringArray("values", values);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
View view = ((LinearLayout) getView().findViewById(R.id.exercises)).findViewWithTag(lastItemClicked);
if (requestCode == START_EXERCISE) {
if (resultCode == Activity.RESULT_OK) { // the exercise had been
// finished.
((TextView) view.findViewById(R.id.remaining_sets)).setText("0");
view.setClickable(false);
values[Integer.valueOf(lastItemClicked)] = "0";
} else if (resultCode == Activity.RESULT_CANCELED) {
String remainingSets = data.getStringExtra("remaining_sets");
((TextView) view.findViewById(R.id.remaining_sets)).setText(remainingSets);
values[Integer.valueOf(lastItemClicked)] = remainingSets;
}
}
}
}
My ExerciseActivity:
public class ExerciseActivity extends Activity {
private Chronometer chronometer;
private TextView timer;
private Button startButton;
private Button endButton;
private int remainingSets;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exercise);
ExerciseEvents.addExerciseListener(new PopupExerciseListener());
chronometer = (Chronometer) findViewById(R.id.exercise_doing_timer);
timer = (TextView) findViewById(R.id.timer);
startButton = (Button) findViewById(R.id.start_exercise);
startButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ExerciseEvents.onExerciseBegin();
}
});
endButton = (Button) findViewById(R.id.end_exercise);
endButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ExerciseEvents.onExerciseRest();
}
});
}
#Override
public void onBackPressed() {
Intent intent = new Intent();
intent.putExtra("remaining_sets", String.valueOf(remainingSets));
setResult(RESULT_CANCELED, intent);
super.onBackPressed();
}
public class PopupExerciseListener implements ExerciseListener {
public PopupExerciseListener() {
remainingSets = getIntent().getIntExtra("remaining_sets", 3);
}
#Override
public void onExerciseBegin() {
if (remainingSets > 0) {
chronometer.setVisibility(View.VISIBLE);
timer.setVisibility(View.GONE);
chronometer.setBase(SystemClock.elapsedRealtime());
chronometer.start();
startButton.setVisibility(View.GONE);
endButton.setVisibility(View.VISIBLE);
} else {
ExerciseEvents.onExerciseFinish();
}
}
#Override
public void onExerciseFinish() {
setResult(RESULT_OK);
finish();
}
#Override
public void onExerciseRest() {
chronometer.setVisibility(View.GONE);
endButton.setVisibility(View.GONE);
timer.setVisibility(View.VISIBLE);
long restTime = getIntent().getLongExtra("time_to_rest", 60) * 1000;
new CountDownTimer(restTime, 1000) {
#Override
public void onTick(long millisUntilFinished) {
timer.setText(String.valueOf(millisUntilFinished / 1000));
}
#Override
public void onFinish() {
ExerciseEvents.onExerciseBegin();
}
}.start();
remainingSets--;
}
}
}
And my ExerciseEvents:
public class ExerciseEvents {
private static LinkedList<ExerciseListener> mExerciseListeners = new LinkedList<ExerciseListener>();
public static void addExerciseListener(ExerciseListener listener) {
mExerciseListeners.add(listener);
}
public static void removeExerciseListener(String listener) {
mExerciseListeners.remove(listener);
}
public static void onExerciseBegin() {
for (ExerciseListener l : mExerciseListeners) {
l.onExerciseBegin();
}
}
public static void onExerciseRest() {
for (ExerciseListener l : mExerciseListeners) {
l.onExerciseRest();
}
}
public static void onExerciseFinish() {
for (ExerciseListener l : mExerciseListeners) {
l.onExerciseFinish();
}
}
public static interface ExerciseListener {
public void onExerciseBegin();
public void onExerciseRest();
public void onExerciseFinish();
}
}
Could anyone give me any help?
After you updated your code, I see you have a big memory leak in your code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exercise);
ExerciseEvents.addExerciseListener(new PopupExerciseListener());
....
}
The call ExerciseEvents.addExerciseListener(new PopupExerciseListener()) adds a new PopupExerciseListener to a static/global list: ExcerciseEvents.mExerciseListeners. Since the class PopupExerciseListener is an inner-class, it implicitly holds a reference to its enclosing ExcerciseActivity. This mean your code is holding on to each instance of ExcerciseActivity forever. Not good.
This may also explain the weird behavior you see. When one of the onExcersizeXXX() methods is called, it will call all ExcerciseListeners in the linked-list, the ones from previous screens and the current one.
Try this in your ExcerciseActivity.java:
....
ExerciseListener mExerciseListener;
....
#Override
protected void onCreate(Bundle savedInstanceState) {
....
....
mExerciseListener = new PopupExerciseListener()
ExerciseEvents.addExerciseListener(mExerciseListener);
....
....
}
#Override
protected void onDestroy() {
ExerciseEvents.removeExerciseListener(mExerciseListener);
super.onDestroy();
}
....
In onDestroy, you deregister your listener, preventing a memory leak and preventing odd multiple callbacks to PopupExerciseListeners that are attached to activities that no longer exist.