Android Crashing when using a FragmentPagerAdapter - java

Okay, I hope someone may be able to help. I have spent tonight trying figure this out, I just seem to understand it.
I have created a translation app using 4 Fragments & FragmentPagerAdapter, however it runs fine on the surface up to when I click on the 4th column and then the app crashes and closes.
Logcat is cut down... the top section shows first sign why it crashes, section shows fatal exception and dies. When scrolling across it shows different names than it states on the tab E.g - see below for log cat
- Numbers show for Numbers,
- Family show for Colors,
- Colors show for Phrases,
- Phrases show nothing.
NumbersFragment{...} not updated inline; expected state 3 found 2
.../com.example.android.miwok W/FragmentManager:moveToState: Fragment state for ColorsFragment{ccf160c #2 id=0x7f0d006b android:switcher:2131558507:2} not updated inline; expected state 3 found 2
...W/FragmentManager: moveToState: Fragment state for PhrasesFragments{...} not updated inline; expected state 3 found 2
...D/MediaPlayer: setSubtitleAnchor in MediaPlayer
...D/AudioManager: AudioManager dispatching onAudioFocusChange(-2) for android.media.AudioManager#d5174d4com.example.android.miwok.ColorsFragment...
...D/AndroidRuntime: Shutting down VM
...E/AndroidRuntime: FATAL EXCEPTION: mainProcess: com.example.android.miwok, PID: 28858
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.media.MediaPlayer.pause()' on a null object reference
at ...ColorsFragment$1.onAudioFocusChange(ColorsFragment.java:26)
at ...AudioManager$FocusEventHandlerDelegate$1.handleMessage(AudioManager.java:2147) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Please see my java code below
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set content of activity to layout file
setContentView(R.layout.activity_main);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setAdapter(new CategoryFragmentPagerAdapter(getSupportFragmentManager(),
MainActivity.this));
TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
}
}
x4 CategoryFragments.java are identical:
public class ColorsFragment extends Fragment {
private MediaPlayer mMediaPlayer;
private AudioManager mAudioManager; // <-- handles audiofocus when sound is played
AudioManager.OnAudioFocusChangeListener mOnAudioFocusChangeListener =
new AudioManager.OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT ||
focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
mMediaPlayer.pause(); // <-- Lose audio focus
mMediaPlayer.seekTo(0); // <-- & start again because its a short clip
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
mMediaPlayer.start(); // <-- Resume playing media
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
releaseMediaPlayer(); // if audiofocus is lost or app is closed
// stop playback and clean resource.
}
}
};
private MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
releaseMediaPlayer();
}
};
public ColorsFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.word_list, container, false);
// Create a list of words
final ArrayList<Word> words = new ArrayList<>();
words.add(new Word("red", "weṭeṭṭi", R.raw.color_red, R.drawable.color_red));
words.add(new Word("green", "chokokki", R.raw.color_green, R.drawable.color_green));
words.add(new Word("brown", "ṭakaakki", R.raw.color_brown, R.drawable.color_brown));
words.add(new Word("gray", "ṭopoppi", R.raw.color_gray, R.drawable.color_gray));
words.add(new Word("black", "kululli", R.raw.color_black, R.drawable.color_black));
words.add(new Word("white", "kelelli", R.raw.color_white, R.drawable.color_white));
words.add(new Word("dusty yellow", "ṭopiisә", R.raw.color_dusty_yellow, R.drawable.color_dusty_yellow));
words.add(new Word("mustard yellow", "chiwiiṭә", R.raw.color_mustard_yellow, R.drawable.color_mustard_yellow));
WordAdapter adapter = new WordAdapter(getActivity(), words, R.color.category_colors);
ListView listView = (ListView) rootView.findViewById(R.id.list);
listView.setAdapter(adapter);
// its important to request audio focus straight away in the program.
mAudioManager = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE); // <-- turns variable to an instance
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
Word word = words.get(position); // <-- Gets the Word() object, at the given position.
releaseMediaPlayer(); // <-- Releases anything that maybe in the media player.
// Request audio focus for playback
int result = mAudioManager.requestAudioFocus(mOnAudioFocusChangeListener,
// Use the music stream.
AudioManager.STREAM_MUSIC,
// Request permanent focus.
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
mMediaPlayer = MediaPlayer.create(getActivity(), word.getAudioResourceId());
mMediaPlayer.start();
mMediaPlayer.setOnCompletionListener(mCompletionListener);
}
}
});
return rootView;
}
private void releaseMediaPlayer() {
if (mMediaPlayer != null) {
mMediaPlayer.release();
mMediaPlayer = null;
}
}
#Override
public void onStop() {
super.onStop();
releaseMediaPlayer();
}
}
CategoryFragmentPagerAdapter
public class CategoryFragmentPagerAdapter extends FragmentPagerAdapter {
final int PAGE_COUNT = 4;
private Context mContext;
public CategoryFragmentPagerAdapter(FragmentManager fm, Context context) {
super(fm);
mContext = context;
}
#Override
public Fragment getItem(int position) {
if (position == 0) {
return new NumbersFragment();
} else if (position == 1) {
return new FamilyFragments();
} else if (position == 2) {
return new ColorsFragment();
} else {
return new PhrasesFragments();
}
}
#Override
public int getCount() {
return PAGE_COUNT;
}
#Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
if (position == 0) {
return mContext.getResources().getString(R.string.category_numbers);
} else if (position == 1) {
return mContext.getResources().getString(R.string.category_family);
} else if (position == 2) {
return mContext.getResources().getString(R.string.category_colors);
} else {
return mContext.getResources().getString(R.string.category_phrases);
}
}
}[![enter image description here][1]][1]

