Splash Screen in Android using Fragment - android

I am designing an android application where I need to add the splash screen of my application. Generally I used to use only Activity upto till now but for this project ADT is creating the Fragment also with Activity.
Now I have a confusion where I should write code of timerTask and Timer to schedule a task to perform either in onCreate of the Activity or onCreateView method or something else ?
Currently I have written like this but I am not sure it is right or wrong.
public class SplashActivity extends Activity {
// using timer to do operation at certain 3 seconds after.
private Timer mTimer;
private TimerTask mTimerTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
// execute this after 3 seconds
mTimerTask = new TimerTask() {
#Override
public void run() {
// start the activity (Login/Home) depends on the login
// status
}
};
mTimer = new Timer();
mTimer.schedule(mTimerTask, 3000);
}
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_splash,
container, false);
return rootView;
}
}
#Override
public void onBackPressed() {
super.onBackPressed();
// cancel the timer if user has pressed the back button to abort it.
if(mTimer !=null)
mTimer.cancel();
}
}

where I should write code of timerTask and Timer to schedule a task to perform either in onCreate of the Activity or onCreateView method or something else ?
Create another Activity and write your timer task code and then navigate to your home activity.Do something like below,
public class MySplash extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
new Handler().postDelayed(new Runnable() {
#Override
public void run()
{
startActivity(new Intent(MySplash.this,SplashActivity.class));
finish();
}
}, 3000);
}
}
then change you home screen code like below where you need to show your fragment class only.
public class SplashActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
Don't forget to add the MySplash in your manifest file and to make it a launcher Activity.
Note: As per the other answer, it's not recommendable to use Splash Screen unless until it is required so much.
Reference,
http://cyrilmottier.com/2012/05/03/splash-screens-are-evil-dont-use-them/

Don't include splash screens in Android. It's bad design. It ruins user experience.
Users don't like to wait. Instead, show them your normal activity and put a ProgressBar in the ActionBar or something.
If the only reason you want a splash screen is to show your logo and brand colors, you should do that in the ActionBar. Style your ActionBar to your brand colors and put the logo of your app at the left of the ActionBar.
http://developer.android.com/design/patterns/help.html#your-app

Related

if i put a toast message in onCreate() function, will message be printed infinitely?

public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listen();
}
public void listen() {
Toast a = Toast.makeText(MainActivity.this,"HI",Toast.LENGTH_SHORT);
a.show();
}
}
Will this goes on printing the HI string..?
No It won't.
However, onCreate() function is called somewhat more often than you think!
(like on Screen Rotation and more ...)
Checkout Activity Lifecycle and learn when onCreate() is called.

How to cancel a asyncTask when a swipe tab is rotated?

