Android: Saved video file cant be played - android-videoview

I have developed an app that can play videos from gallery and then save the played video back into a folder in gallery. The app is working fine as I can select and play videos from gallery and then save it. When the "Save Video' button is clicked, 'Video saved!' message pops and the saved video are found in gallery. The issue now is I cant play the video, it says 'Sorry, this video cannot be played'. Im unable to identify where it went wrong. My codings are as follow:
AndroidVideoPlayer.java:
public class AndroidVideoPlayer extends Activity {
/**
* Called when the activity is first created.
*/
Button button, button2;
VideoView videoView;
private static final int PICK_FROM_GALLERY = 1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_android_video_player);
button = (Button) findViewById(R.id.button);
button2 = (Button) findViewById(R.id.savevideo);
videoView = (VideoView) findViewById(R.id.videoview);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent();
intent.setType("video/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Complete action using"), PICK_FROM_GALLERY);
}
});
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
savequesimage();
// Toast.makeText(getActivity(), "Sample Answer Saved", Toast.LENGTH_LONG).show();
}
});
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) return;
if (requestCode == PICK_FROM_GALLERY) {
Uri mVideoURI = data.getData();
videoView.setVideoURI(mVideoURI);
videoView.start();
}
}
protected boolean savequesimage() {
boolean success = false;
View content = videoView;
content.invalidate();
// make the directory
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/SavedVideo/";
File dir = new File(path);
if(!dir.exists())
dir.mkdirs();;
// create unique identifier
Random generator = new Random();
int n = 100;
n = generator.nextInt(n);
// create file name
String videoName = "Video_" + n + ".mp4";
File fileVideo = new File(dir.getAbsolutePath(), videoName);
try {
fileVideo.createNewFile();
success = true;
} catch (IOException e) {
e.printStackTrace();
}
if (success) {
Toast.makeText(getApplicationContext(), "Video saved!",
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(),
"Error during video saving", Toast.LENGTH_LONG).show();
}
return true;
}
}
activity_android_video_player.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button
android:id="#+id/button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="- PLAY Video -"
/>
<Button
android:id="#+id/savevideo"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="- Save Video -"
/>
<VideoView
android:id="#+id/videoview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mainapp.videoview" >
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".AndroidVideoPlayer"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Can anyone help me to resolve this issue? Any help/suggestion would be really helpful. Thank you.

Firstly, add permission READ_EXTERNAL_STORAGE & WRITE_EXTERNAL_STORAGE to AndroidManifest.xml like this:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
With Android Level >=23 you need ask permission in code:
// With Android Level >= 23 you need ask permission.
if (android.os.Build.VERSION.SDK_INT >= 23) {
// Check if we have write & read permission
int writePermission = this.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
int readPermission = this.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
if (writePermission != PackageManager.PERMISSION_GRANTED ||
readPermission != PackageManager.PERMISSION_GRANTED) {
// If don't have permission so prompt the user.
this.requestPermissions(
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE},
REQUEST_PERMISSION
);
}
}
See more here.

Related

Xamarin Android Map stop working