According crash log you need to secure access to the mMediaPlayer as it could be null:
AudioManager.OnAudioFocusChangeListener mOnAudioFocusChangeListener =
new AudioManager.OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (mMediaPlayer == null)
return;
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT ||
focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
mMediaPlayer.pause(); // <-- Lose audio focus
mMediaPlayer.seekTo(0); // <-- & start again because its a short clip
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
mMediaPlayer.start(); // <-- Resume playing media
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
releaseMediaPlayer(); // if audiofocus is lost or app is closed
// stop playback and clean resource.
}
}
};
I guess listener received AudioManager.AUDIOFOCUS_LOSS after which mMediaPlayer become null. And then it received next event crash happened

Related

How to add image depending on what result or emotion it might detect

I have been trying to figure this out all day, as I would like to add an image depending on the outcome of the emotion may detect. Just wanted to add some some images but I'm still new to this. Can anyone help me with this one to.
btw here's my code:
public class DetectionActivity extends AppCompatActivity {
// Background task of face detection.
private class DetectionTask extends AsyncTask<InputStream, String, Face[]> {
private boolean mSucceed = true;
#Override
protected Face[] doInBackground(InputStream... params) {
// Get an instance of face service client to detect faces in image.
FaceServiceClient faceServiceClient = SampleApp.getFaceServiceClient();
try {
publishProgress("Detecting...");
// Start detection.
return faceServiceClient.detect(
params[0], /* Input stream of image to detect */
true, /* Whether to return face ID */
true, /* Whether to return face landmarks */
new FaceServiceClient.FaceAttributeType[]{
FaceServiceClient.FaceAttributeType.Emotion,
});
} catch (Exception e) {
mSucceed = false;
publishProgress(e.getMessage());
addLog(e.getMessage());
return null;
}
}
#Override
protected void onPreExecute() {
mProgressDialog.show();
addLog("Request: Detecting in image " + mImageUri);
}
#Override
protected void onProgressUpdate(String... progress) {
mProgressDialog.setMessage(progress[0]);
setInfo(progress[0]);
}
#Override
protected void onPostExecute(Face[] result) {
if (mSucceed) {
addLog("Response: Success. Detected " + (result == null ? 0 : result.length)
+ " face(s) in " + mImageUri);
}
// Show the result on screen when detection is done.
setUiAfterDetection(result, mSucceed);
}
}
// Flag to indicate which task is to be performed.
private static final int REQUEST_SELECT_IMAGE = 0;
// The URI of the image selected to detect.
private Uri mImageUri;
// The image selected to detect.
private Bitmap mBitmap;
// Progress dialog popped up when communicating with server.
ProgressDialog mProgressDialog;
// When the activity is created, set all the member variables to initial state.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detection);
//this hides the back button and I thank you
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setTitle(getString(R.string.progress_dialog_title));
// Disable button "detect" as the image to detect is not selected.
setDetectButtonEnabledStatus(false);
LogHelper.clearDetectionLog();
}
// Save the activity state when it's going to stop.
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("ImageUri", mImageUri);
}
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.menuAbout:
// Toast.makeText(this, "You clicked about", Toast.LENGTH_SHORT).show();
View messageView = getLayoutInflater().inflate(R.layout.about, null, false);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setIcon(R.drawable.smile);
builder.setTitle(R.string.app_name);
builder.setView(messageView);
builder.create();
builder.show();
break;
case R.id.menuHelp:
// Toast.makeText(this, "You clicked settings", Toast.LENGTH_SHORT).show();
// Intent help = new Intent(this, HelpActivity.class);
//startActivity(help);
// break;
View messageViewh = getLayoutInflater().inflate(R.layout.help, null, false);
AlertDialog.Builder builderh = new AlertDialog.Builder(this);
builderh.setIcon(R.drawable.smile);
builderh.setTitle(R.string.app_nameh);
builderh.setView(messageViewh);
builderh.create();
builderh.show();
break;
}
return true;
}
// Recover the saved state when the activity is recreated.
#Override
protected void onRestoreInstanceState(#NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mImageUri = savedInstanceState.getParcelable("ImageUri");
if (mImageUri != null) {
mBitmap = ImageHelper.loadSizeLimitedBitmapFromUri(
mImageUri, getContentResolver());
}
}
// Called when image selection is done.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_SELECT_IMAGE:
if (resultCode == RESULT_OK) {
// If image is selected successfully, set the image URI and bitmap.
mImageUri = data.getData();
mBitmap = ImageHelper.loadSizeLimitedBitmapFromUri(
mImageUri, getContentResolver());
if (mBitmap != null) {
// Show the image on screen.
ImageView imageView = (ImageView) findViewById(R.id.image);
imageView.setImageBitmap(mBitmap);
// Add detection log.
addLog("Image: " + mImageUri + " resized to " + mBitmap.getWidth()
+ "x" + mBitmap.getHeight());
}
// Clear the detection result.
FaceListAdapter faceListAdapter = new FaceListAdapter(null);
ListView listView = (ListView) findViewById(R.id.list_detected_faces);
listView.setAdapter(faceListAdapter);
// Clear the information panel.
setInfo("");
// Enable button "detect" as the image is selected and not detected.
setDetectButtonEnabledStatus(true);
}
break;
default:
break;
}
}
// Called when the "Select Image" button is clicked.
public void selectImage(View view) {
Intent intent = new Intent(this, SelectImageActivity.class);
startActivityForResult(intent, REQUEST_SELECT_IMAGE);
}
// Called when the "Detect" button is clicked.
public void detect(View view) {
// Put the image into an input stream for detection.
ByteArrayOutputStream output = new ByteArrayOutputStream();
mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, output);
ByteArrayInputStream inputStream = new ByteArrayInputStream(output.toByteArray());
// Start a background task to detect faces in the image.
new DetectionTask().execute(inputStream);
// Prevent button click during detecting.
setAllButtonsEnabledStatus(false);
}
// View the log of service calls.
public void viewLog(View view) {
Intent intent = new Intent(this, DetectionLogActivity.class);
startActivity(intent);
}
// Show the result on screen when detection is done.
private void setUiAfterDetection(Face[] result, boolean succeed) {
// Detection is done, hide the progress dialog.
mProgressDialog.dismiss();
// Enable all the buttons.
setAllButtonsEnabledStatus(true);
// Disable button "detect" as the image has already been detected.
setDetectButtonEnabledStatus(false);
if (succeed) {
// The information about the detection result.
String detectionResult;
if (result != null) {
detectionResult = result.length + " face"
+ (result.length != 1 ? "s" : "") + " detected";
// Show the detected faces on original image.
ImageView imageView = (ImageView) findViewById(R.id.image);
imageView.setImageBitmap(ImageHelper.drawFaceRectanglesOnBitmap(
mBitmap, result, true));
// Set the adapter of the ListView which contains the details of the detected faces.
FaceListAdapter faceListAdapter = new FaceListAdapter(result);
// Show the detailed list of detected faces.
ListView listView = (ListView) findViewById(R.id.list_detected_faces);
listView.setAdapter(faceListAdapter);
} else {
detectionResult = "0 face detected";
}
setInfo(detectionResult);
}
mImageUri = null;
mBitmap = null;
}
// Set whether the buttons are enabled.
private void setDetectButtonEnabledStatus(boolean isEnabled) {
Button detectButton = (Button) findViewById(R.id.detect);
detectButton.setEnabled(isEnabled);
}
// Set whether the buttons are enabled.
private void setAllButtonsEnabledStatus(boolean isEnabled) {
Button selectImageButton = (Button) findViewById(R.id.select_image);
selectImageButton.setEnabled(isEnabled);
Button detectButton = (Button) findViewById(R.id.detect);
detectButton.setEnabled(isEnabled);
// Button ViewLogButton = (Button) findViewById(R.id.view_log);
// ViewLogButton.setEnabled(isEnabled);
}
// Set the information panel on screen.
private void setInfo(String info) {
TextView textView = (TextView) findViewById(R.id.info);
textView.setText(info);
}
// Add a log item.
private void addLog(String log) {
LogHelper.addDetectionLog(log);
}
// The adapter of the GridView which contains the details of the detected faces.
private class FaceListAdapter extends BaseAdapter {
// The detected faces.
List<Face> faces;
// The thumbnails of detected faces.
List<Bitmap> faceThumbnails;
// Initialize with detection result.
FaceListAdapter(Face[] detectionResult) {
faces = new ArrayList<>();
faceThumbnails = new ArrayList<>();
if (detectionResult != null) {
faces = Arrays.asList(detectionResult);
for (Face face : faces) {
try {
// Crop face thumbnail with five main landmarks drawn from original image.
faceThumbnails.add(ImageHelper.generateFaceThumbnail(
mBitmap, face.faceRectangle));
} catch (IOException e) {
// Show the exception when generating face thumbnail fails.
setInfo(e.getMessage());
}
}
}
}
#Override
public boolean isEnabled(int position) {
return false;
}
#Override
public int getCount() {
return faces.size();
}
#Override
public Object getItem(int position) {
return faces.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater layoutInflater =
(LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.item_face_with_description, parent, false);
}
convertView.setId(position);
// Show the face thumbnail.
((ImageView) convertView.findViewById(R.id.face_thumbnail)).setImageBitmap(
faceThumbnails.get(position));
// Show the face details.
String getEmotion;
// String improve = improveMessage(getEmotion);
DecimalFormat formatter = new DecimalFormat("#0.0");
//add
// String message = findMessage(getEmotion());
// String improve = improveMessage(getEmotion);
String face_description = String.format("Emotion: %s\n",
getEmotion(faces.get(position).faceAttributes.emotion)
);
((TextView) convertView.findViewById(R.id.text_detected_face)).setText(face_description);
return convertView;
}
private String getEmotion(Emotion emotion) {
String emotionType = "";
double emotionValue = 0.0;
String emotionInfo = "";
if (emotion.anger > emotionValue) {
emotionValue = emotion.anger;
emotionType = "Anger";
emotionInfo = "If you haven't fed him/her yet maybe this precious one is thirsty or hungry.\n Try giving your attention. If your baby is acting unusual it's best to seek for medical help.";
}
if (emotion.contempt > emotionValue) {
emotionValue = emotion.contempt;
emotionType = "Contempt";
emotionInfo = "You go girl!";
}
if (emotion.disgust > emotionValue) {
emotionValue = emotion.disgust;
emotionType = "Disgust";
emotionInfo = "Look! If your baby is feeling this way mabye she/he doesn't like this. \n If what your doing right now is good for him/her maybe you can support that.";
}
if (emotion.fear > emotionValue) {
emotionValue = emotion.fear;
emotionType = "Fear";
emotionInfo = "Your baby looks somewhat uncomfortable.\n Make your baby feel comfortable and take note of what makes them feel like that. ";
}
if (emotion.happiness > emotionValue) {
emotionValue = emotion.happiness;
emotionType = "Happiness";
emotionInfo = "Just continue what you are doing. It is important to remember what can make them happy. \n";
}
if (emotion.neutral > emotionValue) {
emotionValue = emotion.neutral;
emotionType = "Neutral";
emotionInfo = "Maybe you should just observe first";
}
if (emotion.sadness > emotionValue) {
emotionValue = emotion.sadness;
emotionType = "Sadness";
emotionInfo = "Just cuddle or dandle your baby.";
}
if (emotion.surprise > emotionValue) {
emotionValue = emotion.surprise;
emotionType = "Surprise";
emotionInfo = "Oooh look. Play with your baby. Try doing peek a boo";
}
return String.format("%s: %f \n\n%s", emotionType, emotionValue, emotionInfo);
}
}
}
Just would like to add some images like happy if that is the detected emotion. Please do help me. Any help is highly appreciated. Thank you :)
I would like to add that after the emotionInfo.
I guess detectWithStream is you want.
Official Doc: Faces.detectWithStream Method
From Java SDK, the List<DetectedFace> object will return if successful.

