I have set up a button that is meant to check for READ_EXTERNAL_STORAGE
permissions, and then open the users phone storage display images. I’ve done this successfully via the following code:
All of this works perfectly on the first try. The user sees the permission dialog box, presses agree and the image selector opens displaying images on their phone! However, the second time we try to use the same button the app crashes. So basically after the permissions are granted the app crashes every time the button is pressed.
The following error is displayed:
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.memory.pod.debug, PID: 26684 java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.PackageManager android.content.Context.getPackageManager()' on a null object reference at android.content.ContextWrapper.getPackageManager(ContextWrapper.java:98) at com.memory.pod.camerax.ui.home.HomeActivity.selectImage(HomeActivity.java:144) at com.memory.pod.camerax.ui.home.HomeActivity.openFileChooser(HomeActivity.java:137) at com.memory.pod.view.BottomTabView$4.onClick(BottomTabView.java:84) at android.view.View.performClick(View.java:7259) at android.view.View.performClickInternal(View.java:7236) at android.view.View.access$3600(View.java:801) at android.view.View$PerformClick.run(View.java:27892) at android.os.Handler.handleCallback(Handler.java:883) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7356) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
BottomTabView.java
public class BottomTabView extends FrameLayout implements ViewPager.OnPageChangeListener { // Initialize content private ImageView mCenterImageView; private ImageView mBottomImageView; private LinearLayout mStartImageView; private LinearLayout mEndImageView; private View mIndicator; private ArgbEvaluator mArgbEvaluator; private int mCenterColor; private int mSideColor; private int mEndViewsTranslationX; private int mIndicatorTranslationX; private int mCenterTranslationY; public BottomTabView(@NonNull Context context) { this(context, null); } public BottomTabView(@NonNull Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public BottomTabView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public void setUpWithViewPager(ViewPager viewPager) { viewPager.addOnPageChangeListener(this); mStartImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if (viewPager.getCurrentItem() != 0) viewPager.setCurrentItem(0); } }); mCenterImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if (viewPager.getCurrentItem() != 1) viewPager.setCurrentItem(1); } }); mEndImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if (viewPager.getCurrentItem() != 2) viewPager.setCurrentItem(2); } }); mBottomImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if (viewPager.getCurrentItem() == 1) { HomeActivity.openFileChooser(getContext()); } } }); } private void init() { LayoutInflater.from(getContext()).inflate(R.layout.view_bottom_tabs, this, true); // Initialize bottom tab view content mCenterImageView = findViewById(R.id.view_bottom_tabs_camera_iv); mStartImageView = findViewById(R.id.view_bottom_tabs_start_linear_layout); mEndImageView = findViewById(R.id.view_bottom_tabs_end_linear_layout); mBottomImageView = findViewById(R.id.view_bottom_tabs_gallery_iv); // Initialize bottom tab view indicator, meant to indicate the current tab in view mIndicator = findViewById(R.id.view_bottom_tabs_indicator); // Set start color and end color for tab view icons mCenterColor = ContextCompat.getColor(getContext(), R.color.white); mSideColor = ContextCompat.getColor(getContext(), R.color.black); // Evaluate the difference between colors mArgbEvaluator = new ArgbEvaluator(); // Change the padding of tab icons based on view // This is the min padding accepted (0) mIndicatorTranslationX = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 140, getResources().getDisplayMetrics()); // Wait till GalleryImageView has been drawn, once GalleryImageView is drawn then proceed with relative padding calculation mBottomImageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // Change padding relative to other icons mEndViewsTranslationX = (int)((mBottomImageView.getX() - mStartImageView.getX()) - mIndicatorTranslationX); mBottomImageView.getViewTreeObserver().removeOnGlobalLayoutListener(this); // Change the position of the center image mCenterTranslationY = getHeight() - mBottomImageView.getBottom(); } }); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { if (position == 0) { // Change color of icons based on view setColor(1 - positionOffset); // Move the start and end images moveViews(1 - positionOffset); // Change indicator position mIndicator.setTranslationX((positionOffset - 1) * mIndicatorTranslationX); // Change scale of center image moveAndScaleCenter(1 - positionOffset); } else if (position == 1) { // Change color of icons based on view setColor(positionOffset); // Move the start and end images moveViews(positionOffset); // Change indicator position mIndicator.setTranslationX(positionOffset * mIndicatorTranslationX); // Change scale of center image moveAndScaleCenter(positionOffset); } } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { } private void moveAndScaleCenter(float fractionFromCenter) { float scale = .7 f + ((1 - fractionFromCenter) * .3 f); // Change scale of center image mCenterImageView.setScaleX(scale); mCenterImageView.setScaleY(scale); int translation = (int)(fractionFromCenter * mCenterTranslationY * 2); // Move center image down mCenterImageView.setTranslationY(translation); mBottomImageView.setTranslationY(translation); // Fadeout bottom image mBottomImageView.setAlpha(1 - fractionFromCenter); } private void moveViews(float fractionFromCenter) { mStartImageView.setTranslationX(fractionFromCenter * mEndViewsTranslationX); mEndImageView.setTranslationX(-fractionFromCenter * mEndViewsTranslationX); mIndicator.setAlpha(fractionFromCenter); mIndicator.setScaleX(fractionFromCenter); } private void setColor(float fractionFromCenter) { int color = (int) mArgbEvaluator.evaluate(fractionFromCenter, mCenterColor, mSideColor); /* mCenterImageView.setColorFilter(color); mStartImageView.setColorFilter(color); mEndImageView.setColorFilter(color); mBottomImageView.setColorFilter(color); */ } }
I did a log.d to identify where it fails, please refer to previous code to see log.d.
How can I overcome this issue?
EDIT:
HomeActivity:
public class HomeActivity extends AppCompatActivity { // Initialize image picker private static final int PICK_IMAGE_REQUEST = 1; private static final int REQUEST_CODE_STORAGE_PERMISSION = 1; private static final int REQUEST_CODE_SELECT_IMAGE = 2; // TODO: FIREBASE TEMPORARY LOGOUT private static FirebaseAuth mAuth; private static final String TAG = "HomeActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); // Initialize views View background = findViewById(R.id.background_view); ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager); // Initialize adapter HomePagerAdapter adapter = new HomePagerAdapter(getSupportFragmentManager()); viewPager.setAdapter(adapter); // Initialize BottomTabView BottomTabView bottomTabView = findViewById(R.id.bottom_tabs); bottomTabView.setUpWithViewPager(viewPager); // Initialize TopSearchView TopSearchView topSearchView = findViewById(R.id.top_search); topSearchView.setUpWithViewPager(viewPager); // Initialize TopProfilePictureView TopProfilePictureView topProfilePictureView = findViewById(R.id.top_profile_picture); topProfilePictureView.setUpWithViewPager(viewPager); // Initialize TopVariableFunctionalityButtonView TopVariableFunctionalityButtonView topVariableFunctionalityButtonView = findViewById(R.id.top_variable_functionality_button); topVariableFunctionalityButtonView.setUpWithViewPager(viewPager); // Initialize color for fade effect final int windowBackgroundColor = ContextCompat.getColor(this, R.color.windowBackground); final int blackBackgroundColor = ContextCompat.getColor(this, R.color.black); // Set the default position of the viewPager viewPager.setCurrentItem(1); // TODO: Initialize Firebase (TEMPORARY) //Initialize Firebase Auth mAuth = FirebaseAuth.getInstance(); bottomTabView.setOnBottomTabViewClickListener(new BottomTabViewClickListener() { @Override public void onClick(View v) { // call your openFileChooser from here, //REMOVE THE STATIC openFileChooser(HomeActivity.this); } }); // Callback each time the fragment is changed viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { if (position == 0) { background.setBackgroundColor(windowBackgroundColor); background.setAlpha(1 - positionOffset); } else if (position == 1) { background.setBackgroundColor(blackBackgroundColor); background.setAlpha(positionOffset); } } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { } }); } // Choose file extended from BottomTabView, opens all images on device // Check for permissions before hand public void openFileChooser(Context context) { Log.d("HomeActivity", "This is the last place a log is observed"); if (ContextCompat.checkSelfPermission(getInstance().getApplicationContext(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions( ((Activity) context), new String[] { Manifest.permission.READ_EXTERNAL_STORAGE }, REQUEST_CODE_STORAGE_PERMISSION ); } else { selectImage(); } } // Open image selector via phone storage private void selectImage() { Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); if (intent.resolveActivity(getPackageManager()) != null) { startActivityForResult(intent, REQUEST_CODE_SELECT_IMAGE); } } // Request permission results @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_CODE_STORAGE_PERMISSION && grantResults.length > 0) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { selectImage(); } else { Toast.makeText(this, "Permission Denied!", Toast.LENGTH_SHORT).show(); } } } // TODO: Is it better to use bitmap or URI // Check if user has selected file and describe next step @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE_SELECT_IMAGE && resultCode == RESULT_OK) { if (data != null) { // Get image URI Uri selectedImageUri = data.getData(); if (selectedImageUri != null) { try { InputStream inputStream = getContentResolver().openInputStream(selectedImageUri); Bitmap bitmap = BitmapFactory.decodeStream(inputStream); // Do something with image // Identify the selected image file, pass onto firebase File selectedImageFile = new File(getPathFormUri(selectedImageUri)); } catch (Exception exception) { Toast.makeText(this, exception.getMessage(), Toast.LENGTH_SHORT).show(); } } } } } private String getPathFormUri(Uri contentUri) { String filePath; Cursor cursor = getContentResolver() .query(contentUri, null, null, null, null); if (cursor == null) { filePath = contentUri.getPath(); } else { cursor.moveToFirst(); int index = cursor.getColumnIndex("_data"); filePath = cursor.getString(index); cursor.close(); } return filePath; } // TODO: TEMPORARY LOGOUT public static void logoutUser(Context context) { mAuth.signOut(); } } BottomTabActivity: public class BottomTabView extends FrameLayout implements ViewPager.OnPageChangeListener { // Initialize content BottomTabViewClickListener bottomTabViewClickListener; private ImageView mCenterImageView; private ImageView mBottomImageView; private LinearLayout mStartImageView; private LinearLayout mEndImageView; private View mIndicator; private ArgbEvaluator mArgbEvaluator; private int mCenterColor; private int mSideColor; private int mEndViewsTranslationX; private int mIndicatorTranslationX; private int mCenterTranslationY; //add this function somewhere public void setOnBottomTabViewClickListener(BottomTabViewClickListener bottomTabViewClickListener) { this.bottomTabViewClickListener = bottomTabViewClickListener; } public BottomTabView(@NonNull Context context) { this(context, null); } public BottomTabView(@NonNull Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public BottomTabView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public void setUpWithViewPager(ViewPager viewPager) { viewPager.addOnPageChangeListener(this); mStartImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if (viewPager.getCurrentItem() != 0) viewPager.setCurrentItem(0); } }); mCenterImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if (viewPager.getCurrentItem() != 1) viewPager.setCurrentItem(1); } }); mEndImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if (viewPager.getCurrentItem() != 2) viewPager.setCurrentItem(2); } }); mBottomImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if (viewPager.getCurrentItem() == 1) { } } }); } private void init() { LayoutInflater.from(getContext()).inflate(R.layout.view_bottom_tabs, this, true); // Initialize bottom tab view content mCenterImageView = findViewById(R.id.view_bottom_tabs_camera_iv); mStartImageView = findViewById(R.id.view_bottom_tabs_start_linear_layout); mEndImageView = findViewById(R.id.view_bottom_tabs_end_linear_layout); mBottomImageView = findViewById(R.id.view_bottom_tabs_gallery_iv); // Initialize bottom tab view indicator, meant to indicate the current tab in view mIndicator = findViewById(R.id.view_bottom_tabs_indicator); // Set start color and end color for tab view icons mCenterColor = ContextCompat.getColor(getContext(), R.color.white); mSideColor = ContextCompat.getColor(getContext(), R.color.black); // Evaluate the difference between colors mArgbEvaluator = new ArgbEvaluator(); // Change the padding of tab icons based on view // This is the min padding accepted (0) mIndicatorTranslationX = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 140, getResources().getDisplayMetrics()); // Wait till GalleryImageView has been drawn, once GalleryImageView is drawn then proceed with relative padding calculation mBottomImageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // Change padding relative to other icons mEndViewsTranslationX = (int)((mBottomImageView.getX() - mStartImageView.getX()) - mIndicatorTranslationX); mBottomImageView.getViewTreeObserver().removeOnGlobalLayoutListener(this); // Change the position of the center image mCenterTranslationY = getHeight() - mBottomImageView.getBottom(); } }); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { if (position == 0) { // Change color of icons based on view setColor(1 - positionOffset); // Move the start and end images moveViews(1 - positionOffset); // Change indicator position mIndicator.setTranslationX((positionOffset - 1) * mIndicatorTranslationX); // Change scale of center image moveAndScaleCenter(1 - positionOffset); } else if (position == 1) { // Change color of icons based on view setColor(positionOffset); // Move the start and end images moveViews(positionOffset); // Change indicator position mIndicator.setTranslationX(positionOffset * mIndicatorTranslationX); // Change scale of center image moveAndScaleCenter(positionOffset); } } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { } private void moveAndScaleCenter(float fractionFromCenter) { float scale = .7 f + ((1 - fractionFromCenter) * .3 f); // Change scale of center image mCenterImageView.setScaleX(scale); mCenterImageView.setScaleY(scale); int translation = (int)(fractionFromCenter * mCenterTranslationY * 2); // Move center image down mCenterImageView.setTranslationY(translation); mBottomImageView.setTranslationY(translation); // Fadeout bottom image mBottomImageView.setAlpha(1 - fractionFromCenter); } private void moveViews(float fractionFromCenter) { mStartImageView.setTranslationX(fractionFromCenter * mEndViewsTranslationX); mEndImageView.setTranslationX(-fractionFromCenter * mEndViewsTranslationX); mIndicator.setAlpha(fractionFromCenter); mIndicator.setScaleX(fractionFromCenter); } private void setColor(float fractionFromCenter) { int color = (int) mArgbEvaluator.evaluate(fractionFromCenter, mCenterColor, mSideColor); /* mCenterImageView.setColorFilter(color); mStartImageView.setColorFilter(color); mEndImageView.setColorFilter(color); mBottomImageView.setColorFilter(color); */ } } interface BottomTabViewClickListener { public void onClick(); }
Advertisement
Answer
Your else statement is currently like this, which means you are trying to create a new instance of HomeActivity and call selectimage(), and it does not work that way.
else { new HomeActivity().selectImage(); }
Please, change it to
else{ selectImage(); }
Please, try this, this should solve your problem.
EDIT: Use of interface and listener pattern
In your BottomTabView add the following
public class BottomTabView extends FrameLayout implements ViewPager.OnPageChangeListener { // Initialize content // add this at top level. BottomTabViewClickListener bottomTabViewClickListener; //add this function somewhere public void setOnBottomTabViewClickListener(BottomTabViewClickListener bottomTabViewClickListener){ this.bottomTabViewClickListener = bottomTabViewClickListener; } // replace HomeActivity.openFileChooser(getContext()); mBottomImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if (viewPager.getCurrentItem() == 1) { bottomTabViewClickListener.onClick(); } } }); } //end of BottomTab View //add this after your BottomTabView not inside interface BottomTabViewClickListener{ public void onClick(); }
Add the following in your HomeActivity
// Initialize BottomTabView BottomTabView bottomTabView = findViewById(R.id.bottom_tabs); bottomTabView.setUpWithViewPager(viewPager); bottomTabView.setOnBottomTabViewClickListener(new BottomTabViewClickListener() { @Override public void onClick() { // call your openFileChooser from here, //REMOVE THE STATIC openFileChooser(HomeActivity.this) } });