Well, i have 3 swipe tabs and in each tab i have called a asynctask in the fragments onCreateView() method. Its showing result in normal case but the problem is when i rotate the screen. Basically it closes forcefully when a asynctask is going on and before completing the task-i rotate the screen.
So, i have tried to cancel the asynctask in onPause and call it again in onCreateView(). Below is the code inside a fragment:
public class AllFragment extends Fragment
{
SearchBusBeans searchBusObj;
ArrayList<SearchBusBeans> searchBusObj_arr;
SearchingBusesAdapter myAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{ .....
....
searchBusObj_arr = new ArrayList<SearchBusBeans>();
new GetSearchedBusesAsync().execute();
}
#Override
public void onPause() {
super.onPause();
GetSearchedBusesAsync asyncObj = new GetSearchedBusesAsync();
if(asyncObj.getStatus() == AsyncTask.Status.RUNNING){
asyncObj.cancel(true);
}
}
private class GetSearchedBusesAsync extends AsyncTask<Void, Void, Void>
{
#Override
protected void onPreExecute() { super.onPreExecute(); }
#Override
protected Void doInBackground(Void... params)
{
if(isCancelled())
this.cancel(true);
if(!isCancelled())
{...........
......do my codes.......
searchBusObj = new SearchBusBeans();
searchBusObj.setname(j_name);
searchBusObj_arr.add(searchBusObj);
}
return null;
}
#Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
pBar.setVisibility(View.GONE);
myAdapter = new SearchingBusesAdapter(getActivity().getApplicationContext(), searchBusObj_arr);
gridView.setAdapter(myAdapter);
}
} //end of asynctask
} //end of fragment
Now as you can see that i have cancelled the asynctask in onPause. and inside doInBackground() i have done my code in condition-if(!isCancelled()). So, shouldn't the asynctask exit and not go to onPostExecute()?
Where am i going wrong? and how to do the cancellation and execution properly?
You can set your fragment to retain its state through a rotation. This will allow your AsyncTask to keep running.
public class AllFragment extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
Override the onCreate method of the fragment and call setRetainInstance(true);. This keeps the fragment alive so that it doesn't get destroyed and then recreated during a configuration change.
There is another approach to stop the execution of an AsyncTask (on any event,not necessary on rotation):
1) Save your AsyncTask in a variable when you call .execute()
mTask = new YourAsyncTask().execute();
2) Then, when you need to stop the task call .cancel()
if(mTask != null) {
mTask.cancel(true);
}
This approach works for me perfectly and it is usable almost for any scenario. Hope it helps!

How to avoid some custom views freezing the UI thread?

I have 9 custom views (extending the View class each of them) in one of my game window that are causing a freeze in my UI thread, when I press the "Play" button, the app freezes (when inflating the layout in "onCreateView", i'm using Fragments) until the game window is generated, something very very ugly.
I'm trying to do this in a separate thread but all are problems, Android doesn't allow me to create new views out of the main (UI) thread.
I tried so many things but I can't get it, could anyone tell me how to achieve this?
Thank you very much
For very cpu intensive drawing you can use.
http://developer.android.com/reference/android/view/SurfaceView.html
One of the purposes of this class is to provide a surface in which a
secondary thread can render into the screen.
I solved it by manually inflating the layout in an AsyncTask. I call the AsyncTask from the "Play Window" where I show a "loading" view and in "onPostExecute" I create the "Game Window" (Fragment) and replace it.
Some dummy code (PlayFragment is the previous screen of GameFragment):
"Play button click" (PlayFragment):
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_play:
Bundle bundle = new Bundle();
bundle.putSerializable(ARG_SELECTED_GAME, selectedGame);
rlLoadingGame.setVisibility(View.VISIBLE);
GameFragment gameFragment = GameFragment.newInstance(selectedGame);
gameFragment.loadGame(activity, bundle);
break;
}
}
loadGame method (GameFragment):
public void loadGame(Activity activity, Bundle bundle) {
this.activity = activity;
if (bundle != null) {
currentGame = (Game) bundle.getSerializable(ARG_SELECTED_GAME);
}
new GenerateGame(bundle).execute();
}
GenerateGame AsyncTask (GameFragment):
class GenerateGame extends AsyncTask<Void, Void>, View> {
private Bundle bundle;
public GenerateGame(Bundle bundle) {
this.bundle = bundle;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
// do your stuff
}
#Override
protected View doInBackground(Void... params) {
View child = activity.getLayoutInflater().inflate(R.layout.game_fragment_layout, null);
// do all your heavy load stuff
return child;
}
#Override
protected void onPostExecute(View layout) {
super.onPostExecute(layout);
// initialize and set all UI elements
replaceFragment(layout, bundle);
}
}
replaceFragment method (GameFragment):
private void replaceFragment(View newView, Bundle bundle) {
fragmentLayout = newView;
// call to fragment manager replace/add or required method passing this as Fragment to replace and the bundle if needed
}
onCreateView (GameFragment):
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (fragmentLayout != null) {
return fragmentLayout;
} else {
return null;
}
}
This is the first approach so it can be refactored and so many things can be done in a better way but it is up to you.