How can convert ListActivity to AppCompatActivity

I want to change my activity parent from ListActivity to AppCompatActivity, because I need to use check permission Granted and it's need AppCompat, but my activity is ListView.
I try this action, but not received a good result :(
This is my source code (Ever has ... is for no added code):
public class RingtoneSelectActivity extends ListActivity {
...
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mShowAll = false;
String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
showFinalAlert(getResources().getText(R.string.err_sdcard_readonly));
return;
}
if (status.equals(Environment.MEDIA_SHARED)) {
showFinalAlert(getResources().getText(R.string.err_sdcard_shared));
return;
}
if (!status.equals(Environment.MEDIA_MOUNTED)) {
showFinalAlert(getResources().getText(R.string.err_no_sdcard));
return;
}
Intent intent = getIntent();
mWasGetContentIntent = intent.getAction().equals(
Intent.ACTION_GET_CONTENT);
// Inflate our UI from its XML layout description.
setContentView(R.layout.media_select);
SplashHandler mHandler = new SplashHandler();
Message msg = new Message();
//Assign a unique code to the message.
//Later, this code will be used to identify the message in Handler class.
msg.what = 0;
// Send the message with a delay of 3 seconds(3000 = 3 sec).
mHandler.sendMessageDelayed(msg, 10000);
try {
mAdapter = new SimpleCursorAdapter(
this,
// Use a template that displays a text view
R.layout.media_select_row,
// Give the cursor to the list adatper
createCursor(""),
// Map from database columns...
new String[]{
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media._ID},
// To widget ids in the row layout...
new int[]{
R.id.row_artist,
R.id.row_album,
R.id.row_title,
R.id.row_icon,
R.id.row_options_button});
setListAdapter(mAdapter);
getListView().setItemsCanFocus(true);
// Normal click - open the editor
getListView().setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent,
View view,
int position,
long id) {
startRingdroidEditor();
}
});
} catch (SecurityException e) {
// No permission to retrieve audio?
Log.e("Ringtone", e.toString());
// todo error 1
} catch (IllegalArgumentException e) {
// No permission to retrieve audio?
Log.e("Ringtone", e.toString());
// todo error 2
}
mAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
public boolean setViewValue(View view,
Cursor cursor,
int columnIndex) {
if (view.getId() == R.id.row_options_button) {
// Get the arrow image view and set the onClickListener to open the context menu.
ImageView iv = (ImageView) view;
iv.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
openContextMenu(v);
}
});
return true;
} else if (view.getId() == R.id.row_icon) {
setSoundIconFromCursor((ImageView) view, cursor);
return true;
}
return false;
}
});
// Long-press opens a context menu
registerForContextMenu(getListView());
}
}
...
}
I changed to this:
public class RingtoneSelectActivity extends AppCompatActivity {
But I received some errors in this lines:
...
setListAdapter(mAdapter);
getListView().setItemsCanFocus(true);
getListView().setOnItemClickListener(new OnItemClickListener() { ... });
...
registerForContextMenu(getListView());
My errors:
Cannot resolve method 'setListAdapter(android.widget.SimpleCursorAdapter)
Cannot resolve method 'getListView()'
How can I fix that errors?
[Edit]
My LogCat:
E/ACRA: ACRA caught a NullPointerException for ir.ari.mp3cutter
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.SimpleCursorAdapter.changeCursor(android.database.Cursor)' on a null object reference
at ir.ari.mp3cutter.RingtoneSelectActivity.refreshListView(RingtoneSelectActivity.java:621)
at ir.ari.mp3cutter.RingtoneSelectActivity.onOptionsItemSelected(RingtoneSelectActivity.java:314)
at android.app.Activity.onMenuItemSelected(Activity.java:2908)
at com.android.internal.policy.PhoneWindow.onMenuItemSelected(PhoneWindow.java:1151)
at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:761)
at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:152)
at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:904)
at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:894)
at com.android.internal.view.menu.MenuPopupHelper.onItemClick(MenuPopupHelper.java:200)
at android.widget.AdapterView.performItemClick(AdapterView.java:310)
at android.widget.AbsListView.performItemClick(AbsListView.java:1145)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3042)
at android.widget.AbsListView$3.run(AbsListView.java:3879)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Line 304 to 319:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_about:
RingtoneEditActivity.onAbout(this);
return true;
case R.id.action_record:
onRecord();
return true;
case R.id.action_show_all_audio:
mShowAll = true;
refreshListView();
return true;
default:
return false;
}
}
And line 619 to 622:
private void refreshListView() {
String filterStr = mFilter.getQuery().toString();
mAdapter.changeCursor(createCursor(filterStr));
}
[notice: I'm sorry for my bad talking, because I not learned English as good :)
So don't change super class, Just check for ungranted permissions with ContextCompat.checkSelfPermission() and then request Permission by ActivityCompat.requestPermissions() and get the result in:
#Override
public void onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}