I have a Xamarin Forms Portable application with Android and iOS. My maps have been working fine and still are in the iOS, but in Android I just get a map of the whole world.
This is the AndroidManifest:
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="25" />
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<application android:label="MyProject" android:icon="#drawable/appicon">
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaS...................................." />
<meta-data android:name="com.google.android.gms.version" android:value="#integer/google_play_services_version" />
This is my Page for booth Android and iOS.
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:Comca.Views;assembly=Comca"
xmlns:controls="clr-namespace:Comca.Controls;assembly=Comca"
xmlns:local="clr-namespace:Comca;assembly=Comca"
xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps"
x:Class="Comca.Pages.LocationsPage">
<ContentPage.Content>
<StackLayout
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<views:PageHeader></views:PageHeader>
<controls:CustomMap x:Name="myMap" MapType="Street"
WidthRequest="{x:Static local:App.ScreenWidth}"
HeightRequest="{x:Static local:App.ScreenHeight}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
The myMap.MoveToRegion does nothing. It goes true setting all the pins but nothing happens, still a map of the whole world.
namespace MyProject.Pages
{
public partial class LocationsPage : ContentPage
{
LocationsViewModel LocationsVM { get; set; }
public List<LocationsResponse> Locations { get; set;}
public LocationsPage()
{
InitializeComponent();
myMap.MoveToRegion(
MapSpan.FromCenterAndRadius(
new Position(26.142051, -81.794683), Distance.FromMiles(4)));
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
if (this.BindingContext != null)
{
LocationsVM = this.BindingContext as LocationsViewModel;
if (LocationsVM.Locations != null)
{
Locations = LocationsVM.Locations;
foreach (var location in Locations)
{
var latitude = Convert.ToDouble(location.Latitude);
var longitude = Convert.ToDouble(location.Longitude);
var label = $"{location.Name} - {location.Plaza}";
var address = $"{location.Street} {location.Citystate}";
var pin = new CustomPin
{
Pin = new Pin
{
Type = PinType.Place,
Position = new Position(latitude, longitude),
Label = label,
Address = address
},
Hours = location.Hours,
Phone = location.Phone,
Id="Myname",
Url = "http://www.myname.com"
};
myMap.CustomPins = new List<CustomPin> { pin };
myMap.Pins.Add(pin.Pin);
}
}
}
}
}
}
I noticed that on the customMapRenderer the if (e.PropertyName.Equals("VisibleRegion") && !isDrawn) never equals VisibleRegion.
First it's Renderer, then Y, then Width and last Height.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Android.Content;
using Android.Gms.Maps;
using Android.Gms.Maps.Model;
using Android.Widget;
using CustomRenderer.Droid;
using MyProject.Controls;
using MyProject.Models;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.Android;
using MyProject.Droid;
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace CustomRenderer.Droid
{
public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter, IOnMapReadyCallback
{
GoogleMap map;
List<CustomPin> customPins;
bool isDrawn;
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
map.InfoWindowClick -= OnInfoWindowClick;
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
customPins = formsMap.CustomPins;
((MapView)Control).GetMapAsync(this);
}
}
public void OnMapReady(GoogleMap googleMap)
{
map = googleMap;
map.InfoWindowClick += OnInfoWindowClick;
map.SetInfoWindowAdapter(this);
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName.Equals("VisibleRegion") && !isDrawn)
{
map.Clear();
foreach (var pin in customPins)
{
var marker = new MarkerOptions();
marker.SetPosition(new LatLng(pin.Pin.Position.Latitude, pin.Pin.Position.Longitude));
marker.SetTitle(pin.Pin.Label);
marker.SetSnippet(pin.Pin.Address);
map.AddMarker(marker);
}
isDrawn = true;
}
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
if (changed)
{
isDrawn = false;
}
}
void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
{
var customPin = GetCustomPin(e.Marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (!string.IsNullOrWhiteSpace(customPin.Phone))
{
var url = Android.Net.Uri.Parse("tel:" + customPin.Phone);
var intent = new Intent(Intent.ActionCall, url);
//intent.SetData(url);
intent.AddFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);
}
}
public Android.Views.View GetInfoContents(Marker marker)
{
var inflater = Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as Android.Views.LayoutInflater;
if (inflater != null)
{
Android.Views.View view;
var customPin = GetCustomPin(marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);
var infoHours = view.FindViewById<TextView>(Resource.Id.InfoWindowHours);
var infoPhone = view.FindViewById<TextView>(Resource.Id.InfoWindowsPhone);
if (infoTitle != null)
{
infoTitle.Text = marker.Title;
}
if (infoSubtitle != null)
{
infoSubtitle.Text = marker.Snippet;
}
if (infoHours != null)
{
infoHours.Text = customPin.Hours;
}
if (infoPhone != null)
{
infoPhone.Text = customPin.Phone;
}
return view;
}
return null;
}
public Android.Views.View GetInfoWindow(Marker marker)
{
return null;
}
CustomPin GetCustomPin(Marker annotation)
{
var position = new Position(annotation.Position.Latitude, annotation.Position.Longitude);
foreach (var pin in customPins)
{
if (pin.Pin.Position == position)
{
return pin;
}
}
return null;
}
}
}
I took over this code and I'm new to Xamarin.
Thanks for any help.

