I'm a relatively new Android developer and currently finishing up my first Android app.
This app is a 'shell' app for a web app and it uses fragments, but I am having two issues. I have done extensive research but I could not get any of the ideas I found to work, so I hope I might be able to get some answers here. Thank you in advance!
1) I want the user to be able to use the back button on their device to go back in the web view
2) I am trying to pass the GPS Latitude and Longitude from a method within a class, out the the variables myLongitude and myLatitude
Here is the code from the MainActivity
public class MainActivity extends FragmentActivity implements ActionBar.TabListener
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Without this, location is not fetched
LocationManager mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
LocationListener mlocListener = new MyLocationListener();
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
//mlocManager.removeUpdates(mlocListener); // This needs to stop getting the location data and save the battery power.
// Set up the action bar to show tabs.
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// For each of the sections in the app, add a tab to the action bar.
actionBar.addTab(actionBar.newTab().setText("Browse").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("My City").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("Search").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("Favs").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("Help").setTabListener(this));
}
// The serialization (saved instance state) Bundle key representing the current tab position.
private static final String STATE_SELECTED_NAVIGATION_ITEM = "selected_navigation_item";
#Override
public void onRestoreInstanceState(Bundle savedInstanceState)
{
// Restore the previously serialized current tab position.
if (savedInstanceState.containsKey(STATE_SELECTED_NAVIGATION_ITEM))
{
getActionBar().setSelectedNavigationItem(savedInstanceState.getInt(STATE_SELECTED_NAVIGATION_ITEM));
}
}
#Override
public void onSaveInstanceState(Bundle outState)
{
// Serialize the current tab position.
outState.putInt(STATE_SELECTED_NAVIGATION_ITEM, getActionBar().getSelectedNavigationIndex());
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
//Gets the Device ID
public String getDeviceId()
{
final String androidId, deviceId;
androidId = android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
deviceId = androidId.toString();
return deviceId;
}
public class MyLocationListener implements LocationListener
{
Double myLatitude; //This is passing a NULL value down to onTabSelected because it is not getting a value from onLocationChanged
Double myLongitude; //This is passing a NULL value down to onTabSelected because it is not getting a value from onLocationChanged
#Override
public void onLocationChanged(Location loc)
{
myLatitude = loc.getLatitude();
myLongitude = loc.getLongitude();
String Text = "My current location is: " + "Latitude = " + myLatitude + "Longitude = " + myLongitude;
Toast.makeText(getApplicationContext(), Text, Toast.LENGTH_SHORT).show();
}
#Override
public void onProviderDisabled(String provider)
{
Toast.makeText(getApplicationContext(), "Gps Disabled", Toast.LENGTH_SHORT ).show();
}
#Override
public void onProviderEnabled(String provider)
{
Toast.makeText(getApplicationContext(), "Gps Enabled", Toast.LENGTH_SHORT).show();
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras)
{}
}
// When the given tab is selected, assign specific content to be displayed //
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction)
{
Fragment fragment = new SectionFragment();
Bundle args = new Bundle();
final String deviceId = getDeviceId();
MyLocationListener location = new MyLocationListener();
final Double myLatitude = location.myLatitude; //This is returning a NULL value
final Double myLongitude = location.myLongitude; //This is returning a NULL value
//Assigns a specific URL to "ARG_SECTION_URL" for each tab
if(tab.getPosition()==0)
{
args.putString(SectionFragment.ARG_SECTION_URL, "http://www.myurl.com/countries.asp?Country=&State=&City=&Category=&Latitude=&Longitude=&ListingID=&AppId=aDG&DeviceID=" + deviceId + "&OrderBy=Name");
}
else if(tab.getPosition()==1)
{
args.putString(SectionFragment.ARG_SECTION_URL, "http://www.myurl.com/landing.asp?Country=&State=&City=&Category=&Latitude=" + myLatitude + "&Longitude=" + myLongitude + "&ListingID=&AppId=aDG&DeviceID=" + deviceId + "&OrderBy=Name");
}
else if(tab.getPosition()==2)
{
args.putString(SectionFragment.ARG_SECTION_URL, "http://www.myurl.com/searchform.asp?Latitude=&Longitude=&ListingID=&AppId=aDG&DeviceID=" + deviceId);
}
else if(tab.getPosition()==3)
{
args.putString(SectionFragment.ARG_SECTION_URL, "http://www.myurl.com/favorites.asp?Latitude=&Longitude=&ListingID=&AppId=aDG&DeviceID=" + deviceId + "&OrderBy=Name");
}
else if(tab.getPosition()==4)
{
args.putString(SectionFragment.ARG_SECTION_URL, "http://www.myurl.com/help.asp?Latitude=&Longitude=&ListingID=&AppId=aDG&DeviceID=" + deviceId);
}
fragment.setArguments(args);
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment).commit();
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction)
{}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction)
{}
#Override
public void onBackPressed()
{
}
//A fragment representing a section of the app, but that simply displays content.
public static class SectionFragment extends Fragment
{
//The fragment argument representing the section number for this fragment.
public static final String ARG_SECTION_URL = "section_url";
public SectionFragment()
{}
#SuppressLint("SetJavaScriptEnabled")
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
//Create a new WebView and set its URL to the fragment's argument value.
WebView myWebView = new WebView(getActivity());
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
myWebView.loadUrl(getArguments().getString(ARG_SECTION_URL));
myWebView.setWebViewClient(new MyWebViewClient());
myWebView.getSettings().setAppCacheEnabled(true);
myWebView.getSettings().setDatabaseEnabled(true);
myWebView.getSettings().setDomStorageEnabled(true);
return myWebView;
}
private class MyWebViewClient extends WebViewClient
{
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
view.loadUrl(url);
return true;
}
}
}
}
I find this way to be more simple.
In WebViewActivity.java, I added 1 method:
#Override
public void onBackPressed() {
WebViewFragment fragment = (WebViewFragment)
getSupportFragmentManager().findFragmentById(R.id.fragmentContainer);
if (fragment.canGoBack()) {
fragment.goBack();
} else {
super.onBackPressed();
}
}
In WebViewFragment.java, I added 2 methods:
public boolean canGoBack() {
return mWebView.canGoBack();
}
public void goBack() {
mWebView.goBack();
}
What I did was implement it within the activity and then have a public static so:
In the main activity:
public class MainActivity extends FragmentActivity{
public static WebView myWebView;
...
#Override
public void onBackPressed() {
if (getSupportFragmentManager().findFragmentByTag("yourtag") != null) {
if(myWebView.canGoBack())
myWebView.goBack();
else {
super.onBackPressed();
}
}
else
super.onBackPressed();
}
...
}
and to reference it within the fragment:
MainActivity.myWebView = (WebView) getView().findViewById(R.id.webview);
and be sure when you create the fragment you add a tag
transaction.replace(R.id.yourfragid, newfragment, "yourtag");
Implement View.OnKeyListener in Snippet with WebView ;
public class ItemMenuFragment extends Fragment implementsView.OnKeyListener
Connect the onKeyListener listener to the WebView;
webView.setOnKeyListener(this);
Override the OnKeyListener.onKey method;
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == MotionEvent.ACTION_UP && webView.canGoBack()) {
webView.goBack();
return true;
}
return false;
}
Related
i decide to use AsyncTaskLoader for lifecycle aware when load data.
It successfully created, but i got one problem when rotate my device, my ProgressBar dismissed and not shown again.
I know it because Activity recreate it and execute onCreate() again.
But i don't know where to handle that, i think it already handled by initLoader
public class MainActivity extends AppCompatActivity implements
LoaderManager.LoaderCallbacks<String> {
public static final String TAG = MainActivity.class.getSimpleName();
public static final int LOADER_ID = 92;
public static final String SEARCH_VALUE = "java";
public static final String ARG_GITHUB_URL = "github_search_url";
#BindView(R.id.tv_results) TextView mResultTextView;
#BindView(R.id.pb_loading_indicator) ProgressBar mLoadingIndicatorProgressBar;
Bundle mBundle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
mBundle = new Bundle();
// Initiate Loader at the first time
// when onCreate called (rotate device)
URL searchUrl = NetworkUtils.buildUrl(SEARCH_VALUE);
mBundle.putString(ARG_GITHUB_URL, searchUrl.toString());
getSupportLoaderManager().initLoader(LOADER_ID, mBundle, this);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int menuItemId = item.getItemId();
if (menuItemId == R.id.action_reload) {
loadGithubRepository();
}
return super.onOptionsItemSelected(item);
}
private void loadGithubRepository() {
Log.e(TAG, "loadGithubRepository: Start load github repository");
mResultTextView.setText("");
// URL searchUrl = NetworkUtils.buildUrl(repoName);
// new GithubRepositoryTask().execute(searchUrl);
LoaderManager loaderManager = getSupportLoaderManager();
if (null == loaderManager.getLoader(LOADER_ID)) {
getSupportLoaderManager().initLoader(LOADER_ID, mBundle, this);
} else {
getSupportLoaderManager().restartLoader(LOADER_ID, mBundle, this);
}
}
// Implement Loader Callback method
#Override
public Loader<String> onCreateLoader(int id, final Bundle args) {
return new AsyncTaskLoader<String>(this) {
#Override
protected void onStartLoading() {
mLoadingIndicatorProgressBar.setVisibility(View.VISIBLE);
if (args != null)
forceLoad();
}
#Override
public String loadInBackground() {
String response = null;
Log.d(TAG, "loadInBackground: " + (args != null));
if (args != null) {
try {
Log.d(TAG, "loadInBackground: " + args.getString(ARG_GITHUB_URL));
URL url = new URL(args.getString(ARG_GITHUB_URL));
response = NetworkUtils.getResponseFromHttp(url);
} catch (Exception e) {
e.printStackTrace();
}
}
return response;
}
};
}
#Override
public void onLoadFinished(Loader<String> loader, String data) {
mLoadingIndicatorProgressBar.setVisibility(View.INVISIBLE);
if (data != null && !data.equals("")) {
mResultTextView.setText(data);
}
}
#Override
public void onLoaderReset(Loader<String> loader) {
// Do nothing...
}
}
How to handle that?
//inside your activity
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
// in manifest
<activity
android:name=".activities.YourActivity"
android:label="#string/title_activity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateHidden|adjustResize" />
which not recreates activity layout.
may be helpful
It is happening because your layout is recreated and, as I understood, default ProgressBar is INVISIBLE. You have to save activity's loading state and set visibility for ProgressBar after restoring instance state.
More information about saving/restoring data in activity:
https://stackoverflow.com/a/151940/2504274
In my app's activity, I have a ViewPager implementation which loads a Map fragment (FragmentA) on launch and then there are 2 other fragments showing content based on the latitude and longitude selected in FragmentA.
I am unable to get the behavior where upon launch, the latitude/longitude from FragmentA, should be provided to the 2 other fragments and continue to provide whenever user clicks on the map in FragmentA.
Here are the approaches I tried:
using interface to communicate between fragment -> activity -> fragment (sticking with this approach)
using bundle to pass information between fragments when the fragments are getting initialized
However, neither of these approaches have worked for me.
MyActivity.java//update to show Daniel's suggestion
public class MyDemoActivity extends FragmentActivity
implements FragmentA.OnFragmentInteractionListener,
FragmentB.OnFragmentInteractionListener, IUserLatLong {
private MyPagerAdapter pagerAdapter;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.map_in_pager_demo);
ViewPager mPager = (ViewPager) findViewById(R.id.pager);
pagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), getApplicationContext());
mPager.setAdapter(pagerAdapter);
//always start w/ Maps View, FragmentA
mPager.setCurrentItem(1);
//
mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//do something
}
#Override
public void onPageSelected(int position) {
// do this instead of calling, notifyDataSetChanged()
Fragment frag = pagerAdapter.fragments[position];
if (frag != null && frag instanceof FragmentB) {
Log.i(TAG, "::FragmentB:: Fetching data from Activity");
//here is my confusion, calling FragmentB with latlong from FragmentA
((FragmentB) frag).setNewLatLong(newUserLatLong);
}
}
#Override
public void onPageScrollStateChanged(int state) {
//do something
}
});
}
#Override
public void onFragmentInteraction(Uri uri) {
//do something
}
#Override
public void makeUseOfNewLocation(UserLatLong userLatLong) {
newUserLatLong = userLatLong;
Log.i(TAG, "LatLong from FragmentA is: " + newUserLatLong.getLat()
+ " and long is: " + newUserLatLong.getLng());
}
/**
* Used for fetching data from activity
* #return
*/
public UserLatLong getLLFromActivity() {
if(newUserLatLong == null) {
Log.e(TAG, "LatLong from FragmentA came up empty");
} else {
Log.i(TAG, "LatLong from FragmentA IS NOT empty: " + newUserLatLong.getLat()
+ " and long is: " + newUserLatLong.getLng());
}
return newUserLatLong;
}
}
MyPagerAdapter.java
public class MyPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 3;
public MyPagerAdapter(FragmentManager fm, Context context) {
super(fm);
this.context = context;
}
#Override
public int getCount() {
return NUM_ITEMS;
}
// not sure if this is really helping
#Override
public int getItemPosition(Object object) {
// POSITION_NONE makes it possible to reload the PagerAdapter
return POSITION_NONE;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
//uses location from FragmentA to get data
return new FragmentB();
case 1:
//loads map and gets location
return new FragmentA();
case 2:
//uses location from FragmentA to get data
return new FragmentC();
default:
return null;
}
}
//This populates your Fragment reference array:
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
fragments[position] = createdFragment;
Log.i(TAG, "::instantiateItem:: " + position + " " + createdFragment.toString());
return createdFragment;
}
}
FragmentA.java /**left out most of map specific code,
but I am interested in getting latitude/longitude whenever onConnected() or onMapClick() gets called*/
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.i(TAG, "In onConnected(), Google API client is:: " + mGoogleApiClient.isConnected());
if (mGoogleApiClient != null) {
try {
// Get last known recent location.
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mCurrentLocation != null) {
// Print current location if not null
final LatLng latLng = new LatLng(mCurrentLocation.getLatitude(),
mCurrentLocation.getLongitude());
//wrap LatLng into UserLatLong
userLatLong.setLat(latLng.latitude);
userLatLong.setLng(latLng.longitude);
//updating the value in the interface
mLLCallback.makeUseOfNewLocation(userLatLong);
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 20);
mMap.animateCamera(cameraUpdate);
mMap.addMarker(new MarkerOptions().position(latLng));
Log.i(TAG, "::Google::My current location set::");
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng latLng1) {
mMap.clear(); //removes the previous marker
mMap.addMarker(new MarkerOptions().position(latLng1));
//updating the value in the interface
mLLCallback.makeUseOfNewLocation(userLatLong);
float x = (float) latLng1.latitude;
float y = (float) latLng1.longitude;
Log.d(TAG, "Map clicked w/ lat: " + x + " and long: " + y);
//wrap LatLng into UserLatLong
userLatLong.setLat(latLng1.latitude);
userLatLong.setLng(latLng1.longitude);
}
});
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
//for zooming automatically to the location of the marker
CameraPosition cameraPosition = new CameraPosition.Builder().target(latLng).zoom(12).build();
mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
//TODO: Constrain the camera target to bounds defined by API
mMap.setMinZoomPreference(Constants.DEFAULT_MIN_ZOOM);
mMap.setMaxZoomPreference(Constants.DEFAULT_MAX_ZOOM);
} else {
Toast.makeText(getActivity(), "Current location is null", Toast.LENGTH_SHORT).show();
}
} catch (SecurityException se1) {
Log.e(TAG, "SecurityException1: " + se1.getLocalizedMessage());
}
} else {
Toast.makeText(getActivity(), "Google API client is null!", Toast.LENGTH_SHORT).show();
}
FragmentB /**in this fragment, I want to refresh content based on latitude/longitude from FragmentA*/
public class FragmentB extends Fragment {
/**
* Required empty public constructor
*/
public FragmentB() {
}
/**the getArguments() is always null*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
currLatLong = getNewLatLong();
}
/**I want latitude/longitude from FragmentA before onCreateView gets called*/
#Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container,
Bundle savedInstanceState) {
LayoutInflater inflater1 = LayoutInflater.from(getContext());
// Inflate the layout for this fragment
view = inflater1.inflate(R.layout.fragment_a, container, false);
currLatLong = getNewLatLong();
//fetch my list based on LatLong
handleDataFetch(currLatLong);
return view;
}
//
private void handleDataFetch(UserLatLong newLatLong) {
final UserLatLong latLong = newLatLong;
final APIEndpointI apiEndpointI = APIRequests.getClient().create(APIEndpointI.class);
String userId = "XXXX-XXX-XXXXXXX";
currLatLong = new UserLatLong(newLat.doubleValue(), newLong.doubleValue());
if (currLatLong != null) {
Log.i(TAG, "Finally! Lat is: " + currLatLong.getLat() +
" and Long is:" + currLatLong.getLng());
/**using retrofit*/
Call<MyResp> call = apiEndpointI.getMyList(userId, currLatLong);
call.enqueue(new Callback<MyResp>() {
#Override
public void onResponse(Call<MyResp> call, Response<MyResp> response) {
Log.i(TAG, "Count: " + response.body().getBundles().size());
Resources res = getContext().getResources();
String cntString = String.format(res.getString(R.string.count), response.body().getBundles().size());
tv1.setText(cntString);
//Initialize with empty data
mGridData = new ArrayList<>();
mGridAdapter = new ProfilePicAdapter(getActivity(), R.layout.grid_item_layout, mGridData);
mGridView.setAdapter(mGridAdapter);
}
#Override
public void onFailure(Call<MyResp> call, Throwable t) {
//do something here
Log.d(TAG, "Failed to get response for GetMyList(): " + t.getMessage());
}
});
} else {
Log.e(TAG, "In onCreateView(), lat long are empty");
}
}
//called from activity to pass the latest latlong
public void setNewLatLong(UserLatLong userLatLong) {
currLatLong = userLatLong;
}
//called from activity to pass the latest latlong
private UserLatLong getNewLatLong() {
return currLatLong;
}
}
It looks like all you need to complete the implementation is to call handleDataFetch() from the setNewLatLong() method if it is a new location.
This is needed since onCreateView() won't be called due to the Fragment being in a ViewPager, so the best way to get the updated location info to FragmentB when it is displayed is to just use a public method called from the ViewPager.OnPageChangeListener in the Activity, as you are doing here.
Just be sure that your equals() method override is implemented correctly in the UserLatLong class, and add this to the setNewLatLong() method:
//called from activity to pass the latest latlong
public void setNewLatLong(UserLatLong userLatLong) {
//Added:
if (!currLatLong.equals(userLatLong)) {
handleDataFetch(userLatLong);
}
currLatLong = userLatLong;
}
Is there an option to modify the content view on the android panorama client? For example I want to display the action bar on top. But currently the action bar is just shown at the beginning and subsequently hidden by the loaded panorama client, since the panorama client is always shown in full screen mode, although it is started in an extra fragment.
I tried now to put the panorama client in a seperated frame through a fragment - this is my code so far:
1. This is the activity whit the panorama fragment and and a text field:
public class PanoramaActivity extends Activity {
public static final String TAG = PanoramaActivity.class.getSimpleName();
private ActionBar actionBar;
private Fragment panoramaClient = new PanoramaClientFragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_snow);
actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
FragmentManager fragMan = getFragmentManager();
FragmentTransaction fragTrans = fragMan.beginTransaction();
fragTrans.replace(R.id.panoramaCLientFrame, panoramaClient, "PANO");
fragTrans.commit();
//Non fullscreen
requestWindowFeature(Window.FEATURE_ACTION_BAR);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.panorama, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
}
2.And this is the fragment class with the panorama client:
public class PanoramaClientFragment extends Fragment implements ConnectionCallbacks,
OnConnectionFailedListener, OnPanoramaInfoLoadedListener {
private View view;
private PanoramaClient panoramaClient;
public static final String TAG = PanoramaClientFragment.class.getSimpleName();
public PanoramaClientFragment() {
// TODO Auto-generated constructor stub
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanteState){
view = inflater.inflate(R.layout.panorama_client, container, false);
return view;
}
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
panoramaClient = new PanoramaClient(getActivity().getApplicationContext(), this, this);
//Non fullscreen
//getActivity().requestWindowFeature(Window.FEATURE_ACTION_BAR);
//getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
//getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
#Override
public void onStart() {
super.onStart();
panoramaClient.connect();
}
#Override
public void onPanoramaInfoLoaded(ConnectionResult result, Intent viewerIntent) {
if (result.isSuccess()) {
Log.i(TAG, "found viewerIntent: " + viewerIntent);
if (viewerIntent != null) {
startActivity(viewerIntent);
}
} else {
Log.e(TAG, "error: " + result);
}
}
#Override
public void onConnectionFailed(ConnectionResult status) {
Log.e(TAG, "connection failed: " + status);
}
#Override
public void onConnected(Bundle arg0) {
Uri uri = Uri.parse("android.resource://" + this.getActivity().getPackageName() + "/" + R.raw.pano1);
panoramaClient.loadPanoramaInfo(this, uri);
}
#Override
public void onDisconnected() {
// Do nothing.
}
#Override
public void onStop() {
super.onStop();
panoramaClient.disconnect();
}
}
If i uncomment the three "non fullscreen"-lines in the fragment class, the app crashes and says:
android.util.AndroidRuntimeException: requestFeature() must be called before adding content
Thanks for your replies.
Greetings.
Try to create a fragment and add the panorama client activity to it.
I think you cannot show the action bar for one simple reason, when your panorama info is loaded you are starting a new activity which is completely out of your control.
if (viewerIntent != null) {
startActivity(viewerIntent);
}
So your code tries to modify the activity that handles the PanoramaClient instance, but not the one that loads the panorama image.
I have build a slide.
I have a ViewPage Activity that call a fragment every time that i swip to left or to right.
My question is:
I have a variable int that in the initial state have the value 6 (week_of_year). When i slide to right is call a new fragment and the variable is not increment as i intend. The variable is only increment in the the second slide.
For example: 6 -> 6 -> 7 -> 8 instead of 6 -> 7 -> 8 -> And i don't have ideia why this happens.
Here is my code:
ViewPage Activity
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_slide);
/**
* Instantiate a ViewPager and a PagerAdapter
*/
date = Calendar.getInstance();
mPager = (ViewPager)findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int arg0) {
if(itemOld < arg0){//right
auxFront = auxFront + 1;
oldStartWeek = oldStartWeek + auxFront;
auxFront=0;
}
else if(itemOld > arg0){//left
auxBack = auxBack - 1;
oldStartWeek = oldStartWeek + auxBack;
auxBack=0;
}
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
#Override
public void onBackPressed(){
if(mPager.getCurrentItem()==0){
super.onBackPressed();
}else{
mPager.setCurrentItem(mPager.getCurrentItem()-1);
}
}
/**
* A simple pager adapter that represents 5 ScreenSlidePageFragment objects, in sequence
*/
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter{
public ScreenSlidePagerAdapter(FragmentManager fm){
super(fm);
}
#Override
public ScreenSlidePageFragment getItem(int position) {
/**
* Pass values from ViewPage activity to Fragment
*/
ScreenSlidePageFragment f = new ScreenSlidePageFragment();
Bundle args = new Bundle();
if(position == 0){
oldStartWeek = date.get(Calendar.WEEK_OF_YEAR);
args.putInt("START_WEEK", oldStartWeek);
f.setArguments(args);
return f;
}
else if(position != 0){
args.putInt("START_WEEK", oldStartWeek);
f.setArguments(args);
itemOld = mPager.getCurrentItem();
return f;
}
return f;
}
#Override
public int getCount() {
return NUM_PAGES;
}
}
}
Fragment that is call in each slide--------------------------------------------
public class ScreenSlidePageFragment extends Fragment implements
AdapterView.OnItemClickListener {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Toast.makeText(getActivity(), "week....." +getArguments().getInt("START_WEEK"), Toast.LENGTH_LONG).show(); //show the correct value
headerWeek.setText(" Week Number: "+getArguments().getInt("START_WEEK",0)); //But is not change corretly in the text view ?????
Thanks for your help and time.
To see why this happens in your ViewPager, you can Log the onCreate, onPause, onResume, etc methods for each fragment. What happens is that the first two fragments are actually created about the same time. So the second fragment is created before it actually displays in a ViewPager, so by the time the user scrolls to the second fragment, there is often old data there.
My solution to this is a little hacky. Note that instead of displayDialog() you would do whatever you needed to update the view when the user is present.
#Override
public void onResume() {
super.onResume();
fragmentActive = true;
if (userVisible()){
displayDialog();
}
else{
recursiveWait();
}
}
private void recursiveWait(){
new WaitAndDoXTask(1000, new DoXListener() {
#Override
public void doX() {
Log.d(TAG, "doX");
if (userVisible()){
displayDialog();
}
else if (fragmentActive){
recursiveWait();
}
}
}).execute();
}
private boolean userVisible(){
boolean vis = getUserVisibleHint();
Log.d(TAG, "user visible = " + vis);
return vis;
}
#Override
public void onPause() {
super.onPause();
Log.d(TAG, "onPause");
fragmentActive = false;
}
Here is the WaitAndDoXTask:
public class WaitAndDoXTask extends AsyncTask<Void, Void, Void>{
DoXListener mListener;
private int mTimeToWait;
/** This class will wait for the set time then do what is put into the listener.
*
*
* Run like this:
* new WaitAndDoXTask(1000, new DoXListener() {
*
* #Override
* public void doX() {
* // TODO Auto-generated method stub
*
* }
* }).execute();
**/
public WaitAndDoXTask(int timeToWait, DoXListener listener){
super();
mTimeToWait = timeToWait;
mListener = listener;
}
public interface DoXListener{
public void doX();
}
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(mTimeToWait);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
if (mListener!=null){
mListener.doX();
}
}
}
Alternatively, if you could set up your Fragment with some Adapter and get notified via onDataSetChanged that might work better.
I have a tabbed application built with fragments and ActionBarSherlock. I have 7 tabs. Here's what's happening.
When I select any tab, the onCreate method for the associated fragment is called as expected. The problem is that the onCreate method is called for the next adjacent tab as well. For instance:
App starts in tab1 and onCreate is called as expected
tab2 onCreate is called as well (should not happen)
-------
Click on tab2 and onCreate is called as expected (even though it's already been called)
tab3 onCreate is called as well (should not happen)
-------
Click on tab6 and onCreate is called as expected
tab7 onCreate is called as well (should not happen)
-------
And really weird, click on tab7 (the last tab)
tab6 (2nd to last tab) onCreate is called as well (should not happen)
I've read a couple of possible problems and checked to make sure it's not happening here:
Not using unique tag for each tab (they are unique)
Emulator has bug that calls onCreate twice (I get the same behavior on my ICS device)
So it's not the two previous possibilities and I'll completely out of ideas. The program runs fine but loading two fragments (which are webviews) takes too much time and isn't the behavior I expected.
Here's my code for the main activity onCreate which creates the tab host:
EDITED:
public class SynergyWorldwideActivity extends SherlockFragmentActivity
{
//TabHost mTabHost;
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set up the view pager
setContentView(R.layout.fragment_tabs_pager);
mViewPager = (ViewPager)findViewById(R.id.pager);
// Set up action bar
final ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayShowTitleEnabled(true);
//bar.setDisplayShowHomeEnabled(false);
// Creat tabs with bundled URLs
Bundle tab1Args=new Bundle(), tab2Args=new Bundle(), tab3Args=new Bundle(),
tab4Args=new Bundle(), tab5Args=new Bundle(), tab6Args=new Bundle(), tab7Args=new Bundle();
tab1Args.putString("tabURL", getString(R.string.webtab1_URL));
tab2Args.putString("tabURL", getString(R.string.webtab2_URL));
tab3Args.putString("tabURL", getString(R.string.webtab3_URL));
tab4Args.putString("tabURL", getString(R.string.webtab4_URL));
tab5Args.putString("tabURL", getString(R.string.webtab5_URL));
tab6Args.putString("tabURL", getString(R.string.webtab6_URL));
tab7Args.putString("tabURL", getString(R.string.webtab7_URL));
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(bar.newTab().setText(getString(R.string.webtab1_name)),
WebTabFragment.MyWebviewFragment.class, tab1Args);
mTabsAdapter.addTab(bar.newTab().setText(getString(R.string.webtab2_name)),
WebTabFragment.MyWebviewFragment.class, tab2Args);
mTabsAdapter.addTab(bar.newTab().setText(getString(R.string.webtab3_name)),
WebTabFragment.MyWebviewFragment.class, tab3Args);
mTabsAdapter.addTab(bar.newTab().setText(getString(R.string.webtab4_name)),
WebTabFragment.MyWebviewFragment.class, tab4Args);
mTabsAdapter.addTab(bar.newTab().setText(getString(R.string.webtab5_name)),
WebTabFragment.MyWebviewFragment.class, tab5Args);
mTabsAdapter.addTab(bar.newTab().setText(getString(R.string.webtab6_name)),
WebTabFragment.MyWebviewFragment.class, tab6Args);
mTabsAdapter.addTab(bar.newTab().setText(getString(R.string.webtab7_name)),
WebTabFragment.MyWebviewFragment.class, tab7Args);
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}
/**
* This is a helper class that implements the management of tabs and all
* details of connecting a ViewPager with associated TabHost. It relies on a
* trick. Normally a tab host has a simple API for supplying a View or
* Intent that each tab will show. This is not sufficient for switching
* between pages. So instead we make the content part of the tab host
* 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
* view to show as the tab content. It listens to changes in tabs, and takes
* care of switch to the correct paged in the ViewPager whenever the selected
* tab changes.
*/
public static class TabsAdapter extends FragmentPagerAdapter implements ActionBar.TabListener, ViewPager.OnPageChangeListener{
private final Context mContext;
//private final TabHost mTabHost;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(FragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = ((SherlockFragmentActivity) activity).getSupportActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
#Override
public int getCount()
{
int iCount = mTabs.size();
return iCount;
}
#Override
public Fragment getItem(int position)
{
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
}
#Override
public void onPageSelected(int position)
{
mActionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrollStateChanged(int state)
{
}
#Override
public void onTabSelected(Tab tab)
{
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
#Override
public void onTabUnselected(Tab tab)
{
}
#Override
public void onTabReselected(Tab tab)
{
}
}
}
Here's the code for the tab fragments:
EDITED:
public class WebTabFragment extends SherlockFragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState == null)
{
FragmentManager fm = getSupportFragmentManager();
if (fm.findFragmentById(android.R.id.content) == null) {
MyWebviewFragment myWebView = new MyWebviewFragment();
fm.beginTransaction().add(android.R.id.content, myWebView).commit();
}
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//outState.putString("tabNumber", mTabNumber);
}
public static class MyWebviewFragment extends SherlockFragment {
final static private String tag = MyWebviewFragment.class.getSimpleName();
String mTabURL;
private WebView mWebView = null;
static final int REFRESH_ID = Menu.FIRST;
private ProgressDialog spinnerDlg;
#Override
public void onSaveInstanceState(Bundle outState)
{
if(mWebView.saveState(outState) == null)
Log.i(tag,"Saving state FAILED!");
else
Log.i(tag, "Saving state succeeded.");
}
#Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
}
#Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.add(Menu.NONE, REFRESH_ID, 0, getString(R.string.refresh_string))
.setIcon(R.drawable.ic_action_refresh)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
}
#Override public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case REFRESH_ID:
if(mWebView != null)
mWebView.reload();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**
* When creating, retrieve this instance's number from its arguments.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Tell the framework to try to keep this fragment around
// during a configuration change.
setRetainInstance(true);
mTabURL = getArguments() != null ? getArguments().getString("tabURL") : "http://www.google.com";
}
/**
* The Fragment's UI is just a simple text view showing its
* instance number.
*/
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Create view object to return
View v = inflater.inflate(R.layout.webview_layout, container, false);
// Set up webview object
if (mWebView != null) {
mWebView.destroy();
}
mWebView = (WebView)v.findViewById(R.id.webview_fragment);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setOnKeyListener(new OnKeyListener(){
#Override
public boolean onKey(View v, int keyCode, KeyEvent event)
{
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return false;
}
});
// Check to see if it has been saved and restore it if true
if(savedInstanceState != null)
{
if (savedInstanceState.isEmpty())
Log.i(tag, "Can't restore state because bundle is empty.");
else
{
if (mWebView.restoreState(savedInstanceState) == null)
Log.i(tag, "Restoring state FAILED!");
else
Log.i(tag, "Restoring state succeeded.");
}
}
else
{
// Load web page
mWebView.setWebViewClient(new MyWebViewClient());
mWebView.getSettings().setPluginsEnabled(true);
mWebView.getSettings().setBuiltInZoomControls(false);
mWebView.getSettings().setSupportZoom(false);
mWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
mWebView.getSettings().setAllowFileAccess(true);
mWebView.getSettings().setDomStorageEnabled(true);
mWebView.loadUrl(mTabURL);
}
return v;
}
#Override
public void onDestroy()
{
super.onDestroy();
}
#Override
public void onDestroyView()
{
super.onDestroyView();
}
#Override
public void onPause()
{
super.onPause();
}
#Override
public void onResume()
{
super.onResume();
}
#Override
public void onConfigurationChanged(Configuration newConfig)
{
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
}
public class MyWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// YouTube video link
if (url.startsWith("http://youtu.be"))
{
String urlSubString = url.substring("http://youtu.be/".length());
String newURL = String.format("http://www.youtube.com/v/%s", urlSubString);
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(newURL)));
return (true);
}
return (false);
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
if(spinnerDlg == null)
{
spinnerDlg = new ProgressDialog(getActivity());
spinnerDlg.setMessage("Loading....");
spinnerDlg.show();
}
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if(spinnerDlg != null)
{
spinnerDlg.dismiss();
}
spinnerDlg = null;
}
}
}
}
Tabs count will start form 0 so in viewPager you have to set the screen limit like below
Example if you have 3 tabs just give
viewPager.setOffscreenPageLimit(2);
Thats one of the properties of tabs. It loads the second one so you aren't swiping to a null tab.. You're welcome to override the tab class and handle that yourself if you want :D.
If you are using fragments, consider using ViewPager. Its much easier to implement and faster in response.
example here,
http://android-developers.blogspot.com/2011/08/horizontal-view-swiping-with-viewpager.html
You say
onCreate is called as well (should not happen)
But that's exactly what should happen if you use ViewPager. How else would you see the fragment if you swipe it half way between the first and second tab?
If you tap on tab 2, it will be recreated maybe, because it is destroyed. Try to override getItemPosition like this:
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}