Which is the best way to show a loading sign to the fragment when data loading?

We use viewpager fragment in it, we want to show every single page when viewpager show a fragment and load data , because it saves memory a lot, but we can not show a sign for loading when data loading, we replace a fragment when asynctask's onPreExecute calls and we replace again when calls onPostExecute, but there is some thing wrong, which is the best way to show loading sign when data loading?
public class TestFragment extends Fragment {
private FragmentManager manager = null;
private class TestTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
getFragmentManager().beginTransaction()
.replace(R.id.content_container, new LoadingFragment())
.commit();
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... arg0) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
getFragmentManager().beginTransaction()
.replace(R.id.content_container, new ContentFragment())
.commit();
super.onPostExecute(result);
}
}
public TestFragment(FragmentManager supportFragmentManager) {
this.manager = supportFragmentManager;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new TestTask().execute();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.empty_page, null);
}
}
Another easy way if you use the action bar in your app is calling supportRequestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); in the FragmentActivity right after super.onCreate(savedInstanceState); and from the child fragment ((ActionBarActivity)getActivity()).setSupportProgressBarIndeterminateVisibility(visibility); will show or hide a progress bar in the action bar of your hosting activity depending on your progress in the AsyncTask.
Note: I'm using support appcompat, but I'm pretty sure the methods are the same if you use ActionBarSherlock.
add an progressbar to the layout of the fragment but defining it invisible and centering it both vertically and horizontally. then in the onPreExecute set the visibility of all other views to Visibility.GONE and set the progressbar to VISIBLE. reverse this in the onPostExecute() method!

Loader is not retained after starting new activity, changing orientation in new activity and pressing back button

I been running into an issue with loaders lately. I created a small project that reproduces the issue https://github.com/solcott/loaders-orientation-change
I have a simple Activity that adds a fragment
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Fragment mainFragment = getFragmentManager().findFragmentById(R.id.main_fragment);
if(mainFragment == null){
Log.w(getClass().getSimpleName(), "creating new Fragment");
mainFragment = new MainFragment();
getFragmentManager().beginTransaction().add(R.id.main_fragment, mainFragment).commit();
}
}
}
In my fragment I start a Loader that just returns an integer that is displayed on the screen. There is also a button that starts a new Activity:
public class MainFragment extends Fragment implements LoaderCallbacks<Integer> {
private static int NEXT_VAL = 0;
TextView text1;
Button button1;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().initLoader(1, null, this);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
text1 = (TextView) view.findViewById(android.R.id.text1);
button1 = (Button) view.findViewById(android.R.id.button1);
button1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(getActivity(), NextActivity.class));
}
});
}
#Override
public Loader<Integer> onCreateLoader(int id, Bundle args) {
AsyncTaskLoader<Integer> loader = new AsyncTaskLoader<Integer>(
getActivity()) {
#Override
public Integer loadInBackground() {
return NEXT_VAL++;
}
};
loader.forceLoad();
return loader;
}
#Override
public void onLoadFinished(Loader<Integer> loader, Integer data) {
text1.setText(data.toString());
}
#Override
public void onLoaderReset(Loader<Integer> loader) {
// TODO Auto-generated method stub
}
}
Up to this point everything works fine I can change the orientation and the integer that is displayed doesn't change. I can even start the new activity and then hit the back button and the integer displayed doesn't change.
However, when I navigate to the new Activity, change orientation and press the back button the integer is incremented. I would expect it to behave the same way that it did without the orientation change.
Calling setRetainInstance(true) in Fragment.onCreate() make it even worse. onLoadComplete is never called and the integer is not displayed at all.
Has anyone else run into this issue and found a workaround?
Same question as asked here: Loader unable to retain itself during certain configuration change
This is a damn annoying problem with AsyncTask loaders. Although a solution is proposed in that thread, I think the general consensus is to avoid AsyncTaskLoaders.

Categories

Resources