android app anatomy - trifork · android app anatomy eric burke square @burke_eric. topics ... ¥...

82
Android App Anatomy Eric Burke Square @burke_eric

Upload: others

Post on 21-May-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Android App AnatomyEric Burke

Square

@burke_eric

Page 2: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Topics• Android lifecycle• Fragments• Open source• Tape• Otto• Dagger

Page 3: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little
Page 4: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

ActionBarSherlock

Android Design on every device.

Page 5: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Lifecycle

Page 6: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Apps Run Forever

Install

Uninstall

Page 7: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Apps Run Forever

Process 1 Process 2

Page 8: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Apps Run Forever

Process 1 Process 2

Activity ActivityActivity

Page 9: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Apps Run Forever

Process 1 Process 2

Activity ActivityActivity

Static Variables

R.I.P.

Page 10: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Kill your process

Page 11: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little
Page 12: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little
Page 13: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Tape

Page 14: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

“If you respect users, persist tasks

to disk.”- Jesse Wilson

Page 15: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Don’t Do This

Page 16: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Client UI

Image File

Server

Loader or Thread

Page 17: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Do This

Pending

Page 18: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Tape API•QueueFile

•O(1) FIFO queue of byte[]

•ObjectQueue

•A queue of <T>

•TaskQueue

•Injects and starts tasks

Page 19: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

TaskQueue

Tape

add()

peek()remove()

Client UI

Server

ServiceUploadTask UploadTask

Page 20: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Usage Pattern

1. UI adds to a TaskQueue:queue.add(new ImageUploadTask(image));

2. Start the Android Service:context.startService(new Intent(context, ImageUploadTaskService.class));

Page 21: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

3. Service executes the next task:Task t = queue.peek();t.execute(this); // Listener

4. If successful:queue.remove();executeNext();

5. If failure, schedule a retry.

Page 22: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Retrying Failed Tasks

•Always process tasks in order: FIFO

•Distinguish between client bugs vs. network or server exceptions

•Client errors - do not retry

•Server & network errors - retry

Page 23: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Fragment Lifecycle

Page 24: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Time ➞

Activity

onCreate() onSaveInstanceState()

Page 25: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Time ➞

Activity

Tap the Upload Button

Page 26: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Loader or Thread

Time ➞

Activity

Page 27: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Loader or Thread

Time ➞

Activity

DialogFragment

beginTransaction()

Page 28: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Loader or Thread

Time ➞

Activity

DialogFragment

commit()

onSaveInstanceState()

Page 29: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Square does not* use Loaders.

Page 30: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Fragment Layout

Page 31: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little
Page 32: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Advantages

•Smooth animations between steps

•ActionBar does not move

•Code organization

Page 33: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Onboarding

Fragment

Fragment

Fragment

Settings

Fragment

Fragment

Fragment

Payment Flow

Fragment

Fragment

Fragment

Page 34: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Fragment ListenerInterface

Containing Activity

defines

implements

Fragment → Activity Communication

http://developer.android.com/training/basics/fragments/communicating.html

Page 35: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

public class NewsFragment extends Fragment { private Listener listener;

public interface Listener { void onItemSelected(int position); }

@Override public void onAttach(Activity a) { super.onAttach(a);

listener = (Listener) a; }}

Listener Interface

Page 36: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

public class HomeActivity extends Activity implements NewsFragment.Listener {

@Override public void onItemSelected(int position) { … }}

Activity

Page 37: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

public class Onboarding extends Activity implements AccountFragment.Listener, ActivateFragment.Listener, ShippingFragment.Listener, BankFragment.Listener, etc...{ // The god object...}

Page 38: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

How can Fragments communicate without tight Activity coupling?

Activity

Fragment

Fragment

Fragment

Fragment

Fragment

Fragment

Page 39: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Bus

Fragment Fragment

FragmentFragment

Service Activity

Publish Subscribe

Page 40: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

LocalBroadcastManager

•Included in Android Support library

•Publishes Intents within your process

Page 41: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Intent intent = new Intent( BroadcastIds.LOCATION_UPDATED_ACTION); intent.putExtra( BroadcastIds.CURRENT_LOCATION_KEY, getCurrentLocation());

LocalBroadcastManager.getInstance( getActivity()).sendBroadcast(intent);

Publishing

Page 42: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Intent intent = new Intent( BroadcastIds.LOCATION_UPDATED_ACTION); intent.putExtra( BroadcastIds.CURRENT_LOCATION_KEY, getCurrentLocation());

LocalBroadcastManager.getInstance( getActivity()).sendBroadcast(intent);

Publishing

Page 43: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Intent intent = new Intent( BroadcastIds.LOCATION_UPDATED_ACTION); intent.putExtra( BroadcastIds.CURRENT_LOCATION_KEY, getCurrentLocation());

LocalBroadcastManager.getInstance( getActivity()).sendBroadcast(intent);

Publishing

Page 44: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive( Context context, Intent intent) {

Location location = (Location) intent.getParcelableExtra( BroadcastIds.CURRENT_LOCATION_KEY);

showLocation(location); }};

Subscribing

Page 45: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

IntentFilter locationFilter = new IntentFilter( BroadcastIds.LOCATION_UPDATED_ACTION);

@Override public void onResume() { super.onResume(); LocalBroadcastManager.getInstance(getActivity()) .registerReceiver(receiver, locationFilter);}

@Override public void onPause() { super.onPause(); LocalBroadcastManager.getInstance(getActivity()) .unregisterReceiver(receiver);}

Subscribing

Page 46: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Boilerplate.No type safety.Hard to test.