Insert TYPE_NUTRITION in Google Fit

I get user input (calorie) and want to insert it in Google Fit but the insertion does not work.
private DataSet insertNutritionData(){
Calendar cal = Calendar.getInstance();
Date now = new Date();
cal.setTime(now);
long endTime = cal.getTimeInMillis();
DataSource nutritionSource = new DataSource.Builder()
.setAppPackageName(getApplicationContext().getPackageName())
.setDataType(DataType.TYPE_NUTRITION)
.setType(DataSource.TYPE_RAW)
.build();
DataSet dataSet = DataSet.create(nutritionSource);
DataPoint dataPoint = DataPoint.create(nutritionSource);
dataPoint.setTimestamp(endTime, TimeUnit.MILLISECONDS);
dataPoint.getValue(Field.FIELD_NUTRIENTS).setKeyValue(Field.NUTRIENT_CALORIES,calorie);
dataSet.add(dataPoint);
return dataSet;
}
The insertion is done in AsyncTask :
private class InsertAndVerifyNutritionTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
DataSet dataSet = insertNutritionData();
Log.i(TAG, "Inserting the dataset in the History API");
com.google.android.gms.common.api.Status insertStatus =
Fitness.HistoryApi.insertData(mClient, dataSet)
.await(1, TimeUnit.MINUTES);
if (!insertStatus.isSuccess()) {
Log.i(TAG, "There was a problem inserting the dataset.");
return null;
}
Log.i(TAG, "Data insert was successful!");
return null;
}
}
Unfortunately, the insertion is not done and I don't know why. There is no sample to explain how can we use TYPE_NUTRIENTS...
Thanks a lot !
[UPDATE]
I found this error :
Couldn't connect to Google API client: ConnectionResult{statusCode=API_UNAVAILABLE, resolution=null}
However, I build my client like this :
mClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.RECORDING_API)
.addApi(Fitness.SENSORS_API)
.addApi(Fitness.HISTORY_API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addScope(new Scope(Scopes.FITNESS_NUTRITION_READ_WRITE))
.addConnectionCallbacks(
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Google Fit connected.");
mTryingToConnect = false;
Log.d(TAG, "Notifying the UI that we're connected.");
notifyUiFitConnected();
}
#Override
public void onConnectionSuspended(int i) {
// If your connection to the sensor gets lost at some point,
// you'll be able to determine the reason and react to it here.
mTryingToConnect = false;
if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "Connection lost. Cause: Network Lost.");
} else if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.i(TAG, "Connection lost. Reason: Service Disconnected");
}
}
}
)
.addOnConnectionFailedListener(
new GoogleApiClient.OnConnectionFailedListener() {
// Called whenever the API client fails to connect.
#Override
public void onConnectionFailed(ConnectionResult result) {
//Toast.makeText(getActivity(),"connection failed 1",Toast.LENGTH_SHORT).show();
mTryingToConnect = false;
notifyUiFailedConnection(result);
}
}
)
.build();
}
Moreover, I don't understand why I cannot connect to fit whereas it worked perfectly...
Updated with the manifest :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.webear.mysilhouette">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application
android:allowBackup="true"
android:label="mySilhouette"
android:icon="#drawable/ic_launcher"
>
<meta-data android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<service
android:enabled="true"
android:name="com.example.webear.mysilhouette.GoogleApiIntentService"/>
(...)
</application>
</manifest>
Kamel
The statusCode says API_UNAVAILABLE. It means:
One of the API components you attempted to connect to is not
available. The API will not work on this device, and updating Google
Play services will not likely solve the problem. Using the API on the
device should be avoided.
Maybe try another device? Or Play Services are misconfigured.

