Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialtshuutheniemvula
7,251 PointsChoose Picture and Video intent calls not attaching data to message, returns null and I can't figure out why exactly.
Take Photo and Video works like a charm but Choose Photo or Video returns null to main activity with no errors caught or error toasts.
Logcat states:
/com.blabla.ribbit E/ViewRootImpl﹕ sendUserActionEvent() mView == null
which leads me to think data is not being attached to intent upon choosing of picture or video
My MainActivity code follows:
public class MyActivity extends FragmentActivity implements ActionBar.TabListener {
public static String TAG = MyActivity.class.getSimpleName();
public static final int TAKE_PHOTO_REQUEST = 0;
public static final int TAKE_VIDEO_REQUEST = 1;
public static final int PICK_PHOTO_REQUEST = 2;
public static final int PICK_VIDEO_REQUEST = 3;
public static final int MEDIA_TYPE_IMAGE = 4;
public static final int MEDIA_TYPE_VIDEO = 5;
public static final int FILE_SIZE_LIMIT = 1024*1024*10; //10MB
protected Uri mMediaUri;
protected DialogInterface.OnClickListener mDialogListener =
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
switch (i) {
case 0: //Picture
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
mMediaUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
if (mMediaUri == null){
//display error
Toast.makeText(MyActivity.this, R.string.error_external_storage, Toast.LENGTH_LONG).show();
}
else{
takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mMediaUri);
startActivityForResult(takePhotoIntent, TAKE_PHOTO_REQUEST);
}
break;
case 1: //Video
Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
mMediaUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO);
mMediaUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
if (mMediaUri == null) {
//display error
Toast.makeText(MyActivity.this, R.string.error_external_storage, Toast.LENGTH_LONG).show();
}
else{
takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mMediaUri);
takeVideoIntent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10);
takeVideoIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
startActivityForResult(takeVideoIntent,TAKE_VIDEO_REQUEST);
}
break;
case 2: //Choose Pic
Intent choosePhotoIntent = new Intent(Intent.ACTION_GET_CONTENT);
choosePhotoIntent.setType("image/*");
startActivityForResult(choosePhotoIntent, PICK_PHOTO_REQUEST);
break;
case 3: //Choose Video
Intent chooseVideoIntent = new Intent(Intent.ACTION_GET_CONTENT);
chooseVideoIntent.setType("video/*");
Toast.makeText(MyActivity.this,getString(R.string.video_message), Toast.LENGTH_LONG).show();
startActivityForResult(chooseVideoIntent, PICK_VIDEO_REQUEST);
break;
}
}
private Uri getOutputMediaFileUri(int mediaType) {
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
if (isExternalStorageAvailable()) {
//Get Uri
//1. Get ex storage directory
String appName = MyActivity.this.getString(R.string.app_name);
File mediaStorageDir = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), appName);
//2. Create own subdirectory
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.e(TAG, "Failed to create directory");
return null;
}
}
//3.Create file name
//4.Create the file
File mediaFile;
Date now = new Date();
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(now);
String path = mediaStorageDir.getPath() + File.separator;
if (mediaType == MEDIA_TYPE_IMAGE) {
mediaFile = new File(path + "IMG_" + timestamp + ".jpeg");
} else if (mediaType == MEDIA_TYPE_VIDEO) {
mediaFile = new File(path + "VID_" + timestamp + ".mp4");
} else {
return null;
}
Log.d(TAG, "File" + Uri.fromFile(mediaFile));
//5. return file's Uri
return Uri.fromFile(mediaFile);
}
else {
return null;
}
}
private boolean isExternalStorageAvailable() {
String state = Environment.getExternalStorageState();
if (state.equals(Environment.MEDIA_MOUNTED)){
return true;
}
else{
return false;
}
}
};
/**
* The {@link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {@link FragmentPagerAdapter} derivative, which will keep every
* loaded fragment in memory. If this becomes too memory intensive, it
* may be best to switch to a
* {@link android.support.v13.app.FragmentStatePagerAdapter}.
*/
SectionsPagerAdapter mSectionsPagerAdapter;
/**
* The {@link ViewPager} that will host the section contents.
*/
ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_my);
ParseAnalytics.trackAppOpened(getIntent());
//ParseUser.logOut();
ParseUser currentUser = ParseUser.getCurrentUser();
if(currentUser==null){
GoToLogin();
}
else{
Log.i(TAG, currentUser.getUsername());
}
// Set up the action bar.
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(this,getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
// When swiping between different sections, select the corresponding
// tab. We can also use ActionBar.Tab#select() to do this if we have
// a reference to the Tab.
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
// Create a tab with text corresponding to the page title defined by
// the adapter. Also specify this Activity object, which implements
// the TabListener interface, as the callback (listener) for when
// this tab is selected.
actionBar.addTab(
actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this));
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == PICK_PHOTO_REQUEST || requestCode == PICK_VIDEO_REQUEST) {
if (data == null) {
Toast.makeText(this, getString(R.string.general_error), Toast.LENGTH_LONG).show();
} else {
mMediaUri = data.getData();
}
if (requestCode == PICK_VIDEO_REQUEST) {
//make sure file less than 10MB
int fileSize = 0;
InputStream inputStream = null;
try {
inputStream = getContentResolver().openInputStream(mMediaUri);
fileSize = inputStream.available();
} catch (FileNotFoundException e) {
Toast.makeText(this, getString(R.string.filesize_error), Toast.LENGTH_LONG).show();
return;
} catch (IOException e) {
Toast.makeText(this, getString(R.string.filesize_error), Toast.LENGTH_LONG).show();
return;
} finally {
try {
inputStream.close();
} catch (IOException e) {
}
}
if (fileSize >= FILE_SIZE_LIMIT) {
Toast.makeText(this, getString(R.string.file_size_warning), Toast.LENGTH_LONG).show();
return;
}
}
} else {
//add to gallery
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(mMediaUri);
String fileType;
if (requestCode == PICK_VIDEO_REQUEST || requestCode == TAKE_VIDEO_REQUEST) {
fileType = ParseConstants.TYPE_VIDEO;
} else {
fileType = ParseConstants.TYPE_IMAGE;
}
sendBroadcast(mediaScanIntent);
Intent recipientIntent = new Intent(this, RecipientsActivity.class);
recipientIntent.setData(mMediaUri);
recipientIntent.putExtra(ParseConstants.KEY_FILE_TYPE, fileType);
startActivity(recipientIntent);
}
}
else if(resultCode != RESULT_CANCELED){
Toast.makeText(this,R.string.general_error, Toast.LENGTH_LONG).show();
}
}
private void GoToLogin() {
Intent intent = new Intent(this,LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.my, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
switch(item.getItemId()){
case R.id.action_logout_item:
ParseUser.logOut();
GoToLogin();
break;
case R.id.action_edit_friends:
Intent intent = new Intent(this, EditFriendsActivity.class);
startActivity(intent);
break;
case R.id.action_camera:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setItems(R.array.camera_choices, mDialogListener);
AlertDialog dialog = builder.create();
dialog.show();
return super.onOptionsItemSelected(item);
default: return super.onOptionsItemSelected(item);
}
return super.onOptionsItemSelected(item);
}
@Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in
// the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
@Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
}
Could it be one of the statements being excluded in onActivityforResult?
14 Answers
Steve Hunter
57,712 PointsThis works.
I don't have a network error so I don't call the AlertDialog.Builder()
block, so I'm of no use, unfortunately.
But, despite it being a little clunky in places (which will be fixed as you finish the app) it works fine. Although, I'm not receiving messages in the Inbox. You may have as I've been sending my messages to everyone on the Friends list! ;-)
I have installed this on a device, a Sony Xperia Z, and it is working OK. To try to replicate the error takes some doing. I tried to send a message in Flight Mode; that won't work as the Friends List is populated on the fly. So, I chose the image to send, selected recipients THEN put it in flight mode and hit send. Yes, I get the error you get but my code errors at the end of the callback block - not at the .show() line.
This might be a Parse issue, rather than a code one?
I've sent a few messages; they're not appearing so maybe you've not got that far yet. But this seems to work fine. There's the odd error creeping in but I think that's more a package name issue which is confusing Gradle and my Mac generally!
But this looks good - I don't know what else to say!
Steve Hunter
57,712 PointsHi,
To make the code a little easier to read, could you add three ` marks (I'm not sure what it is called - it is the reverse apostrophe mark) before the start of the code and then a further three after. If at the three beginning ones you add the word java, the post will be formatted a little more clearly.
It then looks like:
@Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
Also, where is the code for startActivityForResult()
- I can't see it but I can see that it is called in a few places. I'll have a look through onActivityForResult
to see if your suspicions are correct!
Steve Hunter
57,712 PointsHi again,
In onActivityResult()
you start by checking the resultCode
is OK then move on to check requestCode
. In that If
statement, you're checking to see if the request is a PICK, rather than a TAKE. That's fine. It is checking whether the requestCode
is either a PICK_PHOTO or PICK_VIDEO.
However, in the else
of this if
statement, you then go on to check whether the requestCode
is a PICK or TAKE video. That seems at odds to the starting conditions? I'd expect to see the two tAKE options down there so as to be mutually exclusive of the initial conditional?
Hope that helps - I may be wrong, obviously!!
tshuutheniemvula
7,251 PointsHi Steve,
Am actually only seeing this reply now and had come to the same conclusion myself. I now changed onActivitResult to the following but still getting an uncaught exception error just before it toasts 'message sent' on either a PICK_VIDEO or TAKE_VIDEO request:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == PICK_PHOTO_REQUEST || requestCode == PICK_VIDEO_REQUEST) {
if (data == null) {
Toast.makeText(this, getString(R.string.general_error), Toast.LENGTH_LONG).show();
} else {
mMediaUri = data.getData();
}
if (requestCode == PICK_VIDEO_REQUEST) {
//make sure file less than 10MB
int fileSize = 0;
InputStream inputStream = null;
try {
inputStream = getContentResolver().openInputStream(mMediaUri);
fileSize = inputStream.available();
} catch (FileNotFoundException e) {
Toast.makeText(this, getString(R.string.filesize_error), Toast.LENGTH_LONG).show();
return;
} catch (IOException e) {
Toast.makeText(this, getString(R.string.filesize_error), Toast.LENGTH_LONG).show();
return;
} finally {
try {
inputStream.close();
} catch (IOException e) {
}
}
if (fileSize >= FILE_SIZE_LIMIT) {
Toast.makeText(this, getString(R.string.file_size_warning), Toast.LENGTH_LONG).show();
return;
}
}
} else {
//add to gallery
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(mMediaUri);
sendBroadcast(mediaScanIntent);
}
Intent recipientIntent = new Intent(this, RecipientsActivity.class);
recipientIntent.setData(mMediaUri);
String fileType;
if (requestCode == PICK_PHOTO_REQUEST || requestCode == TAKE_PHOTO_REQUEST) {
fileType = ParseConstants.TYPE_IMAGE;
} else {
fileType = ParseConstants.TYPE_VIDEO;
}
recipientIntent.putExtra(ParseConstants.KEY_FILE_TYPE, fileType);
startActivity(recipientIntent);
}
else if(resultCode != RESULT_CANCELED){
Toast.makeText(this,R.string.general_error, Toast.LENGTH_LONG).show();
}
}
Steve Hunter
57,712 PointsLooks like the error is at line 198 of RecipientsActivity. Which line is that?
tshuutheniemvula
7,251 PointsLine 198 is right on: dialog.show()
Found that I was declaring an extra mMediaUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); in the TAKE_VIDEO_REQUEST case, fixed it but am still getting:
02-16 17:35:23.561 1612-1612/com.thetechguys.ribbit E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.thetechguys.ribbit, PID: 1612
android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@41fc6c30 is not valid; is your activity running?
at android.view.ViewRootImpl.setView(ViewRootImpl.java:771)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:278)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
at android.app.Dialog.show(Dialog.java:289)
at com.thetechguys.ribbit.RecipientsActivity$2.done(RecipientsActivity.java:198)
at com.parse.SaveCallback.internalDone(SaveCallback.java:39)
at com.parse.SaveCallback.internalDone(SaveCallback.java:27)
at com.parse.Parse$6$1.run(Parse.java:917)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5598)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(Native Method)
from Logcat
Steve Hunter
57,712 PointsThis one?:
case R.id.action_camera:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setItems(R.array.camera_choices, mDialogListener);
AlertDialog dialog = builder.create();
dialog.show();
tshuutheniemvula
7,251 PointsI meant the case(I found error in) is for choosing actions in MainActivity but the error Logcat gives is actually on 'send' method in RecipientsActivity:
``` protected void send(ParseObject message){ message.saveInBackground(new SaveCallback() { @Override public void done(ParseException e) { if(e==null){ //success Toast.makeText(RecipientsActivity.this,getString(R.string.sucess_message),Toast.LENGTH_LONG).show(); }
else{
//error
AlertDialog.Builder builder = new AlertDialog.Builder(RecipientsActivity.this);
builder.setMessage(getString(R.string.error_sending_message))
.setTitle(getString(R.string.error_selecting_message_title))
.setPositiveButton(android.R.string.ok, null);
AlertDialog dialog = builder.create();
dialog.show();
}
}
});
} ```
Steve Hunter
57,712 PointsOK - you've got the else
part running because e != null
That's good ... add:
Log.d(TAG, "Weird error: " + e);
That might add a little more detail regarding what Parse is doing as that's mentioned in the errors.
It is ironic that the dialog you want to show the connection error is the thing causing the problem!
Is R.string.sucess_message
correct?
Or is it R.string.success_message
Just checking the spelling is the same in both files.
tshuutheniemvula
7,251 PointsIt's a: com.parse.ParseException: i/o failure: java.net.SocketTimeoutException:
! Checking Parse documentation to see how that's avoided.
Steve Hunter
57,712 PointsThat's only one problem, unfortunately.
The else
code is being run because your connection is timing out - that's one issue. The problems is that your error handling code is then causing an exception in the code, due to the dialog.show()
line, for some reason.
Fixing the Parse issue won't fix the dialog issue but it will avoid it as the else
code will never run.
tshuutheniemvula
7,251 PointsYou're right, am still getting the uncaught exception just before dialog.show(). Do you have an idea on where I could start debugging?
Steve Hunter
57,712 PointsI'm wondering if the context is correct given that you are inside a callback method. Maybe try using
AlertDialog.Builder builder = new AlertDialog.Builder(RecipientsActivity.getContext());
One option is to just replace the AlertDialog
with a Toast
although that is cheating a little!!!
Can you send me your project in a zip file? I can see what I get at this end.
tshuutheniemvula
7,251 PointsWhen I substitute it for a Toast, I still get timeoutexception but app doesn't crash, I'm guessing it is probably AlertDialog context that causes it.
Where do I send zip to?
Steve Hunter
57,712 PointsDownloaded (over my appallingly slow broadband) and am currently installing the relevant SDKs and modifying locations etc.
I'll then have a go at fixing the problem. Leave it with me!
Changing the Dialog for a Toast will fix that issue, yes. The timeout exception is a separate one - good luck with that!
tshuutheniemvula
7,251 PointsThanks Steve, I'm just about to start the retrieving messages section so that's why they're not yet appearing in inbox but if it's as you say I should be fine to continue. I've checked on Parse back end and I have actually managed to send one video message even though it still gave me the timeout exception so I gather it most probably is a Parse issue.
Steve Hunter
57,712 PointsLet me know if I can help with anything else as you progress through the app. :-)
Jorge De Pablos
6,260 PointsIs it possible that the Exception is caused because you finish the Recipients Activity after sending the message??
I think Dialogs only can live within the lifecycle of the Activity so if you finish the Activity you get an error.
I'm getting the same error and when I comment the line
finish();
the dialog is shown correctly.
Vincent Rickey
5,581 PointsHi. I also experienced the sendUserActionEvent() mView == null error message. I think there are a few additional pieces to the puzzle in your issue, but I was able to resolve the error by correcting the if statement conditions at the bottom of the onActivityResult else block. The problem was that I accidentally used "CHOOSE_PHOTO_REQUEST" and "CHOOSE_VIDEO_REQUEST" instead of "CHOOSE_PHOTO_REQUEST" and "TAKE_PHOTO_REQUEST". This set a video file type equal to an image, thereby causing the app to crash when I tried to choose a video to add to the message.
Incorrect code - Error - Incorrect combo of CHOOSE_PHOTO_REQUEST and CHOOSE_VIDEO_REQUEST
String fileType;
if (requestCode == CHOOSE_PHOTO_REQUEST || requestCode == CHOOSE_VIDEO_REQUEST) {
fileType = ParseConstants.TYPE_IMAGE;
}
else {
fileType = ParseConstants.TYPE_VIDEO;
}
Resolved - The if statement checks for photos, the else statement checks for videos
String fileType;
if (requestCode == CHOOSE_PHOTO_REQUEST || requestCode == TAKE_PHOTO_REQUEST) {
fileType = ParseConstants.TYPE_IMAGE;
}
else {
fileType = ParseConstants.TYPE_VIDEO;
}