Master-Detail View using ViewPager

I'd like to change the master-detail implementation of my Android phone app. Currently, users can select items from a ListView, opening a new activity. To select a different activity, the user must return to the list. Instead of this pogo-sticking, I'd like the user to swipe left and right to page through the documents using a ViewPager. There can be many documents, so I'd like to load at most 3 pages at a time - the current page, the previous, and the next. Paging back and forth should then add and remove pages left and right. I've created an adapter implementing FragmentStatePagerAdapter that handles static content (e.g. TextViews) nicely. Also deleting pages seems to work OK (not included here). But when I add e.g. an EditText content is copied over from one page to the next when paging.
Below is the code for the adapter and for the activity. There are two questions I have:
What is wrong with my adapter that causes the undesired copying of EditText from one fragment to the next?
This is my first shot at this, and it's probably far from an optimal implementation. But I find this to be such a common use case that I almost feel like there would be a ready made framework for it. Could this be achieved much easier?
Pager Adapter:
public class DetailPagerAdapter extends FragmentStatePagerAdapter {
private final List<Fragment> mFragments;
private final static String TAG = "DetailPagerAdapter";
public DetailPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
mFragments = fragments;
}
#Override
public int getCount() {
return mFragments.size();
}
#Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
#Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
public void addItem(Fragment fragment) {
mFragments.add(fragment);
notifyDataSetChanged();
}
public void removeItem(int position) {
mFragments.remove(position);
notifyDataSetChanged();
}
public void insertItem(int position, Fragment fragment) {
mFragments.add(position, fragment);
notifyDataSetChanged();
}
}
PagingActivity Base Class:
public abstract class PagingActivity
extends AppCompatActivity
implements ViewPager.OnPageChangeListener {
protected ViewPager mViewPager;
DetailPagerAdapter mViewPagerAdapter;
protected ArrayList<String> mAllItemIds;
private String mPreviousItemId;
private String mCurrentItemId;
private String mNextItemId;
private boolean mMuteOnPageSelected = false;
protected abstract Fragment getNewPageFragment(String id);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
List<Fragment> initialFragments = new ArrayList<>();
int currentItemIndex = mAllItemIds.indexOf(mCurrentItemId);
int pageSelection = 1;
// Add previous view.
if (currentItemIndex > 0) {
mPreviousItemId = mAllItemIds.get(mAllItemIds.indexOf(mCurrentItemId) - 1);
initialFragments.add(getNewPageFragment(mPreviousItemId));
} else {
pageSelection = 0;
mPreviousItemId = null;
}
// Add current view.
initialFragments.add(getNewPageFragment(mCurrentItemId));
// Add next view.
if (currentItemIndex < mAllItemIds.size() - 1) {
mNextItemId = mAllItemIds.get(mAllItemIds.indexOf(mCurrentItemId) + 1);
initialFragments.add(getNewPageFragment(mNextItemId));
} else {
mNextItemId = null;
}
mViewPagerAdapter = new DetailPagerAdapter(getSupportFragmentManager(), initialFragments);
mViewPager.setAdapter(mViewPagerAdapter);
mViewPager.setCurrentItem(pageSelection);
mViewPager.addOnPageChangeListener(this);
}
#Override
public void onPageSelected(int position) {
if (!mMuteOnPageSelected) {
mCurrentItemId = ((PagingFragment) (mViewPagerAdapter.getItem(mViewPager.getCurrentItem()))).getItemId();
int currentItemIndex = mAllItemIds.indexOf(mCurrentItemId);
// Navigated to the right.
if (position == mViewPagerAdapter.getCount() - 1) {
// Add next if not already pointing at the last available item.
if (currentItemIndex < mAllItemIds.size() - 1) {
mNextItemId = mAllItemIds.get(mAllItemIds.indexOf(mCurrentItemId) + 1);
mViewPagerAdapter.addItem(getNewPageFragment(mNextItemId));
} else {
mNextItemId = null;
}
// If it succeeds remove first item.
int itemCount = mViewPagerAdapter.getCount();
if ((itemCount > 3) || ((itemCount == 3) && (currentItemIndex == mAllItemIds.size() - 1))) {
mMuteOnPageSelected = true;
mViewPagerAdapter.removeItem(0);
mViewPager.setCurrentItem(1);
mMuteOnPageSelected = false;
}
}
// Navigated to the left.
else if (position == 0) {
// Add item on the left if not already pointing at the first available item.
if (currentItemIndex > 0) {
mPreviousItemId = mAllItemIds.get(mAllItemIds.indexOf(mCurrentItemId) - 1);
mViewPagerAdapter.insertItem(0, getNewPageFragment(mPreviousItemId));
} else {
mPreviousItemId = null;
}
// Check if last item needs to be removed and selection updated.
int itemCount = mViewPagerAdapter.getCount();
if (itemCount == 3) {
if (currentItemIndex == 0) {
// Points to the first of two items.
// -> do not change selection
// -> remove rightmost item.
mViewPagerAdapter.removeItem(itemCount - 1);
} else if (currentItemIndex == mAllItemIds.size() - 2) {
// Will point to the middle of 3 items.
// -> nothing to remove
// -> select middle page.
mMuteOnPageSelected = true;
mViewPager.setCurrentItem(1);
mMuteOnPageSelected = false;
}
} else if (itemCount > 3) {
// Pager contains 4 items, first item selected.
// -> remove rightmost item
// -> select middle page.
mMuteOnPageSelected = true;
mViewPagerAdapter.removeItem(itemCount - 1);
mViewPager.setCurrentItem(1);
mMuteOnPageSelected = false;
}
}
mViewPagerAdapter.notifyDataSetChanged();
}
}
}
The second question was the key: Yes, at least the current state can be achieved much easier by letting the adapter handle the full array of items. FragmentStatePagerAdapter only loads as many fragments at a time as needed, so it can handle all the manual work I had done in the activity.
Pager Adapter
public class MyPagerAdapter extends FragmentStatePagerAdapter {
private List<String> mAllItemIds;
public MyPagerAdapter(Context context, FragmentManager fm) {
super(fm);
mAllItemIds = ...
}
#Override
public int getCount() {
return mAllItemIds.size();
}
#Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
#Override
public Fragment getItem(int position) {
return MyFragment.newInstance(mAllItemIds.get(position));
}
public void removeItem(int position) {
// add needed code here to remove item also from source
// ...
mAllItemIds.remove(position);
notifyDataSetChanged();
}
}
Activity
public abstract class PagingActivity extends AppCompatActivity {
protected ViewPager mViewPager;
MyPagerAdapter mViewPagerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewPager = (ViewPager)findViewById(R.id.viewPager);
mViewPagerAdapter = new MyPagerAdapter(this, getSupportFragmentManager());
mViewPager.setAdapter(mViewPagerAdapter);
}
private void deleteItem() {
mViewPagerAdapter.removeItem(mViewPager.getCurrentItem());
}
}