Reload/Restart fragment with SwipeRefreshLayout containing a RecyclerView list with CardViews

I'm developing an app with a left navigation drawer and every secion of the navigation drawer loads a different fragment containing a RecyclerView list with JSON data from a server. The JSON data is get via Volley but sometimes the async task takes a while and the RecyclerView shows up empty. I want to implement a SwypeRefreshLayout on the fragments so they can be reloaded when the user drags down the view.
I have 2 problems:
1) The animation with the little spinning ball just shows up for a second and then disappears
2) After I do the swype down, all other fragments from the navigation drawer sections show this exact same fragment that was refreshed and not their own anymore.
How can I get it fixed, showing the reload animation properly and triggering the fragment reload on each section independently?
Here's the XML code of the fragment:
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/instancesSRL">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin">
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/instancesCV"
android:layout_gravity="center"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
app:cardBackgroundColor="#color/accent"
android:elevation="100dp"
android:layout_marginBottom="1dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/instancesSection"
android:textColor="#android:color/white"
android:textSize="#dimen/abc_text_size_large_material"
android:textAlignment="center"
android:id="#+id/instancesTV"
android:gravity="center_horizontal"
android:paddingBottom="5dp"
android:paddingTop="5dp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="44dp"
android:layout_height="#dimen/abc_action_button_min_height_material"
android:background="#color/window_bg"
android:layout_alignEnd="#id/instancesTV">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/endpoint_icon"
android:src="#drawable/ic_stars_white_48dp"
android:layout_gravity="center_vertical"
android:padding="5dp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
</LinearLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.RecyclerView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/instancesRV"
android:layout_below="#+id/instancesCV"
android:clickable="true"
android:scrollbars="vertical"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageView"
android:src="#drawable/openstack_logo"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="false"
android:layout_alignParentRight="true"
android:layout_alignWithParentIfMissing="false"
android:alpha="0.1"/>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageButton
android:id="#+id/add_buttonInstances"
android:layout_width="#dimen/diameter"
android:layout_height="#dimen/diameter"
android:tint="#android:color/white"
android:layout_gravity="end|bottom"
android:layout_marginBottom="#dimen/add_button_margin"
android:layout_marginEnd="#dimen/card_height"
android:src="#android:drawable/ic_input_add"
android:clickable="true"
android:stateListAnimator="#drawable/button_elevation"
android:background="#drawable/fab_selector"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
</FrameLayout>
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
And here's the fragment code:
public class InstancesFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
private OnFragmentInteractionListener mListener;
/**
* Returns a new instance of this fragment for the given section
* number.
*/
public static InstancesFragment newInstance(int sectionNumber) {
InstancesFragment fragment = new InstancesFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public InstancesFragment() {
}
public ArrayList<HashMap<String, String>> jsonList;
public RecyclerView recyclerView;
public SwipeRefreshLayout refreshLayout;
private Handler handler = new Handler();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Bundle extras = getArguments();
Serializable parsedList = extras.getSerializable("NovaParsed");
jsonList = (ArrayList<HashMap<String, String>>)parsedList;
View rootView = inflater.inflate(R.layout.fragment_instances, container, false);
refreshLayout = (SwipeRefreshLayout)rootView.findViewById(R.id.instancesSRL);
recyclerView = (RecyclerView)rootView.findViewById(R.id.instancesRV);
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
layoutManager.supportsPredictiveItemAnimations();
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setClickable(true);
recyclerView.setHasFixedSize(true);
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
NovaAdapter novaAdapter = new NovaAdapter(getActivity(),jsonList);
if (novaAdapter.getItemCount() != 0) {
recyclerView.setAdapter(novaAdapter);
}
refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
Fragment instancesFragment = getFragmentManager().findFragmentById(R.id.container);
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.remove(instancesFragment);
fragmentTransaction.commit();
refreshLayout.measure(20, 20);
refreshLayout.setRefreshing(true);
}
});
refreshLayout.setColorSchemeColors(Color.RED, Color.GRAY);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
((Stackerz) activity).onSectionAttached(
getArguments().getInt(ARG_SECTION_NUMBER));
//try {
// mListener = (OnFragmentInteractionListener) activity;
//} catch (ClassCastException e) {
// throw new ClassCastException(activity.toString()
// + " must implement OnFragmentInteractionListener");
//}
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
public void onFragmentInteraction(Uri uri);
}
}
And this is how I call every fragment from the MainActivity using the Navigation Drawer:
#Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, PlaceholderFragment.newInstance(position))
.commit();
switch (position) {
case 0:
extras = authBundle();
OverviewFragment overviewFragment = new OverviewFragment();
overviewFragment.setArguments(extras);
fragmentManager.beginTransaction().add(R.id.container, OverviewFragment.newInstance(position)).commit();
fragmentManager.beginTransaction().replace(R.id.container,overviewFragment).commit();
break;
case 1:
novaExtras = novaBundle();
InstancesFragment instancesFragment = new InstancesFragment();
instancesFragment.setArguments(novaExtras);
fragmentManager.beginTransaction().add(R.id.container, InstancesFragment.newInstance(position)).commit();
fragmentManager.beginTransaction().replace(R.id.container, instancesFragment).commit();
break;
case 2:
flavorsExtras = flavorsBundle();
FlavorsFragment flavorsFragment = new FlavorsFragment();
flavorsFragment.setArguments(flavorsExtras);
fragmentManager.beginTransaction().add(R.id.container, FlavorsFragment.newInstance(position)).commit();
fragmentManager.beginTransaction().replace(R.id.container, flavorsFragment).commit();
break;
case 3:
glanceExtras = glanceBundle();
ImagesFragment imagesFragment = new ImagesFragment();
imagesFragment.setArguments(glanceExtras);
fragmentManager.beginTransaction().add(R.id.container, ImagesFragment.newInstance(position)).commit();
fragmentManager.beginTransaction().replace(R.id.container, imagesFragment).commit();
break;
case 4:
networksExtras = networksBundle();
NetworksFragment networksFragment = new NetworksFragment();
networksFragment.setArguments(networksExtras);
fragmentManager.beginTransaction().add(R.id.container, NetworksFragment.newInstance(position)).commit();
fragmentManager.beginTransaction().replace(R.id.container, networksFragment).commit();
break;
case 5:
subnetsExtras = subnetsBundle();
SubnetsFragment subnetsFragment = new SubnetsFragment();
subnetsFragment.setArguments(subnetsExtras);
fragmentManager.beginTransaction().add(R.id.container, SubnetsFragment.newInstance(position)).commit();
fragmentManager.beginTransaction().replace(R.id.container, subnetsFragment).commit();
break;
case 6:
routersExtras = routersBundle();
RoutersFragment routersFragment = new RoutersFragment();
routersFragment.setArguments(routersExtras);
fragmentManager.beginTransaction().add(R.id.container, RoutersFragment.newInstance(position)).commit();
fragmentManager.beginTransaction().replace(R.id.container, routersFragment).commit();
break;
case 7:
securityExtras = securityBundle();
SecurityFragment securityFragment = new SecurityFragment();
securityFragment.setArguments(securityExtras);
fragmentManager.beginTransaction().add(R.id.container, SecurityFragment.newInstance(position)).commit();
fragmentManager.beginTransaction().replace(R.id.container, securityFragment).commit();
break;
default:
fragmentManager.beginTransaction().replace(R.id.container, PlaceholderFragment.newInstance(position)).commit();
break;
}
}

