This is my Multi selection code.
public class CheckableLayout1 extends ImageView implements Checkable {
private boolean mChecked;
public CheckableLayout1(Context context) {
super(context);
}
#SuppressWarnings("deprecation")
public void setChecked(boolean checked) {
mChecked = checked;
setForeground(checked ? getResources().getDrawable(R.drawable.ic_select) : null);
refreshDrawableState();
}
#Override
public int[] onCreateDrawableState(final int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked())
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
return drawableState;
}
public boolean isChecked() {
return mChecked;
}
public void toggle() {
setChecked(!mChecked);
}
}
It works in android nougat but not in any lower version of android. What is wrong with it?
Related
I have an app that works fine on older Android versions, however, on later (Android 11> onwards) whilst the camera(take photo) function works fine, and permissions are OK I can't use the PhotoPicker function, it just shows blank picker , before crashing out of the app completely - in older devices the photo gallery of the device displays correctly and allows you to select a photo to use.
Here is the onCreate for the
PhotoPickerActivity.java
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
requestWindowFeature(1);
getWindow().setFlags(1024, 1024);
boolean booleanExtra = getIntent().getBooleanExtra(PhotoPicker.EXTRA_SHOW_CAMERA, true);
boolean booleanExtra2 = getIntent().getBooleanExtra(PhotoPicker.EXTRA_SHOW_GIF, false);
boolean booleanExtra3 = getIntent().getBooleanExtra(PhotoPicker.EXTRA_PREVIEW_ENABLED, true);
this.forwardMain = getIntent().getBooleanExtra(PhotoPicker.MAIN_ACTIVITY, false);
setShowGif(booleanExtra2);
setContentView(R.layout.__picker_activity_photo_picker);
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
setTitle(getResources().getString(R.string.tap_to_select));
ActionBar supportActionBar = getSupportActionBar();
supportActionBar.setDisplayHomeAsUpEnabled(true);
// if (Build.VERSION.SDK_INT >= 21) {
supportActionBar.setElevation(25.0f);
// }
this.maxCount = getIntent().getIntExtra(PhotoPicker.EXTRA_MAX_COUNT, 9);
int intExtra = getIntent().getIntExtra(PhotoPicker.EXTRA_GRID_COLUMN, 3);
this.originalPhotos = getIntent().getStringArrayListExtra(PhotoPicker.EXTRA_ORIGINAL_PHOTOS);
this.pickerFragment = (PhotoPickerFragment) getSupportFragmentManager().findFragmentByTag("tag");
if (this.pickerFragment == null) {
this.pickerFragment = PhotoPickerFragment.newInstance(booleanExtra, booleanExtra2, booleanExtra3, intExtra, this.maxCount, this.originalPhotos);
getSupportFragmentManager().beginTransaction().replace(R.id.container, this.pickerFragment, "tag").commit();
getSupportFragmentManager().executePendingTransactions();
}
this.pickerFragment.getPhotoGridAdapter().setOnItemCheckListener(new OnItemCheckListener() {
#Override
public final boolean onItemCheck(int i, Photo photo, int i2) {
return PhotoPickerActivity.this.lambda$onCreate$0$PhotoPickerActivity(i, photo, i2);
}
});
}
We also have PhotoPicker.java
public class PhotoPicker {
public static final int DEFAULT_COLUMN_NUMBER = 3;
public static final int DEFAULT_MAX_COUNT = 9;
public static final String EXTRA_GRID_COLUMN = "column";
public static final String EXTRA_MAX_COUNT = "MAX_COUNT";
public static final String EXTRA_ORIGINAL_PHOTOS = "ORIGINAL_PHOTOS";
public static final String EXTRA_PREVIEW_ENABLED = "PREVIEW_ENABLED";
public static final String EXTRA_SHOW_CAMERA = "SHOW_CAMERA";
public static final String EXTRA_SHOW_GIF = "SHOW_GIF";
public static final String KEY_SELECTED_PHOTOS = "SELECTED_PHOTOS";
public static final String MAIN_ACTIVITY = "MAIN_ACTIVITY";
public static final int REQUEST_CODE = 233;
public static PhotoPickerBuilder builder() {
return new PhotoPickerBuilder();
}
public static class PhotoPickerBuilder {
private Intent mPickerIntent = new Intent();
private Bundle mPickerOptionsBundle = new Bundle();
public void start(Activity activity, int i) {
if (PermissionsUtils.checkReadStoragePermission(activity)) {
activity.startActivityForResult(getIntent(activity), i);
}
}
public void start(Context context, Fragment fragment, int i) {
if (PermissionsUtils.checkReadStoragePermission(fragment.getActivity())) {
fragment.startActivityForResult(getIntent(context), i);
}
}
public void start(Context context, Fragment fragment) {
if (PermissionsUtils.checkReadStoragePermission(fragment.getActivity())) {
fragment.startActivityForResult(getIntent(context), PhotoPicker.REQUEST_CODE);
}
}
public Intent getIntent(Context context) {
this.mPickerIntent.setClass(context, PhotoPickerActivity.class);
this.mPickerIntent.putExtras(this.mPickerOptionsBundle);
return this.mPickerIntent;
}
public void start(Activity activity) {
start(activity, PhotoPicker.REQUEST_CODE);
}
public PhotoPickerBuilder setPhotoCount(int i) {
this.mPickerOptionsBundle.putInt(PhotoPicker.EXTRA_MAX_COUNT, i);
return this;
}
public PhotoPickerBuilder setGridColumnCount(int i) {
this.mPickerOptionsBundle.putInt(PhotoPicker.EXTRA_GRID_COLUMN, i);
return this;
}
public PhotoPickerBuilder setShowGif(boolean z) {
this.mPickerOptionsBundle.putBoolean(PhotoPicker.EXTRA_SHOW_GIF, z);
return this;
}
public PhotoPickerBuilder setShowCamera(boolean z) {
this.mPickerOptionsBundle.putBoolean(PhotoPicker.EXTRA_SHOW_CAMERA, z);
return this;
}
public PhotoPickerBuilder setSelected(ArrayList<String> arrayList) {
this.mPickerOptionsBundle.putStringArrayList(PhotoPicker.EXTRA_ORIGINAL_PHOTOS, arrayList);
return this;
}
public PhotoPickerBuilder setForwardMain(boolean z) {
this.mPickerOptionsBundle.putBoolean(PhotoPicker.MAIN_ACTIVITY, z);
return this;
}
public PhotoPickerBuilder setPreviewEnabled(boolean z) {
this.mPickerOptionsBundle.putBoolean(PhotoPicker.EXTRA_PREVIEW_ENABLED, z);
return this;
}
}
}
In the AndroidManifest.xml the permissions for Camera are there, and on runtime are checked, and permission is granted.
I wrote a wrapper around FirestorePagingAdapter. This works fine most of the times. But there are occasions where this crashes with
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter
I will show you the complete wrapper. Also the last log message I see before the crash is
[Paging adapter] Data loading finished.
I also noticed, when I slowly scroll the list it works fine. Only if I scroll the list fast it crashes eventually.
So here is the code. I cannot figure out where the problem is. Any help is highly appreciated
public abstract class PagingAdapter<T extends RecyclerItem> extends FirestorePagingAdapter<T, RecyclerViewHolder<T, ? extends ViewBinding>> implements Function1<CombinedLoadStates, Unit> {
protected final String TAG = this.getClass().getSimpleName();
private final SnapshotParser<T> mParser;
private SortedList<T> mListItems;
private int mTryCount;
private boolean mReverseFill = false;
private PagingAdapter(#NonNull FirestorePagingOptions<T> options, PagingAdapterCallback<T> callback) {
super(options);
mListItems = new SortedList(RecyclerItem.class, new SortedListAdapterCallback<T>(this) {
#Override
public int compare(T o1, T o2) {
return callback.compare(o1, o2);
}
#Override
public boolean areContentsTheSame(T oldItem, T newItem) {
return callback.areContentsTheSame(oldItem, newItem);
}
#Override
public boolean areItemsTheSame(T item1, T item2) {
return callback.areContentsTheSame(item1, item2);
}
});
mParser = options.getParser();
this.mTryCount = 0;
}
public void setReverseFill(boolean reverseFill) {
this.mReverseFill = reverseFill;
}
#Override
public int getItemViewType(int position) {
return getList().get(position).getRecyclerItemType().getId();
}
public SortedList<T> getList() {
return mListItems;
}
#NonNull
#Override
public RecyclerViewHolder<T, ? extends ViewBinding> onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
RecyclerViewHolder<T, ? extends ViewBinding> viewHolder = onCreateViewHolder(parent, RecyclerItemType
.get(viewType));
if (viewHolder == null) {
throw new NullPointerException("Your list contains items for that you did not specify a view holder for");
}
return viewHolder;
}
public abstract RecyclerViewHolder<T, ? extends ViewBinding> onCreateViewHolder(#NonNull ViewGroup parent, RecyclerItemType itemType);
#Override
public void onBindViewHolder(RecyclerViewHolder<T, ? extends ViewBinding> holder, int position) {
try {
//and trigger the paging to load around with the correct "position"
super.onBindViewHolder(holder, getPagingPosition(position)); //<--Needed to page the list, be we do not really use it (see below)
} catch (Exception ignore) {
//If this fails, because there are less items in the list, do not crash, this is fine
Log.d(TAG, "onBindViewHolder: ");
}
holder.bind(getList().get(position));
}
protected int getPagingPosition(int requestedPosition) {
return requestedPosition;
}
#Override
protected void onBindViewHolder(#NonNull RecyclerViewHolder<T, ? extends ViewBinding> holder, int position, #NonNull T model) {
//We do not use this method
}
#Override
public int getItemCount() {
return getList().size();
}
#Override
public Unit invoke(CombinedLoadStates states) {
LoadState refresh = states.getRefresh();
LoadState append = states.getAppend();
if (refresh instanceof LoadState.Error || append instanceof LoadState.Error) {
//The previous load (either initial or additional) failed
Log.d(TAG, "[Paging adapter] An error occurred while loading the data");
if (mTryCount < 3) {
mTryCount += 1;
retry();
}
}
if (refresh instanceof LoadState.Loading) {
Log.d(TAG, "[Paging adapter] Loading initial data");
}
if (append instanceof LoadState.Loading) {
Log.d(TAG, "[Paging adapter] Loading more data");
}
if (append instanceof LoadState.NotLoading) {
LoadState.NotLoading notLoading = (LoadState.NotLoading) append;
if (notLoading.getEndOfPaginationReached()) {
Log.d(TAG, "[Paging adapter] No further documents");
mTryCount = 0;
return null;
}
if (refresh instanceof LoadState.NotLoading) {
Log.d(TAG, "[Paging adapter] Data loading finished");
mTryCount = 0;
List<T> items = new ArrayList<>();
if (mReverseFill) {
for (int i = snapshot().size() - 1; i >= 0; i--) {
T currentItem = mParser.parseSnapshot(snapshot().get(i));
if (getList().indexOf(currentItem) == SortedList.INVALID_POSITION)
items.add(currentItem);
}
} else {
for (DocumentSnapshot snapshot : snapshot()) {
T currentItem = mParser.parseSnapshot(snapshot);
if (getList().indexOf(currentItem) == SortedList.INVALID_POSITION)
items.add(currentItem);
}
}
addAll(items);
return null;
}
}
return null;
}
public void addAll(Collection<T> items) {
getList().beginBatchedUpdates();
getList().addAll(items);
getList().endBatchedUpdates();
}
public abstract static class PagingAdapterCallback<T extends RecyclerItem> {
public abstract int compare(T o1, T o2);
public abstract boolean areContentsTheSame(T oldItem, T newItem);
public abstract boolean areItemsTheSame(T item1, T item2);
}
}
Just in case you wonder. These are the other two wrapper:
public abstract class RecyclerViewHolder<T extends RecyclerItem, E extends ViewBinding> extends RecyclerView.ViewHolder {
public final String TAG = this.getClass().getSimpleName();
protected final E b;
private final Context mContext;
protected RecyclerViewHolder(#NonNull E b) {
super(b.getRoot());
this.b = b;
this.mContext = b.getRoot().getContext();
}
public abstract void bind(T item);
protected Context getContext() {
return mContext;
}
protected Context requireContext() {
return getContext();
}
protected String getString(int resId) {
return mContext.getString(resId);
}
protected String getString(int resId, Object... args) {
return mContext.getString(resId, args);
}
}
and
public interface RecyclerItem {
#NonNull
RecyclerItemType getRecyclerItemType();
default void setRecyclerItemType(RecyclerItemType type){
//Does not do anything per default
}
}
When I update my Code to androidx I get this error
"error: method setCurrentItemInternal in class ViewPager cannot be applied to given types;
required: int,boolean,boolean,int
found: int,boolean,boolean
reason: actual and formal argument lists differ in length"
Code:
public class NonRestoringViewPager extends ViewPager implements setCurrentItemInternal {
private boolean isRestoring = false;
private final boolean useDefaultImplementation;
public NonRestoringViewPager(Context context) {
super(context);
useDefaultImplementation =
!QuranUtils.isDualPagesInLandscape(context, QuranScreenInfo.getOrMakeInstance(context));
}
public NonRestoringViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
useDefaultImplementation =
!QuranUtils.isDualPagesInLandscape(context, QuranScreenInfo.getOrMakeInstance(context));
}
#Override
public void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {
if (useDefaultImplementation || !isRestoring) {
super.setCurrentItemInternal(item, smoothScroll, always);
}
}
#Override
public void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
if (useDefaultImplementation || !isRestoring) {
super.setCurrentItemInternal(item, smoothScroll, always, velocity);
}
}
#Override
public void onRestoreInstanceState(Parcelable state) {
isRestoring = true;
super.onRestoreInstanceState(state);
isRestoring = false;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
try {
return super.onTouchEvent(ev);
} catch (IllegalArgumentException e) {
return false;
}
}
}
Function signature might have changed in androidx dependencies. So check the function signature and pass required params values.
I'm brand new to Android programming and I'm trying to create a full screen Android Wear interface with custom layouts and no cards. I'm trying to go off the sample but I can't figure out how to get around using CardFragments. My MainActivity code is essentially identical to the example, with a few names changed. Here is the code for my GridViewPagerAdaper:
public class MyGridViewPagerAdapter extends FragmentGridPagerAdapter {
private final Context mContext;
public MyGridViewPagerAdapter(Context ctx, FragmentManager fm) {
super(fm);
mContext = ctx;
}
static final int[] BG_IMAGES = new int[]{
R.drawable.bg,
};
/**
* A simple container for static data in each page
*/
private static class Page {
int titleRes;
int textRes;
int iconRes;
int cardGravity = Gravity.BOTTOM;
boolean expansionEnabled = true;
float expansionFactor = 1.0f;
int expansionDirection = CardFragment.EXPAND_DOWN;
public Page(int titleRes) {
this.titleRes = titleRes;
this.textRes = textRes;
this.iconRes = iconRes;
}
public Page(int titleRes, int textRes, int iconRes, int gravity) {
this.titleRes = titleRes;
this.textRes = textRes;
this.iconRes = iconRes;
this.cardGravity = gravity;
}
}
private final Page[][] PAGES = {
{
new Page(R.drawable.tuner),
},
{
new Page(R.drawable.metronome),
new Page(R.drawable.metroplain)
},
};
#Override
public Fragment getFragment(int row, int col) {
Page page = PAGES[row][col];
// String title = page.titleRes != 0 ? mContext.getString(page.titleRes) : null;
// String text = page.textRes != 0 ? mContext.getString(page.textRes) : null;
CardFragment fragment = CardFragment.create("", "", page.iconRes);
// Advanced settings
fragment.setCardGravity(page.cardGravity);
fragment.setExpansionEnabled(page.expansionEnabled);
fragment.setExpansionDirection(page.expansionDirection);
fragment.setExpansionFactor(page.expansionFactor);
return fragment;
}
#Override
public ImageReference getBackground(int row, int column) {
return ImageReference.forDrawable(BG_IMAGES[row % BG_IMAGES.length]);
}
#Override
public int getRowCount() {
return PAGES.length;
}
#Override
public int getColumnCount(int rowNum) {
return PAGES[rowNum].length;
}
}
What's the best way to get rid of the cards and use a custom layout? Thanks for your help.
In your adapter, give your fragments as following:
private final Activity mContext;
private final Fragment[][] mFragment;
public MyGridViewPagerAdapter(Activity ctx, FragmentManager fm, Fragment[][] fragments)
{
super(fm);
mContext = ctx;
this.mFragment = fragments;
}
then override the following methods:
#Override
public Fragment getFragment(int row, int col)
{
return mFragment[row][col];
}
#Override
public int getRowCount()
{
return mFragment.length;
}
#Override
public int getColumnCount(int rowNum)
{
return mFragment[rowNum].length;
}
then in your activity do as following:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
final GridViewPager pager = (GridViewPager) findViewById(R.id.pager);
final Fragment[][] items = {
{
CusmtomFragment.newInstance("your","arguments"),
CusmtomFragment.newInstance()
},
{
OtherFragment.newInstance(),
AnotherFragment.newInstance(1234)
}
};
// ....
pager.setAdapter(new MyGridViewPagerAdapter(this, getFragmentManager(), items));
}
Hope it helps !
If you implement a custom wearable app you can do what you want including a custom UI.
The problems are more to Is there any way to detect if the clock is round?
Or how to start the app you n the wearable. This is done with a special service. Basically you is the dataApi for that.
I have been trying for a while to implement a Game Thread to utilise a loop to implement logic. I posted a question here not long ago, I hope no one minds the follow up.
I have managed to scrape together this code from my research:
public class GameView extends SurfaceView implements SurfaceHolder.Callback
{
class GameThread extends Thread
{
//states
public static final int STATE_LOSE = 1;
public static final int STATE_PAUSE = 2;
public static final int STATE_READY = 3;
public static final int STATE_RUNNING = 4;
private Paint m_paint;
//canvas dimensions
private int m_canvasWidth;
private int m_canvasHeight;
private long m_lastTime;
private boolean m_run = false;
private int m_mode;
public ImageView ship;
RelativeLayout.LayoutParams shipParams;
// Handle to the surface manager
private SurfaceHolder m_surfaceHolder;
public GameThread(SurfaceHolder surfaceHolder, Context context, Handler handler)
{
m_surfaceHolder = surfaceHolder;
}
//Initialise the game
public void doStart()
{
synchronized (m_surfaceHolder)
{
resetGame();
m_lastTime = System.currentTimeMillis() + 100;
setState(STATE_RUNNING);
ship = (ImageView) findViewById(R.id.imageView1);
shipParams = (RelativeLayout.LayoutParams)ship.getLayoutParams();
}
}
public void pause()
{
synchronized (m_surfaceHolder)
{
if (m_mode == STATE_RUNNING)
setState(STATE_PAUSE);
}
}
#Override
public void run()
{
while (m_run)
{
Canvas c = null;
try
{
c = m_surfaceHolder.lockCanvas(null);
synchronized (m_surfaceHolder)
{
if (m_mode == STATE_RUNNING)
{
updateGame();
}
doDraw(c);
}
}
catch(Exception e){}
finally
{
if (c != null)
{
m_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
public void setRunning(boolean b)
{
m_run = b;
}
public void setState(int mode)
{
synchronized (m_surfaceHolder)
{
setState(mode, null);
}
}
public void setState(int mode, CharSequence message)
{
synchronized (m_surfaceHolder)
{
m_mode = mode;
}
}
public void setPlayers(boolean onePlayer)
{
}
public void setSurfaceSize(int width, int height)
{
synchronized (m_surfaceHolder)
{
m_canvasWidth = width;
m_canvasHeight = height;
}
}
public void unpause()
{
synchronized (m_surfaceHolder)
{
m_lastTime = System.currentTimeMillis() + 100;
}
setState(STATE_RUNNING);
}
private void doDraw(Canvas canvas)
{
canvas.drawARGB(255, 0, 0, 0);
}
private void updateGame()
{
long now = System.currentTimeMillis();
if (m_lastTime > now)
return;
double elapsed = (now - m_lastTime) / 1000.0;
m_lastTime = now;
System.out.print("HELLO WORLD");
shipParams.topMargin++;
ship.setLayoutParams(shipParams);
}
private boolean collided(Rect rectangle)
{
return false;
}
public boolean foundWinner()
{
return false;
}
public void resetGame()
{
}
public void handleInput(MotionEvent event)
{
}
}
private Context m_context;
private GameThread m_thread;
private Handler m_handler;
public GameView(Context context, AttributeSet attrs)
{
super(context, attrs);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
m_handler = new Handler() {
#Override
public void handleMessage(Message m) {
Bundle b = m.getData();
MotionEvent e = b.getParcelable("event");
m_thread.handleInput(e);
}
};
m_thread = new GameThread(holder, context, m_handler);
setFocusable(true);
};
public GameThread getThread()
{
return m_thread;
}
#Override
public void onWindowFocusChanged(boolean hasWindowFocus)
{
if (!hasWindowFocus)
m_thread.pause();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
m_thread.setSurfaceSize(width, height);
}
public void surfaceCreated(SurfaceHolder holder)
{
if(m_thread.getState() == State.TERMINATED)
{
m_thread = new GameThread(getHolder(), m_context, m_handler);
m_thread.setRunning(true);
m_thread.start();
m_thread.doStart();
}
else
{
m_thread.setRunning(true);
m_thread.start();
}
}
public void surfaceDestroyed(SurfaceHolder holder)
{
boolean retry = true;
m_thread.setRunning(false);
while (retry)
{
try
{
m_thread.join();
retry = false;
}
catch (InterruptedException e)
{
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
return true;
}
}
I am fairly certain that my issue lies here and it is merely a logical one. Everything does seem fine to me, however and I am in need of assistance.
I have attempted to draw an image at line 47 and defined a movement to take place in the update method at line 153. I also have placed a print line for extra debug, but the line doesn't show.
I am stumped.
Any help would be great, thanks.
Here are my other codes, if neccessary:
MainActivity.java
GameSetup.java
game_setup.xml
edit: I should note that I'm not getting any kind of errors within the code, it merely doesn't respond
You are initializing m_run as false,then in the while cycle in the run() method you must have set to true. Change it to true and the thread will work normally.
set m_run to true in your doStart() procedure