Android Service: Detect when device is idle for X minutes

I need to know to detect when the android device has been idle for a certain period of time when my app is currently in the background (and if it is idle, bring my app to the front). The only two ways I could think of to do this are:
Somehow detect user interaction outside of the app, and if there hasn't been any input for X number of minutes, bring my app to the front.
or:
When the device goes into sleep mode, bring my app to the front.
I can't figure out how to either of these, but 2 seems like the most feasible option to me. What would be the code for this?
I was able to accomplish 1. by using "transparent" view which was placed on top of all views, which checks for user touches
Steps for achieving the needed effect:
1) Create a Service which in its onCreate method creates the transparent view and attach it to the views stack
2) onStartCommand call the initTimer() method
3) implement View.OnTouchListener on the service
4) override onTouch method
5) onTouch event received - call initTimer()
6) on onDestroy of the service - remove the transparent view from the views stack
7) start the service when onPause of your main activity is called
8) stop the service when the app opens
Here is the code:
private Handler mHandler;
private Runnable mRunnable;
private final int mTimerDelay = 60000;//inactivity delay in milliseconds
private LinearLayout mTouchLayout;//the transparent view
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
mTouchLayout = new LinearLayout(this);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
mTouchLayout.setLayoutParams(lp);
// set on touch listener
mTouchLayout.setOnTouchListener(this);
// fetch window manager object
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
// set layout parameter of window manager
WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT
);
mParams.gravity = Gravity.LEFT | Gravity.TOP;
windowManager.addView(mTouchLayout, mParams);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
initTimer();
return START_NOT_STICKY;
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.d("IdleDetectorService", "Touch detected. Resetting timer");
initTimer();
return false;
}
#Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(mRunnable);
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
if (windowManager != null && mTouchLayout != null) {
windowManager.removeView(mTouchLayout);
}
}
/**
* (Re)sets the timer to send the inactivity broadcast
*/
private void initTimer() {
// Start timer and timer task
if (mRunnable == null) {
mRunnable = new Runnable() {
#Override
public void run() {
Log.d("IdleDetectorService", "Inactivity detected. Sending broadcast to start the app");
try {
boolean isInForeground = new ForegroundCheckTask().execute(getApplicationContext()).get();
if (!isInForeground) {
Intent launchIntent = getApplication()
.getPackageManager()
.getLaunchIntentForPackage("<your-package-name>");
if (launchIntent != null) {
LogUtil.d("IdleDetectorService", "App started");
getApplication().startActivity(launchIntent);
}
}
stopSelf();
} catch (Exception e) {
}
}
};
}
if (mHandler == null) {
mHandler = new Handler();
}
mHandler.removeCallbacks(mRunnable);
mHandler.postDelayed(mRunnable, mTimerDelay);
}
private class ForegroundCheckTask extends AsyncTask<Context, Void, Boolean> {
#Override
protected Boolean doInBackground(Context... params) {
final Context context = params[0];
return isAppOnForeground(context);
}
private boolean isAppOnForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses = null;
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
appProcesses = activityManager.getRunningAppProcesses();
} else {
//for devices with Android 5+ use alternative methods
appProcesses = AndroidProcesses.getRunningAppProcessInfo(getApplication());
}
if (appProcesses == null) {
return false;
}
final String packageName = context.getPackageName();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND &&
appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
}
Note that you should add additional permission in your AndroidManifest.xml file:
android:name="android.permission.SYSTEM_ALERT_WINDOW"