mvvmcross keep program settings using file plugin and json serialize/deserialize

I'm trying to use the fileplugin and json serializer to do this.
I have the following DcsSetup class, in the core project.
For now I'm working with droid. I can't seem to save the file. The json serialize is ok. The WriteFile seems ok, but next time I try to read the file using TryReadTextFile it fails.
I can't find the file on the device, so I think the WriteFile stuff is wrong.
What is the correct way to save and read my Settings class on Android?
public class DcsSetup
{
public class Settings
{
//Server
public string Server;
public int Port;
public int Device;
public string EncodingFromClient;
public string EncodingToClient;
public int FontCorrectionPixelsWidth; //Pixels to add or subtract i Y dimension to get the right font size
public int FontCorrectionPixelsHeight; //Pixels to add or subtract i Y dimension to get the right font size
public float XPct;//Pct to add to vertical placement of textBox and Buttons.
public float YPct;//Pct to add to horisontal placement of textBox and Buttons.
public float SizePct;//Pct to add to horisontal size of textBox and Buttons.
public bool FullScreen;
public bool DontSleep;
//Diverse
public bool AutoSendEnter;
}
public Settings Setting;
public DcsSetup()
{
var setupFound=true;
var fileService = Mvx.Resolve<IMvxFileStore>();
var jsonConvert = Mvx.Resolve<IMvxJsonConverter>();
var path = fileService.PathCombine("Setting", "Settings.txt");
Setting = new Settings();
try {
string settingFile;
if (fileService.TryReadTextFile(path, out settingFile)){
Setting = jsonConvert.DeserializeObject<Settings>(settingFile);
} else{
setupFound = false;
}
}
catch(Exception e) {
AppTrace.Error("Failed to read settings: {0}", e.Message);
setupFound=false;
}
if(setupFound==false){
Setting.Server = "192.168.1.100";
Setting.Port = 1650;
Setting.Device = 1;
Setting.EncodingFromClient = "CP1252";
Setting.EncodingToClient = "CP1252";
Setting.FontCorrectionPixelsWidth = 0;
Setting.FontCorrectionPixelsHeight = 0;
Setting.XPct = 97.0f;
Setting.YPct = 100.0f;
Setting.SizePct = 98.0f;
Setting.FullScreen = false;
Setting.DontSleep = true;
Setting.AutoSendEnter = true;
try {
//json
var json = jsonConvert.SerializeObject(Setting);
fileService.EnsureFolderExists("Setting");
fileService.WriteFile(path, json);
}
catch (Exception e) {
AppTrace.Error("Failed to save settings: {0}", e.Message);
}
}
}
}
}
I just created a project in VS2012 using the 3.1.1-beta2 packages for MvvmCross
I then added the File and Json plugin packages
I changed the core FirstViewModel to:
public class FirstViewModel
: MvxViewModel
{
private readonly IMvxFileStore _fileStore;
private readonly IMvxJsonConverter _jsonConverter;
private readonly string _filePath;
public class ToStore
{
public string Foo { get; set; }
}
public ICommand SaveCommand
{
get
{
return new MvxCommand(() =>
{
var toStore = new ToStore() {Foo = Hello};
var json = _jsonConverter.SerializeObject(toStore);
_fileStore.WriteFile(_filePath, json);
});
}
}
public ICommand LoadCommand
{
get
{
return new MvxCommand(() =>
{
string txt;
if (_fileStore.TryReadTextFile(_filePath, out txt))
{
Mvx.Trace("Loaded {0}", txt);
var stored = _jsonConverter.DeserializeObject<ToStore>(txt);
Hello = stored.Foo;
}
});
}
}
private string _hello = "Hello MvvmCross";
public FirstViewModel(IMvxFileStore fileStore, IMvxJsonConverter jsonConverter)
{
_fileStore = fileStore;
_jsonConverter = jsonConverter;
_filePath = _fileStore.PathCombine("SubDir", "MyFile.txt");
_fileStore.EnsureFolderExists("SubDir");
}
public string Hello
{
get { return _hello; }
set { _hello = value; RaisePropertyChanged(() => Hello); }
}
}
I called this from a test Android UI:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="40dp"
local:MvxBind="Text Hello"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="40dp"
local:MvxBind="Text Hello"
/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="40dp"
android:text="Load"
local:MvxBind="Click LoadCommand"
/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="40dp"
android:text="Save"
local:MvxBind="Click SaveCommand"
/>
</LinearLayout>
This seemed to work OK - it saved and loaded the JSON fine within and between test runs.
Based on this, my only guess is whether you are redeploying the app between runs - if you do this and you don't have MonoDroid's Preserve application data/cache on device between deploys checked, then you won't see the settings preserved.

