Android Camera and SurfaceView: Correct way to release - android-camera

I wanted to know what is the best practice for writing the SurfaceView surfaceDestroyed method and surfaceCreated method, and also the onPause and onResume methods of the Activity using the camera? There are several posts but none of them seem to help.
Here is the code:
SurfaceCreated
public void surfaceCreated(SurfaceHolder holder) {
try {
Log.d(TAG,"Surface Created");
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
SurfaceDestroyed
public void surfaceDestroyed(SurfaceHolder holder) {
this.getHolder().removeCallback(this);
mCamera.stopPreview();
mCamera.release();
}
Activity onResume
protected void onResume() {
super.onResume();
mCamera.setPreviewCallback(null);
Log.d(TAG,"onResume Called");
if (mCamera==null){
mCamera=getCameraInstance();
}
initializeCamera(mCamera);
}
Activity onPause
protected void onPause() {
super.onPause();
Log.d(TAG,"onPause Called");
if(mCamera!=null){
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mPreview.getHolder().removeCallback(mPreview);
preview.removeView(mPreview);
mCamera.release();
mCamera = null;
}
}
In initializeCamera, I do the following:
private void initializeCamera(Camera mCamera) {
mPreview = new InternalCameraPreview(this, mCamera);
preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
With this setup, I get the error Method Called Before Release() when I run the app. Where am I going wrong?

It should be like this:
#Override
public void onPause() {
super.onPause();
if (mCamera != null){
// mCamera.setPreviewCallback(null);
mPreview.getHolder().removeCallback(mPreview);
releaseMediaRecorder();
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
#Override
public void onResume() {
super.onResume();
if (mCamera == null) {
mCamera=getCameraInstance();
mPreview = new CameraPreview(this.getActivity(), mCamera);
preview.addView(mPreview);
}
}
Nothing is needed in surfaceDestroyed

Related

How to call a method AFTER a view has rendered in MAUI - OnAppearing fires too soon

I have some animations that I want to trigger once the view has loaded.
Some of them rely on position values of other views on the page but at the time that OnAppearing fires, the X and Y values for these controls have not been set.
Others can just run by themselves but because they start in OnAppearing, the first few frames aren't rendered.
Adding a Task.Delay into the start of the methods solves the problem but is obviously not great.
Is there any way to create such a method or maybe a way to do it with behaviours? They need to trigger automatically, not in response to some control event like TextChanged etc.
Thanks!
You can do it from the native side, In Ios, you can override the ViewDidLoad method in custom renderer like:
public class MyPageRenderer : PageRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
//call before ViewWillAppear and only called once
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
}
}
and android, override the OnAttachedToWindow method:
public class MyPageRenderer : PageRenderer
{
public MyPageRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
}
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
}
}
`VisualElement` is the base class for most `Microsoft.Maui.Control`s:
public partial class NameOfThePage : ContentPage
{
public NameOfThePage()
{
InitializeComponent();
this.Loaded += NameOfThePage_Loaded;
}
private void NameOfThePage_Loaded(object sender, EventArgs e)
{
/* animations you want to trigger */
}
}
Unfortunately no OnLoad() to override.

Flutter: how to run a code when user closes app?

I have the following subscription:
class CheckInternet with ChangeNotifier {
StreamSubscription<ConnectivityResult> _subscription;
bool haveInternet = false;
static CheckInternet _instance;
static CheckInternet getInstance() {
if (_instance == null) {
_instance = CheckInternet();
_instance.checkConnectivity();
}
return _instance;
}
void checkConnectivity() {
if (_subscription == null) {
_subscription = Connectivity()
.onConnectivityChanged
.listen((ConnectivityResult result) {
bool res = result == ConnectivityResult.mobile ||
result == ConnectivityResult.wifi;
setHaveInternet = res;
});
}
}
I create this subscription in my main() method and while the app is open, it is checking the internet connection. My problem is that how to make a method what will cancel the subscription when the user closes the app.
I need something like the dispose() is for widgets.

How to geocode destination point?

I am trying to navigation application on Mapbox with Unity. I can take the location of the user but i could not able to take destination point from the user. I want to take as text. If i can able to take destination point, i can plot the route easily.
I tried the reload map, but it is not useful. Also, i tried the forward geocode user input file, but i could not make it.
namespace Mapbox.Examples
{
using Mapbox.Unity;
using UnityEngine;
using UnityEngine.UI;
using System;
using Mapbox.Geocoding;
using Mapbox.Utils;
[RequireComponent(typeof(InputField))]
public class ForwardGeocodeUserInput : MonoBehaviour
{
InputField _inputField;
ForwardGeocodeResource _resource;
Vector2d _coordinate;
public Vector2d Coordinate
{
get
{
return _coordinate;
}
}
bool _hasResponse;
public bool HasResponse
{
get
{
return _hasResponse;
}
}
public ForwardGeocodeResponse Response { get; private set; }
//public event Action<> OnGeocoderResponse = delegate { };
public event Action<ForwardGeocodeResponse> OnGeocoderResponse = delegate { };
void Awake()
{
_inputField = GetComponent<InputField>();
_inputField.onEndEdit.AddListener(HandleUserInput);
_resource = new ForwardGeocodeResource("");
}
void HandleUserInput(string searchString)
{
_hasResponse = false;
if (!string.IsNullOrEmpty(searchString))
{
_resource.Query = searchString;
MapboxAccess.Instance.Geocoder.Geocode(_resource, HandleGeocoderResponse);
}
}
void HandleGeocoderResponse(ForwardGeocodeResponse res)
{
_hasResponse = true;
if (null == res)
{
_inputField.text = "no geocode response";
}
else if (null != res.Features && res.Features.Count > 0)
{
var center = res.Features[0].Center;
//_inputField.text = string.Format("{0},{1}", center.x, center.y);
_coordinate = res.Features[0].Center;
}
Response = res;
OnGeocoderResponse(res);
}
}
}
Could you help me?

use tableview as searchable input

I have this tableview that is searcheable. at this point I can fill it and on search goes to a detailview. know I want to convert this to use it as an input? but how?
I have a view with the input, and I technically have a tableview that returns the value, just not in the correct manner.
tableviewmodel:
public class CMCTableViewModel : MvxViewModel
{
protected readonly ICoinMarketCapService _coinMarketCapService;
public CMCTableViewModel(ICoinMarketCapService coinMarketCapService)
{
_coinMarketCapService = coinMarketCapService;
LoadData();
}
public MvxCommand<CoinMarketCapModel> NavigateToDetailCommand
{
get
{
return new MvxCommand<CoinMarketCapModel>(
SelectedCoin =>
{
ShowViewModel<CoinViewModel>(new { coinName = SelectedCoin.Id });
}
);
}
}
private List<CoinMarketCapModel> _coinMarketCapModelList;
private CoinMarketGlobData _CoinMarketGlobDataList;
public List<CoinMarketCapModel> CoinMarketCapModelList
{
get
{
return _coinMarketCapModelList;
}
set
{
_coinMarketCapModelList = value;
RaisePropertyChanged(() => CoinMarketCapModelList);
}
}
public CoinMarketGlobData CoinMarketGlobDatas
{
get
{
return _CoinMarketGlobDataList;
}
set
{
_CoinMarketGlobDataList = value;
RaisePropertyChanged(() => CoinMarketGlobDatas);
}
}
public async void LoadData()
{
//CoinMarketCapModelList = await _coinMarketCapService.GetCoins("20");
//CoinMarketGlobDatas = await _coinMarketCapService.GetGlobalData();
CoinMarketCapModelList = await _coinMarketCapService.GetCoins();
FilteredList = CoinMarketCapModelList;
}
private List<CoinMarketCapModel> _FilteredList;
public List<CoinMarketCapModel> FilteredList
{
get
{
return _FilteredList;
}
set
{
_FilteredList = value;
RaisePropertyChanged(() => FilteredList);
}
}
public void SearchByText(string text)
{
if (string.IsNullOrWhiteSpace(text))
FilteredList = CoinMarketCapModelList;
else
{
FilteredList = CoinMarketCapModelList;
FilteredList = FilteredList.Where(m => m.Name.ToLowerInvariant().Contains(text.ToLowerInvariant())).ToList();
}
}
/// <summary>
/// Gets or sets the subtitle for the base model
/// </summary>
}
View:
[MvxFromStoryboard(StoryboardName = "Main")]
public partial class CMCTableView : MvxTableViewController<CMCTableViewModel>
{
bool useRefreshControl = false;
//private UIRefreshControl refreshControl;
private MvxUIRefreshControl refreshControl;
private void refreshTable(object sender, EventArgs e)
{
refreshControl.EndRefreshing();
TableView.ReloadData();
}
public CMCTableView (IntPtr handle) : base (handle)
{
}
UISearchBar _searchBar;
CMCTableViewSource _cmcTableViewSource;
public override void ViewDidLoad()
{
refreshControl = new MvxUIRefreshControl();
refreshControl.ValueChanged += refreshTable;
TableView.AddSubview(refreshControl);
_cmcTableViewSource = new CMCTableViewSource(this.TableView);
base.ViewDidLoad();
this.TableView.Source = _cmcTableViewSource;
this.TableView.ReloadData();
//BEGIN initialize searchbar
var searchController = new UISearchController(searchResultsController: null);
searchController.SearchBar.SizeToFit();
searchController.SearchBar.SearchBarStyle = UISearchBarStyle.Minimal;
searchController.SearchBar.Placeholder = "Select a currency";
searchController.DimsBackgroundDuringPresentation = false;
NavigationItem.HidesSearchBarWhenScrolling = false;
NavigationItem.SearchController = searchController;
_searchBar = searchController.SearchBar;
_searchBar.SearchButtonClicked += SearchBar_SearchButtonClicked;
_searchBar.TextChanged += SearchBarOnTextChanged;
_searchBar.CancelButtonClicked += SearchBarOnCancelButtonClicked;
// END initialize searchbar
MvxFluentBindingDescriptionSet<CMCTableView, CMCTableViewModel> set = new MvxFluentBindingDescriptionSet<CMCTableView, CMCTableViewModel>(this);
set.Bind(_cmcTableViewSource).To(vm => vm.FilteredList);
set.Bind(_cmcTableViewSource)
.For(src => src.SelectionChangedCommand)
.To(vm => vm.NavigateToDetailCommand);
set.Apply();
}
private void SearchBarOnCancelButtonClicked(object sender, EventArgs eventArgs)
{
((CMCTableViewModel)ViewModel).SearchByText(string.Empty);
BeginInvokeOnMainThread(() => _searchBar.ResignFirstResponder());
}
//public override void ViewWillAppear(bool animated)
//{
// base.ViewWillAppear(animated);
// NavigationController.NavigationBarHidden = false;
//}
private void SearchBarOnTextChanged(object sender, UISearchBarTextChangedEventArgs e)
{
if (string.IsNullOrWhiteSpace(_searchBar.Text))
{
((CMCTableViewModel)ViewModel).SearchByText(string.Empty);
BeginInvokeOnMainThread(() => _searchBar.ResignFirstResponder());
}
else
{
((CMCTableViewModel)ViewModel).SearchByText(_searchBar.Text);
}
}
private void SearchBar_SearchButtonClicked(object sender, EventArgs e)
{
((CMCTableViewModel)ViewModel).SearchByText(_searchBar.Text);
BeginInvokeOnMainThread(() => _searchBar.ResignFirstResponder());
}
}
i used a button as input that goes to the tableview, on selection i store the needed data(id and name in this case) in a static model. then i return to the parentview.
model:
public class addUserCoinHelperModel
{
public static string coinID { get; set; }
public static string name { get; set; }
public static string Amount { get; set; }
}
on selection in viewmodel:
public MvxCommand<CoinMarketCapModel> NavigateToDetailCommand
{
get
{
return new MvxCommand<CoinMarketCapModel>(
SelectedCoin =>
{
addUserCoinHelperModel.coinID = SelectedCoin.Id;
addUserCoinHelperModel.name = SelectedCoin.Name;
ShowViewModel<AddUserCoinViewModel>();
//ShowViewModel<CoinViewModel>(new { coinName = SelectedCoin.Id });
}
);
}
}
in the view in the viewdidload:
if (addUserCoinHelperModel.coinID != null){
btnPickCoin.SetTitle(addUserCoinHelperModel.name, UIControlState.Normal);
}

What the Parameter..?

I want to ask what is the parameter content of this code
static frmMain _instance;
public frmMain(string userInfo)
{
InitializeComponent();
btnUserInfo.Text = userInfo;
//this.StyleManager = metroStyleManager1;
}
public static frmMain Instance
{
get
{
if (_instance == null)
**_instance = new frmMain(*//What's in here//*);**
return _instance;
}
}