Save Fragment objects

I have an Activity that Displays Fragments one at a time , now each fragment load it data from server and keep fetching data in a list , the user can display another fragment in the activity by selecting an item in the Spinner that displayed in the ActonBar.
here is the code for the Activity
public class HomeActivity extends SherlockFragmentActivity .....{
private class ListInfo {
private String tag;
private Class<?> clss;
private Bundle bundle;
private Fragment fragment;
public ListInfo(String tag, Class<?> clss, Bundle bundle) {
this.tag = tag;
this.clss = clss;
this.bundle = bundle;
}
}
String[] naviStrings;
private HashMap<String, ListInfo> listMap = new HashMap<String, HomeActivity.ListInfo>();
private ListInfo mLastListInfo = null;
private int currentSelectedOptionInSpinner;
ChannelFragment fr;
#SuppressWarnings("unchecked")
#Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
Log.d("HomeActivity", "onCreate");
Log.d("onCreate bundle", "" + arg0);
setContentView(R.layout.test);
naviStrings = getResources().getStringArray(
R.array.action_bar_spinner_entries);
initializeList(arg0);
Context context = getSupportActionBar().getThemedContext();
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
context, R.array.action_bar_spinner_entries,
R.layout.sherlock_spinner_item);
adapter.setDropDownViewResource(R.layout.sherlock_spinner_dropdown_item);
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
getSupportActionBar().setListNavigationCallbacks(adapter, this);
getSupportActionBar().setSelectedNavigationItem(
currentSelectedOptionInSpinner);
}
private void initializeList(Bundle args) {
ListInfo listInfo = null;
// add first Fragment
listMap.put(naviStrings[5], (listInfo = new ListInfo(naviStrings[5],
AboutUsActivity.class, args)));
addFragmentToList(this, listInfo);
listMap.put(naviStrings[3], (listInfo = new ListInfo(naviStrings[3],
Fragment1.class, args)));
addFragmentToList(this, listInfo);
listMap.put(naviStrings[2], (listInfo = new ListInfo(naviStrings[2],
Fragment2.class, args)));
addFragmentToList(this, listInfo);
listMap.put(naviStrings[1], (listInfo = new ListInfo(naviStrings[1],
Fragment3.class, args)));
addFragmentToList(this, listInfo);
listMap.put(naviStrings[4], (listInfo = new ListInfo(naviStrings[4],
Fragment4.class, args)));
addFragmentToList(this, listInfo);
if (args != null) {
Toast.makeText(this, "args is not null", Toast.LENGTH_SHORT).show();
// set the current selected index in the ActionBar spinner
if (args.getInt(
ApplicationMetaData.IntentData.LAST_SELECTED_ITEM_SPINNER,
-1) > -1
&& args.getInt(
ApplicationMetaData.IntentData.LAST_SELECTED_ITEM_SPINNER,
-1) < naviStrings.length) {
Toast.makeText(this, "selected is not null",
Toast.LENGTH_SHORT).show();
currentSelectedOptionInSpinner = args
.getInt(ApplicationMetaData.IntentData.LAST_SELECTED_ITEM_SPINNER);
} else {
currentSelectedOptionInSpinner = 2;
}
} else {
currentSelectedOptionInSpinner = 2;
}
onNavigationItemSelected(currentSelectedOptionInSpinner, 0);
}
private static void addFragmentToList(SherlockFragmentActivity activity,
ListInfo instanse) {
// check to see if we already have a fragment for this tab , probably
// from a previously save state.
// if so deactivated it ,because our initial state is that a tab is not
// shown.
String tag = instanse.tag;
instanse.fragment = activity.getSupportFragmentManager()
.findFragmentByTag(tag);
if (instanse.fragment != null && !instanse.fragment.isDetached()) {
FragmentTransaction ft = activity.getSupportFragmentManager()
.beginTransaction();
ft.detach(instanse.fragment);
ft.commit();
activity.getSupportFragmentManager().executePendingTransactions();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(
ApplicationMetaData.IntentData.LAST_SELECTED_ITEM_SPINNER,
currentSelectedOptionInSpinner);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
Log.d("onNavigationItemSelected", "" + itemPosition);
if (itemPosition == 5) {
Intent i = new Intent(this, AboutUsActivity.class);
startActivity(i);
return true;
}
Log.d("fragment data", listMap.get(naviStrings[itemPosition]) + "");
ListInfo newtItem = listMap.get(naviStrings[itemPosition]);
if (newtItem != mLastListInfo) {
FragmentTransaction ft = this.getSupportFragmentManager()
.beginTransaction();
if (mLastListInfo != null) {
if (mLastListInfo.fragment != null) {
ft.detach(mLastListInfo.fragment);
}
}
if (newtItem != null) {
if (newtItem.fragment == null) {
// create and add
newtItem.fragment = Fragment.instantiate(this,
newtItem.clss.getName(), newtItem.bundle);
ft.add(android.R.id.content, newtItem.fragment,
newtItem.tag);
} else {
ft.attach(newtItem.fragment);
}
}
mLastListInfo = newtItem;
ft.commit();
this.getSupportFragmentManager().executePendingTransactions();
return true;
}
return false;
}}
now when i navigate from one fragment to another lets say from Fragment1 to Fragment2 when i return back to fragment1 it preserve it state and does not have to load it data from the beginning , but if i start a new Activity from the home Activity the system destroy the Activity and the Fragments in it , is There a way to preserve these Fragment note when i rotate the Home Activity nothing happened , only if i start a new Activity ??????
UPDATE
in all of the Four Fragment i make in the onCreate setRetaineInstance(true);
One option is to override saveInstanceState in your Fragments and/or Activites in order to persist data and later retrieve it from the Bundle that gets passed into onActivityCreated/onCreate.
If you are dealing with large sets of data, you may be better off using another persistence mechanism like the SQLite database

Categories