ActionBar + Tab crashes when screen orientation changes

My app has the following characteristics.
When in landscape mode, split the screen in half and show a couple of Fragments ("LocFragment" and "MapFragment").
When in portrait mode, show 2 Tabs in ActionBar. A Fragment covers the whole screen, and switch between the Fragments with Tab selection.
Targeting 4.x+, so I'm not concerned about Support Library or ActionBarSherlock.
If the phone is in the landscape mode when the app starts, everything works fine. But the app crashes when 1) the phone is in the portrait mode, 2) app starts, and 3) the phone turned to the landscape mode.
layour/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/FragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
layout-land/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:name="org.solamour.eq.LocFragment"
android:id="#+id/EarthquakeListFragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment
android:name="org.solamour.eq.MapFragment"
android:id="#+id/EarthquakeMapFragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
public class MainActivity extends Activity {
TabListener<LocFragment> locTabListener;
TabListener<MapFragment> mapTabListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar = getActionBar();
View fragmentContainer = findViewById(R.id.FragmentContainer);
boolean bLandscape = fragmentContainer == null;
if (!bLandscape) {
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionBar.setDisplayShowTitleEnabled(false);
Tab listTab = actionBar.newTab();
locTabListener = new TabListener<LocFragment>
(this, R.id.FragmentContainer,
LocFragment.class);
listTab.setText("List")
.setContentDescription("List of locations")
.setTabListener(locTabListener);
actionBar.addTab(listTab);
Tab mapTab = actionBar.newTab();
mapTabListener = new TabListener<MapFragment>
(this, R.id.FragmentContainer,
MapFragment.class);
mapTab.setText("Map")
.setContentDescription("Map of interests")
.setTabListener(mapTabListener);
actionBar.addTab(mapTab);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
View fragmentContainer = findViewById(R.id.FragmentContainer);
boolean bLandscape = fragmentContainer == null;
if (!bLandscape) {
FragmentTransaction ft =
getFragmentManager().beginTransaction();
if (mapTabListener.fragment != null) {
ft.detach(mapTabListener.fragment);
}
if (locTabListener.fragment != null) {
ft.detach(locTabListener.fragment);
}
ft.commit();
}
super.onSaveInstanceState(outState);
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
View fragmentContainer = findViewById(R.id.FragmentContainer);
boolean bLandscape = fragmentContainer == null;
if (!bLandscape) {
locTabListener.fragment =getFragmentManager().
findFragmentByTag(LocFragment.class.getName());
mapTabListener.fragment = getFragmentManager().
findFragmentByTag(MapFragment.class.getName());
}
}
public static class TabListener<T extends Fragment>
implements ActionBar.TabListener {
private Fragment fragment;
private Activity activity;
private Class<T> fragmentClass;
private int fragmentContainer;
public TabListener(Activity activity,
int fragmentContainer, Class<T> fragmentClass) {
this.activity = activity;
this.fragmentContainer = fragmentContainer;
this.fragmentClass = fragmentClass;
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (fragment == null) {
String fragmentName = fragmentClass.getName();
fragment = Fragment.instantiate(activity, fragmentName);
ft.add(fragmentContainer, fragment, fragmentName);
} else {
ft.attach(fragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (fragment != null) {
ft.detach(fragment);
}
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
if (fragment != null)
ft.attach(fragment);
}
}
}
Speaking of crash, Eclipse simply says "Unable to start activity ComponentInfo{...}: android.view.InflateException: Binary XML file line #7: Error inflating class fragment". It must be somewhere in "setContentView(R.layout.activity_main)", but I'm not sure how to set up the source to follow inside the code. I'd appreciate any suggestions. Thank you.
__
sol
The error is in the line 7 in the landscape layout:
fragment
android:name="org.solamour.eq.LocFragment"
Maybe the path to the class is wrong or Maybe the LocFragment had an error and when you show it you get a crash.