I am creating an android camera app using opencv. First I make it like when I click the start button, it start taking pictures and in every second takes a picture and store it in storage. It works perfectly for me.
Then I tried to make it some tricky by forcing it to take 5 pictures in a second it works well.
But actually I faced problem when I make it to 20 pictures in 1 second. It did not work. The app hangs as soon as I click on the start button. I don't know why. But I think the problem is in threading.
Can someone help me how i will do it.
I have two java files in my project and here is the code.
package org.opencv.samples.tutorial3;
import java.io.FileOutputStream;
import java.util.List;
import org.opencv.android.JavaCameraView;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.util.AttributeSet;
import android.util.Log;
public class Tutorial3View extends JavaCameraView implements PictureCallback {
private static final String TAG = "Sample::Tutorial3View";
private String mPictureFileName;
public Tutorial3View(Context context, AttributeSet attrs) {
super(context, attrs);
}
public List<String> getEffectList() {
return mCamera.getParameters().getSupportedColorEffects();
}
public boolean isEffectSupported() {
return (mCamera.getParameters().getColorEffect() != null);
}
public String getEffect() {
return mCamera.getParameters().getColorEffect();
}
public void setEffect(String effect) {
Camera.Parameters params = mCamera.getParameters();
params.setColorEffect(effect);
mCamera.setParameters(params);
}
public List<Size> getResolutionList() {
return mCamera.getParameters().getSupportedPreviewSizes();
}
public void setResolution(Size resolution) {
disconnectCamera();
mMaxHeight = resolution.height;
mMaxWidth = resolution.width;
connectCamera(getWidth(), getHeight());
}
public Size getResolution() {
return mCamera.getParameters().getPreviewSize();
}
public void takePicture(final String fileName) {
Log.i(TAG, "Taking picture");
this.mPictureFileName = fileName;
// Postview and jpeg are sent in the same buffers if the queue is not empty when performing a capture.
// Clear up buffers to avoid mCamera.takePicture to be stuck because of a memory issue
mCamera.setPreviewCallback(null);
// PictureCallback is implemented by the current class
mCamera.takePicture(null, null, this);
}
#Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.i(TAG, "Saving a bitmap to file");
// The camera preview was automatically stopped. Start it again.
mCamera.startPreview();
mCamera.setPreviewCallback(this);
// Write the image in a file (in jpeg format)
try {
FileOutputStream fos = new FileOutputStream(mPictureFileName);
fos.write(data);
fos.close();
} catch (java.io.IOException e) {
Log.e("PictureDemo", "Exception in photoCallback", e);
}
}
}
And the second one is:
package org.opencv.samples.tutorial3;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.ListIterator;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Mat;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SubMenu;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Toast;
public class Tutorial3Activity extends Activity implements CvCameraViewListener2 {
private static final String TAG = "OCVSample::Activity";
private Tutorial3View mOpenCvCameraView;
private List<Size> mResolutionList;
private MenuItem[] mEffectMenuItems;
private SubMenu mColorEffectsMenu;
private MenuItem[] mResolutionMenuItems;
private SubMenu mResolutionMenu;
Thread thread;
Button start,stop;
boolean loop=false;
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
#Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i(TAG, "OpenCV loaded successfully");
mOpenCvCameraView.enableView();
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
public Tutorial3Activity() {
Log.i(TAG, "Instantiated new " + this.getClass());
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "called onCreate");
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.tutorial3_surface_view);
start=(Button)findViewById(R.id.button2) ;
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
loop=true;
thread = new Thread(new task());
thread.start();
}
});
stop=(Button) findViewById(R.id.button);
stop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
loop=false;
}
});
mOpenCvCameraView = (Tutorial3View) findViewById(R.id.tutorial3_activity_java_surface_view);
mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(this);
}
#Override
public void onPause()
{
super.onPause();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
#Override
public void onResume()
{
super.onResume();
if (!OpenCVLoader.initDebug()) {
Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
} else {
Log.d(TAG, "OpenCV library found inside package. Using it!");
mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
}
}
public void onDestroy() {
super.onDestroy();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
public void onCameraViewStarted(int width, int height) {
}
public void onCameraViewStopped() {
}
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
return inputFrame.rgba();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
List<String> effects = mOpenCvCameraView.getEffectList();
if (effects == null) {
Log.e(TAG, "Color effects are not supported by device!");
return true;
}
mColorEffectsMenu = menu.addSubMenu("Color Effect");
mEffectMenuItems = new MenuItem[effects.size()];
int idx = 0;
ListIterator<String> effectItr = effects.listIterator();
while(effectItr.hasNext()) {
String element = effectItr.next();
mEffectMenuItems[idx] = mColorEffectsMenu.add(1, idx, Menu.NONE, element);
idx++;
}
mResolutionMenu = menu.addSubMenu("Resolution");
mResolutionList = mOpenCvCameraView.getResolutionList();
mResolutionMenuItems = new MenuItem[mResolutionList.size()];
ListIterator<Size> resolutionItr = mResolutionList.listIterator();
idx = 0;
while(resolutionItr.hasNext()) {
Size element = resolutionItr.next();
mResolutionMenuItems[idx] = mResolutionMenu.add(2, idx, Menu.NONE,
Integer.valueOf(element.width).toString() + "x" + Integer.valueOf(element.height).toString());
idx++;
}
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
Log.i(TAG, "called onOptionsItemSelected; selected item: " + item);
if (item.getGroupId() == 1)
{
mOpenCvCameraView.setEffect((String) item.getTitle());
Toast.makeText(this, mOpenCvCameraView.getEffect(), Toast.LENGTH_SHORT).show();
}
else if (item.getGroupId() == 2)
{
int id = item.getItemId();
Size resolution = mResolutionList.get(id);
mOpenCvCameraView.setResolution(resolution);
resolution = mOpenCvCameraView.getResolution();
String caption = Integer.valueOf(resolution.width).toString() + "x" + Integer.valueOf(resolution.height).toString();
Toast.makeText(this, caption, Toast.LENGTH_SHORT).show();
}
return true;
}
class task implements Runnable {
public void run() {
while (loop) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
String currentDateandTime = sdf.format(new Date());
final String fileName = Environment.getExternalStorageDirectory().getPath() +
"/sample_picture_" + currentDateandTime + ".jpg";
mOpenCvCameraView.takePicture(fileName);
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(Tutorial3Activity.this, fileName + " saved", Toast.LENGTH_SHORT).show();
}
});
try {
thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Note: The above code works well for taking 5 pictures in 1 second. But when I change thread.sleep(200) to thread.sleep(50) for taking 20 pictures in 1 second it hangs.
Related
I'm doing a Simple Media Recorder/Player App and the recording part is successfully done. But now I'm having problems with the media player's part. Let me tell you the issues:
When I try to play a media file with the Media Player it says a preparing error like this:
java.io.IOException: Prepare failed.: status=0x1
How can I solve this problem?
My Three Classes:
-RecordFragment.java:
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat;
import androidx.fragment.app.Fragment;
import android.os.Environment;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Chronometer;
import android.widget.TextView;
import android.widget.Toast;
import com.airbnb.lottie.LottieAnimationView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.venomapps.voicerecorder.R;
import com.venomapps.voicerecorder.Utils.Constants;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class RecordFragment extends Fragment {
private TextView textViewInformation;
private FloatingActionButton floatingActionButtonStartRecording;
private FloatingActionButton floatingActionButtonFinishRecording;
private FloatingActionButton floatingActionButtonCancelRecording;
private int recordingStatus = 0;
private String fileName = "";
private Context context;
String[] permissions = {Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE};
private MediaRecorder mediaRecorder;
private String outPutFilePath;
private Chronometer chronometerRecord;
private boolean running;
private long pauseOffset;
private LottieAnimationView lottieAnimationViewVoice;
public RecordFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_record, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
context = getActivity();
bindUI(view);
setListeners();
}
private void bindUI(View view) {
textViewInformation = view.findViewById(R.id.textViewInformation);
floatingActionButtonStartRecording = view.findViewById(R.id.floatingActionButtonStartRecording);
floatingActionButtonFinishRecording = view.findViewById(R.id.floatingActionButtonFinishRecording);
floatingActionButtonCancelRecording = view.findViewById(R.id.floatingActionButtonCancelRecording);
chronometerRecord = view.findViewById(R.id.chronometerRecord);
lottieAnimationViewVoice = view.findViewById(R.id.lottieAnimationViewVoice);
}
private void setListeners() {
floatingActionButtonStartRecording.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(context,
Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
switch (recordingStatus) {
case 0:
startRecording();
break;
case 1:
if (Build.VERSION.SDK_INT >= 24) {
pauseRecording();
} else {
finishRecording();
}
break;
case 2:
resumeRecording();
case 3:
break;
}
} else {
askPermissions();
}
}
});
floatingActionButtonFinishRecording.setOnClickListener(new View.OnClickListener() {
#SuppressLint("SetTextI18n")
#Override
public void onClick(View view) {
if (recordingStatus == 1 || recordingStatus == 2) {
finishRecording();
} else {
Toast.makeText(getActivity(), getString(R.string.not_recording), Toast.LENGTH_SHORT).show();
}
}
});
floatingActionButtonCancelRecording.setOnClickListener(new View.OnClickListener() {
#SuppressLint("SetTextI18n")
#Override
public void onClick(View view) {
if (recordingStatus == 1 || recordingStatus == 2) {
cancelRecording();
} else {
Toast.makeText(getActivity(), getString(R.string.not_recording), Toast.LENGTH_SHORT).show();
}
}
});
chronometerRecord.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
#Override
public void onChronometerTick(Chronometer chronometer) {
long time = SystemClock.elapsedRealtime() - chronometer.getBase();
int h = (int) (time / 3600000);
int m = (int) (time - h * 3600000) / 60000;
int s = (int) (time - h * 3600000 - m * 60000) / 1000;
String t = (h < 10 ? "0" + h : h) + ":" + (m < 10 ? "0" + m : m) + ":" + (s < 10 ? "0" + s : s);
chronometer.setText(t);
}
});
}
#SuppressLint("SetTextI18n")
private void startRecording() {
String basePath = Environment.getExternalStorageDirectory().toString();
String date = getCurrentDateFormatted();
String myDirectory = "Voice Recorder";
fileName = getString(R.string.recording_file) + date;
fileName = fileName.replace(" ", "");
fileName = fileName.replace("|", "");
fileName = fileName + ".mp3";
outPutFilePath = basePath + File.separator + myDirectory + File.separator + fileName;
String filePath = basePath + File.separator + myDirectory;
File newFolder = new File(filePath);
if (!newFolder.exists()) {
boolean createFolder = newFolder.mkdirs();
if (createFolder) {
Log.d("VOICE_RECORDER", "Created folder successfully!");
}
}
recordingStatus = 1;
mediaRecorder = new MediaRecorder();
if (Build.VERSION.SDK_INT >= 24) {
floatingActionButtonStartRecording.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_pause_orange, null));
} else {
floatingActionButtonStartRecording.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_stop_red, null));
}
textViewInformation.setText(getString(R.string.recording));
lottieAnimationViewVoice.playAnimation();
lottieAnimationViewVoice.setVisibility(View.VISIBLE);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mediaRecorder.setOutputFile(outPutFilePath);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mediaRecorder.setAudioEncodingBitRate(16 * 44100);
mediaRecorder.setAudioSamplingRate(44100);
try {
mediaRecorder.prepare();
mediaRecorder.start();
if (!running) {
chronometerRecord.setVisibility(View.VISIBLE);
chronometerRecord.setBase(SystemClock.elapsedRealtime());
chronometerRecord.start();
running = true;
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void pauseRecording() {
if (Build.VERSION.SDK_INT >= 24) {
mediaRecorder.pause();
}
if (running) {
chronometerRecord.stop();
pauseOffset = SystemClock.elapsedRealtime() - chronometerRecord.getBase();
running = false;
}
lottieAnimationViewVoice.cancelAnimation();
lottieAnimationViewVoice.setFrame(0);
lottieAnimationViewVoice.setVisibility(View.INVISIBLE);
recordingStatus = 2;
floatingActionButtonStartRecording.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_play_green, null));
textViewInformation.setText(getString(R.string.tap_to_resume));
Toast.makeText(context, getString(R.string.paused), Toast.LENGTH_SHORT).show();
}
private void resumeRecording() {
if (Build.VERSION.SDK_INT >= 24) {
mediaRecorder.resume();
}
chronometerRecord.setBase(SystemClock.elapsedRealtime() - pauseOffset);
chronometerRecord.start();
lottieAnimationViewVoice.playAnimation();
lottieAnimationViewVoice.setVisibility(View.VISIBLE);
recordingStatus = 1;
floatingActionButtonStartRecording.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_pause_orange, null));
textViewInformation.setText(getString(R.string.recording));
Toast.makeText(context, getString(R.string.resume), Toast.LENGTH_SHORT).show();
}
#SuppressLint("SetTextI18n")
private void finishRecording() {
chronometerRecord.setVisibility(View.INVISIBLE);
chronometerRecord.stop();
chronometerRecord.setBase(SystemClock.elapsedRealtime());
pauseOffset = 0;
mediaRecorder.stop();
mediaRecorder = null;
recordingStatus = 3;
floatingActionButtonStartRecording.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_app, null));
Toast.makeText(context, getString(R.string.saved) + " " + fileName, Toast.LENGTH_LONG).show();
textViewInformation.setText(getString(R.string.tap_to_record));
lottieAnimationViewVoice.cancelAnimation();
lottieAnimationViewVoice.setFrame(0);
lottieAnimationViewVoice.setVisibility(View.INVISIBLE);
recordingStatus = 0;
}
#SuppressLint("SetTextI18n")
private void cancelRecording() {
chronometerRecord.setVisibility(View.INVISIBLE);
chronometerRecord.stop();
chronometerRecord.setBase(SystemClock.elapsedRealtime());
pauseOffset = 0;
try {
mediaRecorder.stop();
} catch (RuntimeException e) {
e.printStackTrace();
mediaRecorder = null;
mediaRecorder = new MediaRecorder();
} finally {
if (mediaRecorder != null) {
mediaRecorder = null;
}
}
File file = new File(outPutFilePath);
if (file.exists()) {
boolean deleted = file.delete();
if (deleted) {
Log.d("Voice Recorder", "Deleted file successfully!");
}
}
recordingStatus = 3;
floatingActionButtonStartRecording.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_app, null));
Toast.makeText(context, getString(R.string.cancelled) + " " + fileName, Toast.LENGTH_LONG).show();
textViewInformation.setText(getString(R.string.tap_to_record));
lottieAnimationViewVoice.cancelAnimation();
lottieAnimationViewVoice.setFrame(0);
lottieAnimationViewVoice.setVisibility(View.INVISIBLE);
recordingStatus = 0;
}
private String getCurrentDateFormatted() {
return new SimpleDateFormat("dd-MM-yy|hh:mm:ss", Locale.getDefault()).format(new Date());
}
private void askPermissions() {
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(context,
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
assert getParentFragment() != null;
requestPermissions(permissions, Constants.RECORD_AUDIO_AND_WRITE_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull final String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(context,
Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(context, getString(R.string.permission_granted), Toast.LENGTH_SHORT).show();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(getString(R.string.no_read_permission))
.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(context,
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(permissions, Constants.RECORD_AUDIO_AND_WRITE_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
}
}
}).setNegativeButton(getString(R.string.go_to_settings), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", "com.venomapps.voicerecorder", null);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.setData(uri);
context.startActivity(intent);
requireActivity().finish();
}
});
builder.create();
builder.show();
}
}
}
PlaylistFragment.java:
import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Environment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.venomapps.voicerecorder.Adapters.PlaylistAdapter;
import com.venomapps.voicerecorder.R;
import java.io.File;
import java.io.IOException;
public class PlaylistFragment extends Fragment implements PlaylistAdapter.onItemListClick {
private BottomSheetBehavior bottomSheetBehavior;
private RecyclerView recyclerViewPlaylist;
private File[] files;
private PlaylistAdapter playlistAdapter;
private MediaPlayer mediaPlayer = null;
private boolean isPlaying = false;
private File fileToPlay;
public PlaylistFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFiles();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_playlist_item_list, container, false);
// Set the adapter
if (view instanceof RecyclerView) {
Context context = view.getContext();
RecyclerView recyclerView = (RecyclerView) view;
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
recyclerView.setLayoutManager(linearLayoutManager);
}
return view;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
bindUI(view);
setListeners();
setAdapter();
}
private void bindUI(View view) {
ConstraintLayout constraintLayoutMediaPlayer = view.findViewById(R.id.constraintLayoutMediaPlayer);
bottomSheetBehavior = BottomSheetBehavior.from(constraintLayoutMediaPlayer);
recyclerViewPlaylist = view.findViewById(R.id.recyclerViewPlaylist);
}
private void setListeners() {
bottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
}
});
}
private void getFiles() {
String path = Environment.getExternalStorageDirectory().toString() + File.separator + "Voice Recorder";
File directory = new File(path);
files = directory.listFiles();
}
private void setAdapter() {
playlistAdapter = new PlaylistAdapter(files, this);
recyclerViewPlaylist.setHasFixedSize(true);
recyclerViewPlaylist.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerViewPlaylist.setAdapter(playlistAdapter);
}
#Override
public void onClickListener(File file, int position) throws IOException {
if(isPlaying){
stopAudio();
playAudio(fileToPlay);
}else{
fileToPlay = file;
playAudio(fileToPlay);
}
}
private void playAudio(File fileToPlay) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(fileToPlay.getAbsolutePath());
mediaPlayer.prepare();
mediaPlayer.start();
}catch (Exception e){
e.printStackTrace();
}
isPlaying = true;
}
private void stopAudio(){
isPlaying = false;
}
}
-PlaylistAdapter.java:
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.venomapps.voicerecorder.Utils.TimeAgo;
import com.venomapps.voicerecorder.R;
import java.io.File;
import java.io.IOException;
public class PlaylistAdapter extends RecyclerView.Adapter<PlaylistAdapter.PlaylistViewHolder> {
private static File[] files;
private TimeAgo timeAgo;
private Context context;
private static onItemListClick onItemListClick;
public PlaylistAdapter(File[] files, onItemListClick onItemListClick) {
PlaylistAdapter.files = files;
PlaylistAdapter.onItemListClick = onItemListClick;
}
#NonNull
#Override
public PlaylistViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_playlist_item, parent, false);
context = parent.getContext();
timeAgo = new TimeAgo();
return new PlaylistViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull PlaylistViewHolder holder, int position) {
holder.textViewPlaylistFileName.setText(files[position].getName());
holder.textViewPlaylistStats.setText(timeAgo.getTimeAgo(files[position].lastModified(), context));
if(position == getItemCount() - 1){
holder.playlistSeparator.setVisibility(View.INVISIBLE);
}
}
#Override
public int getItemCount() {
return files.length;
}
public static class PlaylistViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private final TextView textViewPlaylistFileName;
private final TextView textViewPlaylistStats;
private final View playlistSeparator;
private final FloatingActionButton floatingActionButtonPlaylistPlay;
private final ImageButton imageButtonPlaylistItem;
public PlaylistViewHolder(#NonNull View itemView) {
super(itemView);
textViewPlaylistFileName = itemView.findViewById(R.id.textViewPlaylistFileName);
textViewPlaylistStats = itemView.findViewById(R.id.textViewPlaylistStats);
playlistSeparator = itemView.findViewById(R.id.playlistSeparator);
floatingActionButtonPlaylistPlay = itemView.findViewById(R.id.floatingActionButtonPlaylistPlay);
imageButtonPlaylistItem = itemView.findViewById(R.id.imageButtonPlaylistItem);
floatingActionButtonPlaylistPlay.setOnClickListener(this);
}
#Override
public void onClick(View v) {
try {
onItemListClick.onClickListener(files[getAdapterPosition()], getAdapterPosition());
} catch (IOException e) {
e.printStackTrace();
}
}
}
public interface onItemListClick{
void onClickListener(File file, int position) throws IOException;
}
}
Firstly, I suggest you to post full error log, and only the code which create the problem (and not your entire project ...)
There is 3 possibilities which can create your problem :
File problem (path or file not exist).
Wrong format (or not supported one).
Not permission. Do file.setReadable(true); to fix this
More informations here : https://stackoverflow.com/a/11977292/10952503
I am attempting to to create a widget from a native view navigation map using method channels and AndroidViews but I keep running into this problem:
E/MethodChannel#flutter/platform_views( 2258): Failed to handle method call
E/MethodChannel#flutter/platform_views( 2258): java.lang.IllegalArgumentException: Cannot add a null child view to a ViewGroup.
Here is the flutter Code :
Main.dart
import 'navigation_view.dart';
import 'package:expandable_bottom_sheet/expandable_bottom_sheet.dart';
import 'package:flutter/material.dart';
import 'customButton1.dart';
import 'Constantes.dart';
void main() => runApp(MaterialApp(home: TextViewExample()));
class TextViewExample extends StatefulWidget {
#override
_TextViewExampleState createState() => _TextViewExampleState();
}
class _TextViewExampleState extends State<TextViewExample>
with SingleTickerProviderStateMixin {
#override
void initState() {
super.initState();
}
Widget build(BuildContext context) {
// var s = NavigationView(
// onNavigationViewCreated: _onNavigationViewCreated,
// );
double screenWidth, screenHeight;
Size size = MediaQuery.of(context).size;
screenHeight = size.height;
screenWidth = size.width;
print("FLUTTER INIT");
return Scaffold(
body: SafeArea(
child: Stack(children: [
Positioned(
width: screenWidth,
height: screenHeight - 220,
child: Container(
child: NavigationView(
onNavigationViewCreated: _onNavigationViewCreated,
),
),
),
Positioned(
bottom: 75,
child: Container(
height: screenHeight,
width: screenWidth,
void _onNavigationViewCreated(NavigationViewController controller) {}
}
Here is navigation_view.dart
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
typedef void NavigationViewCreatedCallback(NavigationViewController controller);
class NavigationView extends StatefulWidget {
const NavigationView({
Key key,
this.onNavigationViewCreated,
}) : super(key: key);
final NavigationViewCreatedCallback onNavigationViewCreated;
#override
State<StatefulWidget> createState() => _NavigationViewState();
}
class _NavigationViewState extends State<NavigationView> {
#override
Widget build(BuildContext context) {
if (defaultTargetPlatform == TargetPlatform.android) {
return AndroidView(
viewType: 'com.Mavic.Cabinn/navigationview',
onPlatformViewCreated: _onPlatformViewCreated,
);
}
return Text(
'$defaultTargetPlatform is not yet supported by the navigation_view plugin');
}
void _onPlatformViewCreated(int id) {
if (widget.onNavigationViewCreated == null) {
return;
}
widget.onNavigationViewCreated(new NavigationViewController._(id));
}
}
class NavigationViewController {
NavigationViewController._(int id)
: _channel = new MethodChannel(
'com.Mavic.Cabinn/navigationview$id');
final MethodChannel _channel;
// Future<void> setNavigation() async {
// try {
// Future.delayed(const Duration(seconds: 1), () async {
// await _channel.invokeMethod('EmpezarNavegacion');
//
// return;
// });
// } on PlatformException catch (e) {
// print(e);
// }
// Future<void> setNavigation() async {
// assert(AndroidView != null);
// return _channel.invokeMethod('EmpezarNavegacion');
// }
//}
Future<dynamic> setNavigation() async {
String message;
try {
final String result = await _channel.invokeMethod('EmpezarNagevacion');
message = result;
} on PlatformException catch (e) {
print(message);
}
}
}
And Finally the Java Code
package com.example.embeded_java_test;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.location.Location;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.AbsoluteSizeSpan;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.mapbox.api.directions.v5.DirectionsCriteria;
import com.mapbox.api.directions.v5.models.BannerInstructions;
import com.mapbox.api.directions.v5.models.DirectionsResponse;
import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.services.android.navigation.ui.v5.route.NavigationMapRoute;
import com.example.embeded_java_test.R;
import com.mapbox.services.android.navigation.ui.v5.NavigationView;
import com.mapbox.services.android.navigation.ui.v5.NavigationViewOptions;
import com.mapbox.services.android.navigation.ui.v5.OnNavigationReadyCallback;
//import com.mapbox.services.android.navigation.ui.v5.listeners.BannerInstructionsListener;
//import com.mapbox.services.android.navigation.ui.v5.listeners.InstructionListListener;
import com.mapbox.services.android.navigation.ui.v5.listeners.BannerInstructionsListener;
import com.mapbox.services.android.navigation.ui.v5.listeners.InstructionListListener;
import com.mapbox.services.android.navigation.ui.v5.listeners.NavigationListener;
//import com.mapbox.services.android.navigation.ui.v5.listeners.SpeechAnnouncementListener;
//import com.mapbox.services.android.navigation.ui.v5.voice.SpeechAnnouncement;
import com.mapbox.services.android.navigation.ui.v5.listeners.SpeechAnnouncementListener;
import com.mapbox.services.android.navigation.ui.v5.voice.SpeechAnnouncement;
import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute;
import com.mapbox.services.android.navigation.v5.routeprogress.ProgressChangeListener;
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;
import java.util.Locale;
import java.util.concurrent.Future;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import org.jetbrains.annotations.NotNull;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.platform.PlatformView;
import com.example.embeded_java_test.MainActivity;
public class EmbeddedNavigationActivity extends AppCompatActivity implements OnNavigationReadyCallback,
NavigationListener, ProgressChangeListener, InstructionListListener, SpeechAnnouncementListener,
BannerInstructionsListener,PlatformView, MethodCallHandler {
private Point ORIGIN = Point.fromLngLat(-77.03194990754128, 38.909664963450105);
private Point DESTINATION = Point.fromLngLat(-77.0270025730133, 38.91057077063121);
private final int INITIAL_ZOOM = 16;
private NavigationView navigationView;
private View spacer;
private TextView speedWidget;
private final MethodChannel methodChannel;
private boolean bottomSheetVisible = true;
private boolean instructionListShown = false;
private NavigationMapRoute navigationMapRoute;
// #Override
// public void onCreate(#Nullable Bundle savedInstanceState) {
// super.onCreate(savedInstanceState);
// navigationView = findViewById(R.id.navigationView);
// navigationView.onCreate(savedInstanceState);
// setTheme(R.style.Theme_AppCompat_Light_NoActionBar);
// //initNightMode();
#Override
public void dispose() {}
private Context context;
private Activity activity;
private Bundle savedInstance;
public EmbeddedNavigationActivity(Context currentContext, Activity currentActivity, Bundle currentBundle,BinaryMessenger messenger, int id)
{
new MainActivity();
MainActivity newMain = new MainActivity();
this.activity=this;
System.out.println(activity + "Activity");
this.context=this;
System.out.println(context + "Context");
System.out.println(activity);
Log.i("Here", "Constructor!!!");
System.out.println(activity + " This Activity");
this.savedInstance=currentBundle;
System.out.println(currentContext + "Context");
//
methodChannel = new MethodChannel(messenger, "com.Mavic.Cabinn/navigationview_" + id);
methodChannel.setMethodCallHandler(this);
}
#Override
public View getView() {
Log.i("Here", "GETVIEW");
return navigationView;
}
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
Log.i("MSG", "CALLING SET TEXT");
switch (methodCall.method) {
case "EmpezarNavegacion":
EmpezarNavegacion(methodCall, result);
result.success(null);
break;
default:
result.notImplemented();
}
}
public void EmpezarNavegacion(MethodCall methodCall, Result result)
{
double LtLang = (double) methodCall.arguments;
result.success(null);
Mapbox.getInstance(context, activity.getString(R.string.access_token));
activity.setContentView(R.layout.cabinn_nav);
navigationView =activity.findViewById(R.id.navigationView);
//super.onCreate(savedInstanceState);
//Mapbox.getInstance(this,getString(R.string.access_token));
//navigationView =(NavigationView)findViewById(R.id.navigationView);
if(navigationView==null)
{
Log.e("ERROR NAVEGACION","NAVIGATION VIEW ES NULL, NO ESTA SETEADO EL CONTENT");
return;
}
//fabNightModeToggle = findViewById(R.id.fabToggleNightMode);
//speedWidget = findViewById(R.id.speed_limit);
//spacer = findViewById(R.id.spacer);
//setSpeedWidgetAnchor(R.id.summaryBottomSheet);
// ORIGIN=ORIGEN;
// DESTINATION=DESTINO;
CameraPosition initialPosition = new CameraPosition.Builder()
.target(new LatLng(ORIGIN.latitude(), ORIGIN.longitude()))
.zoom(INITIAL_ZOOM)
.build();
//navigationView.onCreate(savedInstanceState);
navigationView.onCreate(this.savedInstance);
navigationView.initialize(this, initialPosition);
}
#Override
public void onNavigationReady(boolean isRunning) {
//navigationView.findViewById(R.id.instructionLayoutText).setVisibility(View.INVISIBLE);
navigationView.findViewById(R.id.instructionListLayout).setVisibility(View.INVISIBLE);
//navigationView.findViewById(R.id.maneuverView).setVisibility(View.INVISIBLE);
navigationView.findViewById(R.id.summaryBottomSheet).setVisibility(View.INVISIBLE);
navigationView.findViewById(R.id.feedbackFab).setVisibility(View.INVISIBLE);
navigationView.findViewById(R.id.subStepText).setVisibility(View.INVISIBLE);
navigationView.findViewById(R.id.subStepLayout).setVisibility(View.INVISIBLE);
navigationView.findViewById(R.id.summaryContentLayout).setVisibility(View.INVISIBLE);
//navigationView.findViewById(R.id.subManeuverView).setVisibility(View.INVISIBLE);
//navigationView.findViewById(R.id.stepDistanceText).setVisibility(View.INVISIBLE);
//navigationView.findViewById(R.id.stepPrimaryText).setVisibility(View.INVISIBLE);
//navigationView.findViewById(R.id.stepSecondaryText).setVisibility(View.INVISIBLE);
fetchRoute();
}
public void onStart_() {
Log.i("NAV","NAVIGATION START");
navigationView.onStart();
}
public void onResume_() {
navigationView.onResume();
}
public void onLowMemory_() {
navigationView.onLowMemory();
}
public void onBackPressed_() {
// If the navigation view didn't need to do anything, call super
if (!navigationView.onBackPressed()) {
super.onBackPressed();
}
}
protected void onSaveInstanceState_(Bundle outState) {
navigationView.onSaveInstanceState(outState);
}
protected void onRestoreInstanceState_(Bundle savedInstanceState) {
navigationView.onRestoreInstanceState(savedInstanceState);
}
public void onPause_() {
navigationView.onPause();
}
public void onStop_() {
navigationView.onStop();
}
protected void onDestroy_() {
navigationView.onDestroy();
if (isFinishing()) {
saveNightModeToPreferences(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
}
}
#Override
public void onCancelNavigation() {
// Navigation canceled, finish the activity
finish();
}
#Override
public void onNavigationFinished() {
// Intentionally empty
}
#Override
public void onNavigationRunning() {
// Intentionally empty
}
#Override
public void onProgressChange(Location location, RouteProgress routeProgress) {
setSpeed(location);
}
#Override
public void onInstructionListVisibilityChanged(boolean shown) {
instructionListShown = shown;
speedWidget.setVisibility(shown ? View.GONE : View.VISIBLE);
if (instructionListShown) {
// fabNightModeToggle.hide();
} else if (bottomSheetVisible) {
//fabNightModeToggle.show();
}
}
#Override
public SpeechAnnouncement willVoice(SpeechAnnouncement announcement) {
return SpeechAnnouncement.builder().announcement("All announcements will be the same.").build();
}
#Override
public BannerInstructions willDisplay(BannerInstructions instructions) {
return instructions;
}
private void startNavigation(DirectionsRoute directionsRoute) {
NavigationViewOptions.Builder options =
NavigationViewOptions.builder()
.navigationListener(this)
.directionsRoute(directionsRoute)
.shouldSimulateRoute(true)
.progressChangeListener(this);
//.instructionListListener(this)
//.speechAnnouncementListener(this)
// .bannerInstructionsListener(this);
setBottomSheetCallback(options);
//setupNightModeFab();
navigationView.startNavigation(options.build());
}
private void fetchRoute() {
NavigationRoute.builder(this.context)
.accessToken(this.activity.getString(R.string.access_token))
.origin(ORIGIN)
.voiceUnits(DirectionsCriteria.METRIC)
.destination(DESTINATION)
.alternatives(true)
.build()
.getRoute(new Callback<DirectionsResponse>() {
#Override
public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
if(response.body() == null)
{
Log.e("ERROR RUTA","NO RUTA ENCONTRADA");
return;
}else if(response.body().routes().size()==0)
{
Log.e("ERROR RUTA","SIN RUTA ENCONTRADA");
return;
}
DirectionsRoute currentRoute = response.body().routes().get(0);
//navigationMapRoute.addRoute(currentRoute);
startNavigation(currentRoute);
}
#Override
public void onFailure(Call<DirectionsResponse> call, Throwable t) {
}
});
}
void simpleCallBack(Call<DirectionsResponse> call, Response<DirectionsResponse> response)
{
DirectionsRoute directionsRoute = response.body().routes().get(0);
startNavigation(directionsRoute);
}
private void setSpeedWidgetAnchor(#IdRes int res) {
//CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) spacer.getLayoutParams();
//layoutParams.setAnchorId(res);
//spacer.setLayoutParams(layoutParams);
}
private void setBottomSheetCallback(NavigationViewOptions.Builder options) {
options.bottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
switch (newState) {
case BottomSheetBehavior.STATE_HIDDEN:
bottomSheetVisible = false;
//fabNightModeToggle.hide();
setSpeedWidgetAnchor(R.id.recenterBtn);
break;
case BottomSheetBehavior.STATE_EXPANDED:
bottomSheetVisible = true;
break;
case BottomSheetBehavior.STATE_SETTLING:
if (!bottomSheetVisible) {
// View needs to be anchored to the bottom sheet before it is finished expanding
// because of the animation
//fabNightModeToggle.show();
setSpeedWidgetAnchor(R.id.summaryBottomSheet);
}
break;
default:
return;
}
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
}
});
}
private void setupNightModeFab() {
//fabNightModeToggle.setOnClickListener(view -> toggleNightMode());
}
private void toggleNightMode() {
int currentNightMode = getCurrentNightMode();
alternateNightMode(currentNightMode);
}
private void initNightMode() {
// int nightMode = retrieveNightModeFromPreferences();
//AppCompatDelegate.setDefaultNightMode(nightMode);
}
private int getCurrentNightMode() {
return getResources().getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_MASK;
}
private void alternateNightMode(int currentNightMode) {
int newNightMode;
if (currentNightMode == Configuration.UI_MODE_NIGHT_YES) {
newNightMode = AppCompatDelegate.MODE_NIGHT_NO;
} else {
newNightMode = AppCompatDelegate.MODE_NIGHT_YES;
}
saveNightModeToPreferences(newNightMode);
recreate();
}
private void saveNightModeToPreferences(int nightMode) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = preferences.edit();
//editor.putInt(getString(R.string.current_night_mode), nightMode);
editor.apply();
}
private void setSpeed(Location location) {
String string = String.format("%d\nMPH", (int) (location.getSpeed() * 2.2369));
//int mphTextSize = getResources().getDimensionPixelSize(R.dimen.mph_text_size);
//int speedTextSize = getResources().getDimensionPixelSize(R.dimen.speed_text_size);
SpannableString spannableString = new SpannableString(string);
// spannableString.setSpan(new AbsoluteSizeSpan(mphTextSize),
// string.length() - 4, string.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
// spannableString.setSpan(new AbsoluteSizeSpan(speedTextSize),
// 0, string.length() - 3, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
}
I used this article as reference in order to attempt to replicate this but I hit many a speed bump trying to get this to work properly: https://medium.com/flutter-community/flutter-platformview-how-to-create-flutter-widgets-from-native-views-366e378115b6
This is my flutter doctor output:
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.12.13+hotfix.9, on Linux, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[✓] Android Studio (version 3.6)
[✓] Connected device (1 available)
• No issues found!
Like I was saying ive been attempting to find a null value and searched high and low for questions similar to this one but Ive had no such luck as this is not something Ive seen done. I also checked if there were any plugins to create and embedded map and unfortunately there arent any at the moment.
I am working on GoogleFit Api for daily steps count. I am getting the correct result. But when i sign out the application (In this case, app exit the Googlefit fragment's parent activity)
After sign in again, i access the same fragment again, but Googlefit returns the stepsCount as zero and getting times out at result.await.
Here is my Code.
GoogleFitFragment.java
package com.example.mudasirrao.mvvm.Fragments.GoogleFitFragments;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.example.mudasirrao.mvvm.R;
import com.example.mudasirrao.mvvm.ViewModel.GoogleFitViewModels.GoogleFitViewModel;
import com.example.mudasirrao.mvvm.databinding.FragmentGoogleFitBinding;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.fitness.ConfigApi;
import com.google.android.gms.fitness.Fitness;
import com.google.android.gms.fitness.result.DataTypeResult;
public class GoogleFitFragment extends Fragment {
GoogleFitViewModel googleFitViewModel;
public GoogleFitFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
FragmentGoogleFitBinding fragmentGoogleFitBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_google_fit, container, false);
View view = fragmentGoogleFitBinding.getRoot();
googleFitViewModel = new GoogleFitViewModel(getActivity(), fragmentGoogleFitBinding);
fragmentGoogleFitBinding.setGoogleFitFragmentViewModel(googleFitViewModel);
return view;
}
}
GoogleFitViewModel.java
package com.example.mudasirrao.mvvm.ViewModel.GoogleFitViewModels;
import android.content.Context;
import android.content.SharedPreferences;
import android.databinding.ObservableField;
import android.os.AsyncTask;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.example.mudasirrao.mvvm.CallBacks.CallBackGoogleFitClient;
import com.example.mudasirrao.mvvm.DataManager.GoogleFitDataManager;
import com.example.mudasirrao.mvvm.databinding.FragmentGoogleFitBinding;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.fitness.ConfigApi;
import com.google.android.gms.fitness.Fitness;
import com.google.android.gms.fitness.data.DataSet;
import com.google.android.gms.fitness.data.DataType;
import com.google.android.gms.fitness.data.Field;
import com.google.android.gms.fitness.result.DailyTotalResult;
import java.util.concurrent.TimeUnit;
import static android.content.Context.MODE_PRIVATE;
public class GoogleFitViewModel {
private Context context;
private FragmentGoogleFitBinding fragmentGoogleFitBinding;
public final ObservableField<String> steps = new ObservableField<>();
public GoogleApiClient localGoogleApiClient;
String dailySteps;
public GoogleFitViewModel(Context context, final FragmentGoogleFitBinding fragmentGoogleFitBinding) {
this.context = context;
this.fragmentGoogleFitBinding = fragmentGoogleFitBinding;
SharedPreferences prefs = context.getSharedPreferences("dailySteps", MODE_PRIVATE);
dailySteps = prefs.getString("daily_steps", null);
if (dailySteps != null) {
steps.set(dailySteps);
GoogleFitDataManager.singletonObject(context).buildFitnessClient(new CallBackGoogleFitClient() {
#Override
public void onResponse(GoogleApiClient googleApiClient) {
localGoogleApiClient = googleApiClient;
if (googleApiClient != null) {
new VerifyDataTask().execute(localGoogleApiClient);
fragmentGoogleFitBinding.setGoalLayout.animate().alpha(0.2f).setDuration(1000);
enableDisableLayout(false);
fragmentGoogleFitBinding.previewImage.setVisibility(View.GONE);
fragmentGoogleFitBinding.saveButton.setText("Edit");
fragmentGoogleFitBinding.saveButton.setTag("disabled_edit");
fragmentGoogleFitBinding.goalProgressLayout.setVisibility(View.VISIBLE);
fragmentGoogleFitBinding.goalText.setText("Take " + steps.get() + " steps a day");
}
}
});
} else {
steps.set("0000");
fragmentGoogleFitBinding.setGoalLayout.animate().alpha(1.0f).setDuration(3000);
}
}
public void onClickStepsButton1(View view) {
steps.set("2000");
}
public void onClickStepsButton2(View view) {
steps.set("8000");
}
public void onClickStepsButton3(View view) {
steps.set("10000");
}
public void onClickStepsButton4(View view) {
steps.set("13000");
}
public void onClickSave(View view) {
if ((Integer.valueOf(steps.get()) > 0)) {
if (fragmentGoogleFitBinding.saveButton.getTag() == null) {
GoogleFitDataManager.singletonObject(context).buildFitnessClient(new CallBackGoogleFitClient() {
#Override
public void onResponse(GoogleApiClient googleApiClient) {
localGoogleApiClient = googleApiClient;
if (googleApiClient != null) {
new VerifyDataTask().execute(localGoogleApiClient);
fragmentGoogleFitBinding.setGoalLayout.animate().alpha(0.2f).setDuration(1000);
enableDisableLayout(false);
fragmentGoogleFitBinding.previewImage.setVisibility(View.GONE);
fragmentGoogleFitBinding.saveButton.setText("Edit");
fragmentGoogleFitBinding.saveButton.setTag("disabled_edit");
fragmentGoogleFitBinding.goalProgressLayout.setVisibility(View.VISIBLE);
}
}
});
} else {
if (fragmentGoogleFitBinding.saveButton.getTag().equals("disabled_edit")) {
fragmentGoogleFitBinding.setGoalLayout.animate().alpha(1.0f).setDuration(1000);
enableDisableLayout(true);
fragmentGoogleFitBinding.saveButton.setTag("enabled_edit");
fragmentGoogleFitBinding.saveButton.setText("Save");
} else if (fragmentGoogleFitBinding.saveButton.getTag().equals("enabled_edit")) {
new VerifyDataTask().execute(localGoogleApiClient);
fragmentGoogleFitBinding.setGoalLayout.animate().alpha(0.2f).setDuration(1000);
enableDisableLayout(false);
fragmentGoogleFitBinding.saveButton.setText("Edit");
fragmentGoogleFitBinding.saveButton.setTag("disabled_edit");
}
}
fragmentGoogleFitBinding.goalText.setText("Take " + steps.get() + " steps a day");
} else
Toast.makeText(context, "Please Select Steps", Toast.LENGTH_SHORT).show();
}
protected void renderStepsProgress(int stepsTaken) {
saveDailyStepsInSharedPref(steps.get());
int percentage = (int) (((double) stepsTaken / (double) Integer.valueOf(steps.get())) * 100);
if (percentage > 100) {
percentage = 100;
}
fragmentGoogleFitBinding.waveLoadingView.setCenterTitle(String.valueOf(percentage) + " %");
fragmentGoogleFitBinding.waveLoadingView.setProgressValue(percentage);
fragmentGoogleFitBinding.stepsTakenText.setText("You have taken " + String.valueOf(stepsTaken) + " steps today");
}
private void enableDisableLayout(Boolean visibility) {
View child;
for (int i = 0; i < fragmentGoogleFitBinding.stepButtonLayout1.getChildCount(); i++) {
child = fragmentGoogleFitBinding.stepButtonLayout1.getChildAt(i);
child.setEnabled(visibility);
}
for (int i = 0; i < fragmentGoogleFitBinding.stepButtonLayout2.getChildCount(); i++) {
child = fragmentGoogleFitBinding.stepButtonLayout2.getChildAt(i);
child.setEnabled(visibility);
}
}
private void saveDailyStepsInSharedPref(String dailySteps) {
SharedPreferences.Editor editor = context.getSharedPreferences("dailySteps", MODE_PRIVATE).edit();
editor.putString("daily_steps", dailySteps);
editor.apply();
}
private class VerifyDataTask extends AsyncTask<GoogleApiClient, Void, Integer> {
#Override
protected Integer doInBackground(GoogleApiClient... params) {
int total = 0;
PendingResult<DailyTotalResult> result = Fitness.HistoryApi.readDailyTotal(params[0], DataType.TYPE_STEP_COUNT_DELTA);
DailyTotalResult totalResult = result.await(30, TimeUnit.SECONDS);
if (totalResult.getStatus().isSuccess()) {
DataSet totalSet = totalResult.getTotal();
total = totalSet.isEmpty()
? 0
: totalSet.getDataPoints().get(0).getValue(Field.FIELD_STEPS).asInt();
} else {
Log.d("steps_count_error", "There was a problem getting the step count!!");
}
return total;
}
protected void onPostExecute(Integer result) {
renderStepsProgress(result);
}
}
}
GoogleFitDataManager.java
package com.example.mudasirrao.mvvm.DataManager;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.widget.Toast;
import com.example.mudasirrao.mvvm.CallBacks.CallBackGoogleFitClient;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.fitness.Fitness;
import com.google.android.gms.fitness.FitnessStatusCodes;
import com.google.android.gms.fitness.data.DataType;
import static com.bumptech.glide.gifdecoder.GifHeaderParser.TAG;
public class GoogleFitDataManager {
private static GoogleFitDataManager googleFitDataManager;
private GoogleApiClient googleApiClient = null;
private Context context;
public GoogleFitDataManager(Context context) {
this.context = context;
}
public static GoogleFitDataManager singletonObject(Context context) {
if (googleFitDataManager == null) {
googleFitDataManager = new GoogleFitDataManager(context);
}
return googleFitDataManager;
}
public void buildFitnessClient(final CallBackGoogleFitClient callBackGoogleFitClient) {
if (googleApiClient == null) {
googleApiClient = new GoogleApiClient.Builder(context)
.addApi(Fitness.HISTORY_API)
.addApi(Fitness.RECORDING_API)
.addApi(Fitness.CONFIG_API)
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(#Nullable Bundle bundle) {
subscribeGoogleFit(googleApiClient);
callBackGoogleFitClient.onResponse(googleApiClient);
}
#Override
public void onConnectionSuspended(int i) {
if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Toast.makeText(context, "Connection lost. Cause: Network Lost.", Toast.LENGTH_SHORT).show();
} else if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Toast.makeText(context, "Connection lost. Reason: Service Disconnected", Toast.LENGTH_SHORT).show();
}
}
}
)
.enableAutoManage((FragmentActivity) context, 0, new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i("TAG", "Google Play services connection failed. Cause: " + result.toString());
Toast.makeText(context, "Exception while connecting to Google Play services: " + result.getErrorMessage(), Toast.LENGTH_SHORT).show();
}
})
.build();
} else {
subscribeGoogleFit(googleApiClient);
callBackGoogleFitClient.onResponse(googleApiClient);
}
}
public void subscribeGoogleFit(GoogleApiClient client) {
Fitness.RecordingApi.subscribe(client, DataType.TYPE_STEP_COUNT_DELTA)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
if (status.getStatusCode() == FitnessStatusCodes.SUCCESS_ALREADY_SUBSCRIBED) {
Log.i(TAG, "Existing subscription for activity detected.");
} else {
Log.i(TAG, "Successfully subscribed!");
}
} else {
Log.i(TAG, "There was a problem subscribing.");
}
}
});
}
}
What I was doing that I was creating the static object of the class in which I was making the googlefit client. In this case, when I exit the Activity, the object was not destroying and googlefit client was getting disconnected due to the enableAutoManage in onDestroy of the fragment. And as per my checks, I was not connecting to the googleFit client again.
I removed the object as static and now I stick the API client class object with the life cycle of the activity in which my fragment resides. Also I removed enableAutoManage and now connecting and disconnecting the API client by myself.
I have been stuck for hours . I have integrated admob ads on my application and I add it when user write something in edit text but it takes time to load ads some times it comes while some times skip .So user type the text and move to the next activity and my ads not load in time .
Can you give me some solution how to solve this issue !
thanks in advance
PassValues.java
package com.logixcess.wordguessing;
import android.content.Context;
import android.media.MediaPlayer;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.widget.Button;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.InterstitialAd;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* Created by ert on 17/04/2016.
*/
public class Passvalues {
public static String[] words , toCompare;
public static int score = 0,staticScore = 0,prevScore = 0,correctCount = 0;
public static String selectedWord;
public static List<String> repeated = null;
public static List<Button> buttonList = new ArrayList<Button>();
public static int[] hiscore = new int[5];
public static String[] hiscorename = new String[5];
public static MediaPlayer mediaPlayer;//sounds
public static MediaPlayer tones;//music
static float volLeft = 70,volRight = 70;
public static boolean sound = true,music=true;
public static boolean adCheck = false;
public static InterstitialAd interstitial;
public Passvalues()
{
words=null ; toCompare=null;
score = 0;prevScore = 0;correctCount = 0;
selectedWord="";
repeated = null;
buttonList = new ArrayList<Button>();
hiscore = new int[5];
hiscorename = new String[5];
adCheck = false;
}
public static void playMusic(Context context,int id)
{
if(Passvalues.music)
{
if(tones != null)
{
if (!tones.isPlaying()) {
tones = MediaPlayer.create(context, id);
tones.setLooping(true);
tones.start();
}
}
else {
tones = MediaPlayer.create(context, id);
tones.setLooping(true);
tones.start();
}
}
}
public static void stopMusic(){
/* if(!Passvalues.sound) {
if(tones != null)
{
if(tones.isPlaying()) {
stopPlaying(tones);
}
}
else
{
tones = null;
stopPlaying(tones);
}
}*/
if((!Passvalues.music)&&(!Passvalues.sound))
{
if(tones!=null)
{
stopPlaying(tones);
tones=null;
}
else
{
//pehlay se hi band hai music
}
if(mediaPlayer!=null)
{
stopPlaying(mediaPlayer);
mediaPlayer=null;
}
else
{
//peh;ay se hi sound band hai
}
}
}
public static void playSound(Context context,int id){
if(Passvalues.sound)
{
mediaPlayer = MediaPlayer.create(context, id);
mediaPlayer.start();
}
else if(mediaPlayer != null)
{
if(mediaPlayer.isPlaying()) {
stopPlaying(mediaPlayer);
}
if(mediaPlayer != null)
stopPlaying(mediaPlayer);
}
}
public static void stopPlaying(MediaPlayer mp)
{
if(mp!=null)
{
mp.stop();
mp.release();
mp=null;
}
}
public static boolean showad(Context context)
{
if(isNetworkAvailable(context))
{
if(interstitial == null)
interstitial = new InterstitialAd(context);
interstitial.setAdUnitId("ca-app-pub-7328520387956873/2174089947");
AdRequest adRequest = new AdRequest.Builder()
.addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
.build();
interstitial.loadAd(adRequest);
return true;
}
return false;
}
private static boolean isNetworkAvailable(Context context) {
ConnectivityManager connectivityManager
= (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
}
EnterHighScore.java
this is the activity for ads
package com.logixcess.wordguessing;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.InterstitialAd;
import com.logixcess.wordguessing.R;
import android.app.Activity;
import android.app.DialogFragment;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager.WakeLock;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.AbsListView;
import android.widget.Button;
import android.widget.EditText;
import com.google.android.gms.ads.AdListener;
public class EnterHiscore extends Activity {
int score;
EditText namebox;
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
onBackPressed();
super.onKeyDown(keyCode, event);
return true;
}
#Override
public void onBackPressed() {
Intent setIntent = new Intent(EnterHiscore.this,MainScreen.class);
//setIntent.addCategory(Intent.CATEGORY_HOME);
//setIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(setIntent);
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//set screen full screen and no title
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
//this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setContentView(R.layout.enterhiscore);
Passvalues.showad(EnterHiscore.this);
View backgroundImage = findViewById(R.id.bak);
Drawable background = backgroundImage.getBackground();
background.setAlpha(90);
//get score
score = Passvalues.staticScore; //getIntent().getIntExtra("score", 0);
//declare views
namebox = (EditText) findViewById(R.id.namebox);
Button save = (Button) findViewById(R.id.save);
namebox.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!Passvalues.adCheck) {
Passvalues.interstitial.setAdListener(new AdListener() {
#Override
public void onAdLoaded() {
super.onAdLoaded();
if (Passvalues.interstitial.isLoaded()) {
Passvalues.interstitial.show();
}
}
#Override
public void onAdClosed() {
//finish();
Passvalues.interstitial = null;
}
});
Passvalues.adCheck = true;
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
save.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
process_highscore(score, namebox.getText().toString());
}
});
}
public void loadscore() {
// load preferences
SharedPreferences hiscores = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
for (int i = 0; i < 5; i++) {
Passvalues.hiscore[i] = hiscores.getInt("score" + i, 0);
Passvalues.hiscorename[i] = hiscores.getString("name" + i, "---");
}
}
public void savescore() {
//load preferences
SharedPreferences hiscores = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor hiscores_editor = hiscores.edit();
for (int i = 0; i < 5; i++) {
hiscores_editor.putInt("score" + i, Passvalues.hiscore[i]);
hiscores_editor.putString("name" + i, Passvalues.hiscorename[i]);
}
hiscores_editor.commit();
loadscore();
}
public void process_highscore(int score, String name){
System.out.println("ll"+score + name);
loadscore();
boolean ready = false;
if (score > Passvalues.hiscore[0]) {
Passvalues.hiscore[4] = Passvalues.hiscore[3];
Passvalues.hiscorename[4] = Passvalues.hiscorename[3];
Passvalues.hiscore[3] = Passvalues.hiscore[2];
Passvalues.hiscorename[3] = Passvalues.hiscorename[2];
Passvalues.hiscore[2] = Passvalues.hiscore[1];
Passvalues.hiscorename[2] = Passvalues.hiscorename[1];
Passvalues.hiscore[1] = Passvalues.hiscore[0];
Passvalues.hiscorename[1] = Passvalues.hiscorename[0];
Passvalues.hiscore[0] = score;
Passvalues.hiscorename[0] = name;
ready = true;
}
if (score > Passvalues.hiscore[1] && score <= Passvalues.hiscore[0] && !ready) {
Passvalues.hiscore[4] = Passvalues.hiscore[3];
Passvalues.hiscorename[4] = Passvalues.hiscorename[3];
Passvalues.hiscore[3] = Passvalues.hiscore[2];
Passvalues.hiscorename[3] = Passvalues.hiscorename[2];
Passvalues.hiscore[2] = Passvalues.hiscore[1];
Passvalues.hiscorename[2] = Passvalues.hiscorename[1];
Passvalues.hiscore[1] = score;
Passvalues.hiscorename[1] = name;
ready = true;
}
if (score > Passvalues.hiscore[2] && score <= Passvalues.hiscore[1] && !ready) {
Passvalues.hiscore[4] = Passvalues.hiscore[3];
Passvalues.hiscorename[4] = Passvalues.hiscorename[3];
Passvalues.hiscore[3] = Passvalues.hiscore[2];
Passvalues.hiscorename[3] = Passvalues.hiscorename[2];
Passvalues.hiscore[2] = score;
Passvalues.hiscorename[2] = name;
ready = true;
}
if (score > Passvalues.hiscore[4] && score <= Passvalues.hiscore[3] && !ready) {
Passvalues.hiscore[4] = score;
Passvalues.hiscorename[4] = name;
}
savescore();
Intent i=new Intent(EnterHiscore.this,Highscore.class);
startActivity(i);
//go back to hiscores
finish();
}
}
Instead of displaying the ad in the #onAdLoaded() callback, display it in the natural break point in #onTextChanged():
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!Passvalues.adCheck) {
if (Passvalues.interstitial.isLoaded()) {
Passvalues.interstitial.show();
}
Passvalues.interstitial.setAdListener(new AdListener() {
#Override
public void onAdLoaded() {
super.onAdLoaded();
}
#Override
public void onAdClosed() {
//finish();
Passvalues.interstitial = null;
}
});
Passvalues.adCheck = true;
}
}
I'm working on a basic application that tells the user the amount of contours in the video feed in real time using OpenCV. I have this working, but about a minute into running the application closes and there are no logcat errors. I'm a new developer, but through some research believe this is a memory-leak issue. I think it has something to do with setting the text on each video frame. Here is my code:
import java.util.ArrayList;
import java.util.List;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.JavaCameraView;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.widget.TextView;
public class MainActivity extends Activity implements CvCameraViewListener2 {
static {
if (!OpenCVLoader.initDebug()) {
Log.d("ERROR", "Unable to load OpenCV");
}
else {
Log.d("SUCCESS", "OpenCV loaded");
}
}
private TextView contourCount;
//TAG for log
private static final String TAG = "Contour Count";
//Mats for image processing
private Mat mRgba;
private Mat mGray;
//Declare the cameraview
private JavaCameraView openCvCameraView;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
//OpenCv
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
#Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i(TAG, "OpenCV loaded successfully");
//Turn on cameraview
openCvCameraView.enableView();
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
//OnResume handling
#Override
public void onResume()
{
super.onResume();
openCvCameraView.enableView();
}
//OnCreate tasks
#Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "called onCreate");
super.onCreate(savedInstanceState);
//Keep the screen on while app is running
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//Set layout and initialize cameraView
setContentView(R.layout.fragment_main);
openCvCameraView = (JavaCameraView) findViewById(R.id.HelloOpenCvView);
openCvCameraView.setVisibility(SurfaceView.VISIBLE);
openCvCameraView.setCvCameraViewListener(this);
openCvCameraView.enableView();
}
//Handling onPause tasks - Disable Camera
#Override
public void onPause()
{
super.onPause();
if (openCvCameraView != null)
openCvCameraView.disableView();
}
//Handling onDestroy tasks - Disable Camera
public void onDestroy() {
super.onDestroy();
if (openCvCameraView != null)
openCvCameraView.disableView();
}
//New Mats for first onFrame
public void onCameraViewStarted(int width, int height) {
//Initialization of variables used for video analysis
mGray = new Mat();
mRgba = new Mat();
}
//Release the Mats when camera is stopped
public void onCameraViewStopped() {
mGray.release();
mRgba.release();
}
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
mGray = inputFrame.gray();
Mat imageHSV = new Mat(mRgba.size(), Core.DEPTH_MASK_8U);
Mat imageBlurr = new Mat(mRgba.size(), Core.DEPTH_MASK_8U);
Mat imageA = new Mat(mRgba.size(), Core.DEPTH_MASK_ALL);
Imgproc.cvtColor(mRgba, imageHSV, Imgproc.COLOR_BGR2GRAY);
Imgproc.GaussianBlur(imageHSV, imageBlurr, new Size(5,5), 0);
Imgproc.adaptiveThreshold(imageBlurr, imageA, 255,Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY,7, 5);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(imageA, contours, new Mat(), Imgproc.RETR_EXTERNAL,Imgproc.CHAIN_APPROX_SIMPLE);
setContours(contours.size());
return mRgba;
}
public void setContours(final int level) {
runOnUiThread(new Runnable() {
#Override
public void run() {
contourCount = (TextView) findViewById(R.id.contourLevel);
contourCount.setText("" + level);
}
});
}
}
The same issue occurs if I declare contourCount in onCreate(). I'm not sure if it has something to do with making level final in the method call for setContours(), but I have also tried to solve this using a handler that is declared in onCreate() and sending a message to it with the contours.size() within onCameraFrame() but this also causes the same issue. What am I doing wrong? How can I avoid this in the future? I am new to this so please be detailed in explaining the issue and future avoidance.
Thank you in advance! :)
EDIT SOLVED:
Figured it out. Thanks to everyone who contributed. Here is the working code for anyone interested or those with the same issue in the future!
The fix comes from releasing the Mats used in onCameraFrame
import java.util.ArrayList;
import java.util.List;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.JavaCameraView;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.widget.TextView;
public class MainActivity extends Activity implements CvCameraViewListener2 {
static {
if (!OpenCVLoader.initDebug()) {
Log.d("ERROR", "Unable to load OpenCV");
}
else {
Log.d("SUCCESS", "OpenCV loaded");
}
}
//TAG for log
private static final String TAG = "Contour Count";
//Mats for image processing
private Mat mRgba;
private Mat mGray;
private Mat imageHSV;
private Mat imageBlurr;
private Mat imageA;
private Mat hierarchy;
//Declare the cameraview
private JavaCameraView openCvCameraView;
private static String level;
private static TextView contourCount;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
//OpenCv
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
#Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i(TAG, "OpenCV loaded successfully");
//Turn on cameraview
openCvCameraView.enableView();
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
//OnResume handling
#Override
public void onResume()
{
super.onResume();
openCvCameraView.enableView();
}
//OnCreate tasks
#Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "called onCreate");
super.onCreate(savedInstanceState);
//Keep the screen on while app is running
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//Set layout and initialize cameraView
setContentView(R.layout.fragment_main);
openCvCameraView = (JavaCameraView) findViewById(R.id.HelloOpenCvView);
openCvCameraView.setVisibility(SurfaceView.VISIBLE);
openCvCameraView.setCvCameraViewListener(this);
openCvCameraView.enableView();
contourCount = (TextView) findViewById(R.id.contourLevel);
}
//Handling onPause tasks - Disable Camera
#Override
public void onPause()
{
super.onPause();
if (openCvCameraView != null)
openCvCameraView.disableView();
}
//Handling onDestroy tasks - Disable Camera
public void onDestroy() {
super.onDestroy();
if (openCvCameraView != null)
openCvCameraView.disableView();
}
//New Mats for first onFrame
public void onCameraViewStarted(int width, int height) {
//Initialization of variables used for video analysis
mGray = new Mat();
mRgba = new Mat();
}
//Release the Mats when camera is stopped
public void onCameraViewStopped() {
mGray.release();
mRgba.release();
}
//onCameraFrame image processing
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
imageHSV = new Mat(mRgba.size(), Core.DEPTH_MASK_8U);
imageBlurr = new Mat(mRgba.size(), Core.DEPTH_MASK_8U);
imageA = new Mat(mRgba.size(), Core.DEPTH_MASK_ALL);
hierarchy = new Mat();
Imgproc.cvtColor(mRgba, imageHSV, Imgproc.COLOR_BGR2GRAY);
Imgproc.GaussianBlur(imageHSV, imageBlurr, new Size(5,5), 0);
Imgproc.adaptiveThreshold(imageBlurr, imageA, 255,Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY,7, 5);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(imageA, contours, hierarchy, Imgproc.RETR_EXTERNAL,Imgproc.CHAIN_APPROX_SIMPLE);
//Imgproc.findContours(imageA, contours, new Mat(), Imgproc.RETR_LIST,Imgproc.CHAIN_APPROX_SIMPLE);
level = "" + contours.size();
setContour();
imageHSV.release();
imageBlurr.release();
imageA.release();
hierarchy.release();
return mRgba;
}
public void setContour() {
runOnUiThread(new Runnable() {
#Override
public void run() {
contourCount.setText(level);
}
});
}
}
In the past when creating memory intensive apps I've had to manually increase the amount of memory the app has access to. There may not necessarily be a OOM error, but the app may simply be extremely memory intensive.
Try adding this to your application tag in your manifest:
android:largeHeap="true"
Hopefully this helps :)