Я установил кнопку, которая предназначена для проверки разрешений READ_EXTERNAL_STORAGE
, а затем открываю изображения для отображения в памяти телефона пользователей. Я успешно сделал это с помощью следующего кода:
Все это отлично работает с первой попытки. Пользователь видит диалоговое окно разрешений, нажимает кнопку «Согласиться», и открывается селектор изображений, отображающий изображения на его телефоне! Однако во второй раз, когда мы пытаемся использовать ту же кнопку, приложение вылетает. Итак, в основном после предоставления разрешений приложение вылетает каждый раз при нажатии кнопки.
Отображается следующая ошибка:
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); */
}
}
Я выполнил журнал d, чтобы определить, где он не работает, см. предыдущий код для просмотра журнала. d.
Как я могу решить эту проблему?
РЕДАКТИРОВАТЬ:
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();
}