title: The method nextPage() and previousPage() in PageController doesn't work sometimes
body: <p>Here is my code:
  I response key event in Android MainActivity, and use BasicMessageChannel to post key message:</p>
  
  <pre><code>public class MainActivity extends FlutterActivity {
  
  private static final String CHANNEL = "scroll";
  private static final String KEY_LEFT = "keyLeft";
  private static final String KEY_RIGHT = "keyRight";
  private BasicMessageChannel messageChannel;
  private FlutterView flutterView;
  
  private String[] getArgsFromIntent(Intent intent) {
      // Before adding more entries to this list, consider that arbitrary
      // Android applications can generate intents with extra data and that
      // there are many security-sensitive args in the binary.
      ArrayList&lt;String&gt; args = new ArrayList&lt;String&gt;();
      if (intent.getBooleanExtra("trace-startup", false)) {
          args.add("--trace-startup");
      }
      if (intent.getBooleanExtra("start-paused", false)) {
          args.add("--start-paused");
      }
      if (intent.getBooleanExtra("enable-dart-profiling", false)) {
          args.add("--enable-dart-profiling");
      }
      if (!args.isEmpty()) {
          String[] argsArray = new String[args.size()];
          return args.toArray(argsArray);
      }
      return null;
  }
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      GeneratedPluginRegistrant.registerWith(this);
      flutterView = new FlutterView(this);
      String[] args = getArgsFromIntent(getIntent());
      FlutterMain.ensureInitializationComplete(getApplicationContext(), args);
      flutterView.runFromBundle(FlutterMain.findAppBundlePath(getApplicationContext()), null);
      messageChannel = new BasicMessageChannel&lt;&gt;(flutterView, CHANNEL, StringCodec.INSTANCE);
  }
  
  @Override
  public boolean dispatchKeyEvent(KeyEvent event) {
      if (event.getAction() == KeyEvent.ACTION_DOWN) {
          Log.d(TAG, "dispatchKeyEvent: ACTION_DOWN keyCode = " + event.getKeyCode());
          switch (event.getKeyCode()) {
              case KeyEvent.KEYCODE_DPAD_LEFT:
                  messageChannel.send(KEY_LEFT);
                  return true;
  
              case KeyEvent.KEYCODE_DPAD_RIGHT:
                  messageChannel.send(KEY_RIGHT);
                  return true;
  
              default:
                  break;
          }
      }
      return super.dispatchKeyEvent(event);
  }
  
  @Override
  protected void onDestroy() {
      if (flutterView != null) {
          flutterView.destroy();
      }
      super.onDestroy();
  }
  
  @Override
  protected void onPause() {
      super.onPause();
      flutterView.onPause();
  }
  
  @Override
  protected void onPostResume() {
      super.onPostResume();
      flutterView.onPostResume();
  }
  </code></pre>
  
  <p>}</p>
  
  <p>When Flutter receives the message, I call nextPage() and previousPage() to scroll PageView, it doesn't work. But I find if I call nextPage() and previousPage() in onTap() method of the GestureDetector, it works:</p>
  
  <pre><code>class _Page {
    _Page({
      this.imagePath,
    });
  
    final String imagePath;
  }
  
  final List&lt;_Page&gt; _allPages = &lt;_Page&gt;[
    new _Page(imagePath: 'images/1.jpg'),
    new _Page(imagePath: 'images/2.jpg'),
    new _Page(imagePath: 'images/3.jpg'),
    new _Page(imagePath: 'images/4.jpg'),
    new _Page(imagePath: 'images/5.jpg'),
    new _Page(imagePath: 'images/6.jpg'),
  ];
  
  class ScrollablePageDemo extends StatefulWidget {
    @override
    _ScrollablePageDemoState createState() =&gt; new _ScrollablePageDemoState();
  }
  
  class _ScrollablePageDemoState extends State&lt;ScrollablePageDemo&gt;
      with SingleTickerProviderStateMixin {
    PageController _controller;
    static const String _channel = 'scroll';
    static const String _emptyMessage = '';
    static const String KEY_LEFT = "keyLeft";
    static const String KEY_RIGHT = "keyRight";
    static const BasicMessageChannel&lt;String&gt; platform =
        const BasicMessageChannel&lt;String&gt;(_channel, const StringCodec());
  
    @override
    void initState() {
      super.initState();
      _controller = new PageController(
          initialPage: 0, keepPage: true, viewportFraction: 1.0);
      platform.setMessageHandler(changePage);
    }
  
    @override
    void dispose() {
      super.dispose();
      _controller.dispose();
    }
  
    Future&lt;String&gt; changePage(String message) async {
      setState(() {
        print(message);
        if (message == KEY_RIGHT) {
          //here doesn't work
          _controller.nextPage(duration: kTabScrollDuration, curve: Curves.ease);
          print("tab right: page = " + _controller.page.toString());
        } else if (message == KEY_LEFT) {
          //here doesn't work
          _controller.previousPage(duration: kTabScrollDuration, curve: Curves.ease);
          print("tab left: page = " + _controller.page.toString());
        }
      });
      return _emptyMessage;
    }
  
    PageView buildPageView() {
      return new PageView(
        controller: _controller,
        children: _allPages.map((_Page page) {
          return new Container(
              key: new ObjectKey(page.imagePath),
              padding: const EdgeInsets.all(12.0),
              child: new Card(
                  child: new Image.asset(page.imagePath, fit: BoxFit.fill)));
        }).toList(),
      );
    }
  
    @override
    Widget build(BuildContext context) {
      return new GestureDetector(
          onTap: () {
            print('Listen PageView');
            //here works
            _controller.nextPage(duration: kTabScrollDuration, curve: Curves.ease);
          },
          child: new Scaffold(
              appBar: new AppBar(
                title: new Text('PageView'),
              ),
              body: buildPageView()));
    }
  }
  
  void main() {
    runApp(new MaterialApp(
      title: 'Flutter Study',
      home: new ScrollablePageDemo(),
    ));
  }
  </code></pre>