Page 47: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Otto

Page 48: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

public class BaseFragment extends Fragment { @Inject Bus bus;

@Override public void onResume() { super.onResume(); bus.register(this); }

@Override public void onPause() { super.onPause(); bus.unregister(this); }}

Registration

Page 49: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

public class BaseFragment extends Fragment { @Inject Bus bus;

@Override public void onResume() { super.onResume(); bus.register(this); }

@Override public void onPause() { super.onPause(); bus.unregister(this); }}

Registration

Fails fast at runtime.

Page 50: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

@Subscribepublic void onLocationUpdated(Location l) { showLocation(l);}

Subscribing

Receives any type extending Location.

Page 51: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

bus.post(getCurrentLocation());

Publishing

Synchronous delivery.

Page 52: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

@Produce(getting data the first time)

Page 53: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

How to get this image?

Page 54: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

post(UserImage)Bus

UserImageCache

Downloader

Page 55: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

public class AccountActivity extends BaseActivity {

@Subscribe public void onUserImageUpdated( UserImage image) { ((ImageView) findViewById(R.id.image)) .setImageBitmap(image.getBitmap());}

Subscribing

Page 56: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Activity

onResume() onPause()

Downloader

UserImageCache

get() done()

Page 57: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

@Singleton public class UserImageCache {

@Produce public UserImage produceUserImage() { return cachedUserImage; }

…}

Producers

Page 58: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Activity

UserImageCache

@Produce

Bus

@Subscribe

Page 59: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

@Produce decouples threads from the Activity and Fragment lifecycle.

Page 60: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Otto API Summary

•register(), unregister(), post()

•@Subscribe, @Produce

•Thread confinement

•Easy to test!

Page 61: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Origins of Otto

•Forked from Guava’s EventBus

•Optimized for Android - 16k!

•Less reflection; more caching

Page 62: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Dependency Injection

Page 63: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Guice on Android?

•We’ve used it for 2+ years

•Startup performance is a challenge

•Runtime error checking

•See also: RoboGuice

Page 64: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Can we do better?

Page 65: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Dagger†

Page 66: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

What is Dagger?

Compile-timedependency injection.

Page 67: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

import javax.inject.Inject; // JSR-330

public class PublishFragment extends BaseFragment {

@Inject Bus bus; @Inject LocationManager locationManager;

…}

@Inject†

Page 68: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

public class AccountUpdater {

private final Bus bus; private final AccountService accounts;

@Inject public AccountUpdater(Bus bus, AccountService accounts) { this.bus = bus; this.accounts = accounts; }}

Constructor Injection†

Page 69: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

@Module( entryPoints = { HomeActivity.class, PublishFragment.class, SubscribeFragment.class })public class ExampleModule {

@Provides @Singleton Bus provideBus() { return new Bus(); }}

Module†

Page 70: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

@Module( entryPoints = { HomeActivity.class, PublishFragment.class, SubscribeFragment.class })public class ExampleModule {

@Provides @Singleton Bus provideBus() { return new Bus(); }}

Module†

Page 71: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Missing Provider Method?

No injectable members on com.squareup.otto.Bus. Do you want to add an injectable constructor?

required by com.squareup.anatomy.PublishFragment for com.squareup.anatomy.ExampleModule

Page 72: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

public class ExampleApp extends Application { private ObjectGraph objectGraph;

@Override public void onCreate() { super.onCreate();

objectGraph = ObjectGraph.get( new ExampleModule(this)); }

public ObjectGraph objectGraph() { return objectGraph; }}

Bootstrapping†

Page 73: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

public class ExampleApp extends Application { private ObjectGraph objectGraph;

@Override public void onCreate() { super.onCreate();

objectGraph = ObjectGraph.get( new ExampleModule(this)); }

public ObjectGraph objectGraph() { return objectGraph; }}

Bootstrapping†

Page 74: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

public class ExampleApp extends Application { private ObjectGraph objectGraph;

@Override public void onCreate() { super.onCreate();

objectGraph = ObjectGraph.get( new ExampleModule(this)); }

public ObjectGraph objectGraph() { return objectGraph; }}

Bootstrapping†

Page 75: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

public class ExampleApp extends Application { private ObjectGraph objectGraph;

@Override public void onCreate() { super.onCreate();

objectGraph = ObjectGraph.get( new ExampleModule(this)); }

public ObjectGraph objectGraph() { return objectGraph; }}

Bootstrapping†

Page 76: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

BaseFragment

Fragment

AddressFragmentNameFragment

ExampleApp(ObjectGraph)

Page 77: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

public class BaseFragment extends Fragment {

@Override public void onCreate(Bundle state) { super.onCreate(state);

((ExampleApp) getActivity() .getApplication()) .objectGraph().inject(this); }}

Fragment Injection†

Page 78: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

public class BaseFragment extends Fragment {

@Override public void onCreate(Bundle state) { super.onCreate(state);

((ExampleApp) getActivity() .getApplication()) .objectGraph().inject(this); }}

Fragment Injection†

Page 79: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

public class BaseFragment extends Fragment {

@Override public void onCreate(Bundle state) { super.onCreate(state);

((ExampleApp) getActivity() .getApplication()) .objectGraph().inject(this); }}

Fragment Injection†

Page 80: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Dagger Limitations

•No final and private field injection

•No method injection

•No scopes

•@Assisted

Page 81: Android App Anatomy - Trifork · Android App Anatomy Eric Burke Square @burke_eric. Topics ... ¥ Distinguish between client bugs vs. network or server exceptions ... •Very little

Dagger Features

•Compile time injection

•Very little magic

•über fast