Can you use Flutter MethodChannel to return a native map from Java

huangapple 未分类评论48阅读模式
英文:

Can you use Flutter MethodChannel to return a native map from Java

问题

I'm sorry, but you've provided quite a lengthy code snippet that includes various parts such as Flutter Dart code, Java code, and explanations. It's not feasible to translate the entire code and explanations accurately within the limitations of this response format. However, if you have specific questions about parts of the code or need help with particular issues, feel free to ask, and I'll do my best to assist you.

英文:

I am attempting to to create a widget from a native view navigation map using method channels and AndroidViews but I keep running into this problem:

E/MethodChannel#flutter/platform_views( 2258): Failed to handle method call
E/MethodChannel#flutter/platform_views( 2258): java.lang.IllegalArgumentException: Cannot add a null child view to a ViewGroup.

Here is the flutter Code :

Main.dart

import 'navigation_view.dart';
import 'package:expandable_bottom_sheet/expandable_bottom_sheet.dart';
import 'package:flutter/material.dart';
import 'customButton1.dart';
import 'Constantes.dart';

void main() => runApp(MaterialApp(home: TextViewExample()));

class TextViewExample extends StatefulWidget {
  @override
  _TextViewExampleState createState() => _TextViewExampleState();
}

class _TextViewExampleState extends State<TextViewExample>
	with SingleTickerProviderStateMixin {
  @override
  void initState() {
	super.initState();
  }

  Widget build(BuildContext context) {
//    var s = NavigationView(
//      onNavigationViewCreated: _onNavigationViewCreated,
//    );
	double screenWidth, screenHeight;
	Size size = MediaQuery.of(context).size;
	screenHeight = size.height;
	screenWidth = size.width;
	print("FLUTTER INIT");
	return Scaffold(
		body: SafeArea(
	  child: Stack(children: [
		Positioned(
		  width: screenWidth,
		  height: screenHeight - 220,
		  child: Container(
			child: NavigationView(
			  onNavigationViewCreated: _onNavigationViewCreated,
			),
		  ),
		),
		Positioned(
		  bottom: 75,
		  child: Container(
			height: screenHeight,
			width: screenWidth,
			

  void _onNavigationViewCreated(NavigationViewController controller) {}
}   

Here is navigation_view.dart

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

typedef void NavigationViewCreatedCallback(NavigationViewController controller);

class NavigationView extends StatefulWidget {
  const NavigationView({
	Key key,
	this.onNavigationViewCreated,
  }) : super(key: key);

  final NavigationViewCreatedCallback onNavigationViewCreated;

  @override
  State<StatefulWidget> createState() => _NavigationViewState();
}

class _NavigationViewState extends State<NavigationView> {
  @override
  Widget build(BuildContext context) {
	if (defaultTargetPlatform == TargetPlatform.android) {
	  return AndroidView(
		viewType: 'com.Mavic.Cabinn/navigationview',
		onPlatformViewCreated: _onPlatformViewCreated,
	  );
	}
	return Text(
		'$defaultTargetPlatform is not yet supported by the navigation_view plugin');
  }

  void _onPlatformViewCreated(int id) {
	if (widget.onNavigationViewCreated == null) {
	  return;
	}
	widget.onNavigationViewCreated(new NavigationViewController._(id));
  }
}

class NavigationViewController {
  NavigationViewController._(int id)
	  : _channel = new MethodChannel(
			'com.Mavic.Cabinn/navigationview$id');

  final MethodChannel _channel;

//  Future<void> setNavigation() async {
//    try {
//      Future.delayed(const Duration(seconds: 1), () async {
//        await _channel.invokeMethod('EmpezarNavegacion');
//
//        return;
//      });
//    } on PlatformException catch (e) {
//      print(e);
//    }
//  Future<void> setNavigation() async {
//    assert(AndroidView != null);
//    return _channel.invokeMethod('EmpezarNavegacion');
//  }
//}

  Future<dynamic> setNavigation() async {
	String message;
	try {
	  final String result = await _channel.invokeMethod('EmpezarNagevacion');
	  message = result;
	} on PlatformException catch (e) {
	  print(message);
	}
  }
}

And Finally the Java Code

package com.example.embeded_java_test;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.location.Location;
import android.os.Bundle;
import android.preference.PreferenceManager;


import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.AbsoluteSizeSpan;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.mapbox.api.directions.v5.DirectionsCriteria;
import com.mapbox.api.directions.v5.models.BannerInstructions;
import com.mapbox.api.directions.v5.models.DirectionsResponse;
import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.services.android.navigation.ui.v5.route.NavigationMapRoute;
import com.example.embeded_java_test.R;
import com.mapbox.services.android.navigation.ui.v5.NavigationView;
import com.mapbox.services.android.navigation.ui.v5.NavigationViewOptions;
import com.mapbox.services.android.navigation.ui.v5.OnNavigationReadyCallback;
//import com.mapbox.services.android.navigation.ui.v5.listeners.BannerInstructionsListener;
//import com.mapbox.services.android.navigation.ui.v5.listeners.InstructionListListener;
import com.mapbox.services.android.navigation.ui.v5.listeners.BannerInstructionsListener;
import com.mapbox.services.android.navigation.ui.v5.listeners.InstructionListListener;
import com.mapbox.services.android.navigation.ui.v5.listeners.NavigationListener;
//import com.mapbox.services.android.navigation.ui.v5.listeners.SpeechAnnouncementListener;
//import com.mapbox.services.android.navigation.ui.v5.voice.SpeechAnnouncement;
import com.mapbox.services.android.navigation.ui.v5.listeners.SpeechAnnouncementListener;
import com.mapbox.services.android.navigation.ui.v5.voice.SpeechAnnouncement;
import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute;
import com.mapbox.services.android.navigation.v5.routeprogress.ProgressChangeListener;
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;

import java.util.Locale;
import java.util.concurrent.Future;

import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import androidx.appcompat.app.AppCompatDelegate;
import androidx.coordinatorlayout.widget.CoordinatorLayout;

import org.jetbrains.annotations.NotNull;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.platform.PlatformView;
import com.example.embeded_java_test.MainActivity;

public class EmbeddedNavigationActivity extends AppCompatActivity implements OnNavigationReadyCallback,
		NavigationListener, ProgressChangeListener, InstructionListListener, SpeechAnnouncementListener,
		BannerInstructionsListener,PlatformView, MethodCallHandler {

	private  Point ORIGIN = Point.fromLngLat(-77.03194990754128, 38.909664963450105);
	private  Point DESTINATION = Point.fromLngLat(-77.0270025730133, 38.91057077063121);
	private  final int INITIAL_ZOOM = 16;

	private NavigationView navigationView;
	private View spacer;
	private TextView speedWidget;
	private final MethodChannel methodChannel;

	private boolean bottomSheetVisible = true;
	private boolean instructionListShown = false;
	private NavigationMapRoute navigationMapRoute;
//    @Override
//    public void onCreate(@Nullable Bundle savedInstanceState) {
//        super.onCreate(savedInstanceState);
//        navigationView = findViewById(R.id.navigationView);
//        navigationView.onCreate(savedInstanceState);
//        setTheme(R.style.Theme_AppCompat_Light_NoActionBar);
//        //initNightMode();

	@Override
	public void dispose() {}

	private Context context;
	private Activity activity;
	private Bundle savedInstance;


	public EmbeddedNavigationActivity(Context currentContext, Activity currentActivity, Bundle currentBundle,BinaryMessenger messenger, int id)
	{

		new MainActivity();
		MainActivity newMain = new MainActivity();
		this.activity=this;
		System.out.println(activity + "Activity");
		this.context=this;
		System.out.println(context + "Context");


		System.out.println(activity);
		Log.i("Here", "Constructor!!!");

		System.out.println(activity + " This Activity");
		this.savedInstance=currentBundle;
		System.out.println(currentContext + "Context");
//
		methodChannel = new MethodChannel(messenger, "com.Mavic.Cabinn/navigationview_" + id);
		methodChannel.setMethodCallHandler(this);
	}


	@Override
	public View getView() {
		Log.i("Here", "GETVIEW");
		return navigationView;
	}




	public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
		Log.i("MSG", "CALLING SET TEXT");
				switch (methodCall.method) {
			case "EmpezarNavegacion":
				EmpezarNavegacion(methodCall, result);
					result.success(null);
				break;
			default:
				result.notImplemented();
		}

 }


	public void EmpezarNavegacion(MethodCall methodCall, Result result)
	{
		double LtLang = (double) methodCall.arguments;
		result.success(null);


		Mapbox.getInstance(context, activity.getString(R.string.access_token));
		activity.setContentView(R.layout.cabinn_nav);

		navigationView =activity.findViewById(R.id.navigationView);
		//super.onCreate(savedInstanceState);
		//Mapbox.getInstance(this,getString(R.string.access_token));
		//navigationView =(NavigationView)findViewById(R.id.navigationView);
		if(navigationView==null)
		{
			Log.e("ERROR NAVEGACION","NAVIGATION VIEW ES NULL, NO ESTA SETEADO EL CONTENT");
			return;
		}
		//fabNightModeToggle = findViewById(R.id.fabToggleNightMode);
		//speedWidget = findViewById(R.id.speed_limit);
		//spacer = findViewById(R.id.spacer);
		//setSpeedWidgetAnchor(R.id.summaryBottomSheet);
//        ORIGIN=ORIGEN;
//        DESTINATION=DESTINO;
		CameraPosition initialPosition = new CameraPosition.Builder()
				.target(new LatLng(ORIGIN.latitude(), ORIGIN.longitude()))
				.zoom(INITIAL_ZOOM)
				.build();
		//navigationView.onCreate(savedInstanceState);
		navigationView.onCreate(this.savedInstance);
		navigationView.initialize(this, initialPosition);
	}
	@Override
	public void onNavigationReady(boolean isRunning) {
		//navigationView.findViewById(R.id.instructionLayoutText).setVisibility(View.INVISIBLE);

		navigationView.findViewById(R.id.instructionListLayout).setVisibility(View.INVISIBLE);
		//navigationView.findViewById(R.id.maneuverView).setVisibility(View.INVISIBLE);
		navigationView.findViewById(R.id.summaryBottomSheet).setVisibility(View.INVISIBLE);
		navigationView.findViewById(R.id.feedbackFab).setVisibility(View.INVISIBLE);
		navigationView.findViewById(R.id.subStepText).setVisibility(View.INVISIBLE);
		navigationView.findViewById(R.id.subStepLayout).setVisibility(View.INVISIBLE);
		navigationView.findViewById(R.id.summaryContentLayout).setVisibility(View.INVISIBLE);
		//navigationView.findViewById(R.id.subManeuverView).setVisibility(View.INVISIBLE);
		//navigationView.findViewById(R.id.stepDistanceText).setVisibility(View.INVISIBLE);
		//navigationView.findViewById(R.id.stepPrimaryText).setVisibility(View.INVISIBLE);
		//navigationView.findViewById(R.id.stepSecondaryText).setVisibility(View.INVISIBLE);

		fetchRoute();
	}

	public void onStart_() {
		Log.i("NAV","NAVIGATION START");
		navigationView.onStart();
	}

	public void onResume_() {
		navigationView.onResume();
	}

	public void onLowMemory_() {
		navigationView.onLowMemory();
	}

	public void onBackPressed_() {
// If the navigation view didn't need to do anything, call super
		if (!navigationView.onBackPressed()) {
			super.onBackPressed();
		}
	}

	protected void onSaveInstanceState_(Bundle outState) {
		navigationView.onSaveInstanceState(outState);
	}

	protected void onRestoreInstanceState_(Bundle savedInstanceState) {
		navigationView.onRestoreInstanceState(savedInstanceState);
	}

	public void onPause_() {
		navigationView.onPause();
	}

	public void onStop_() {
		navigationView.onStop();
	}

	protected void onDestroy_() {
		navigationView.onDestroy();
		if (isFinishing()) {
			saveNightModeToPreferences(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
			AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
		}
	}
	@Override
	public void onCancelNavigation() {
// Navigation canceled, finish the activity
		finish();
	}
	@Override

	public void onNavigationFinished() {
// Intentionally empty
	}
	@Override

	public void onNavigationRunning() {
// Intentionally empty
	}
	@Override

	public void onProgressChange(Location location, RouteProgress routeProgress) {
		setSpeed(location);
	}
	@Override

	public void onInstructionListVisibilityChanged(boolean shown) {
		instructionListShown = shown;
		speedWidget.setVisibility(shown ? View.GONE : View.VISIBLE);
		if (instructionListShown) {
		   // fabNightModeToggle.hide();
		} else if (bottomSheetVisible) {
			//fabNightModeToggle.show();
		}
	}

	@Override
	public SpeechAnnouncement willVoice(SpeechAnnouncement announcement) {
		return SpeechAnnouncement.builder().announcement("All announcements will be the same.").build();
	}

	@Override
	public BannerInstructions willDisplay(BannerInstructions instructions) {
		return instructions;
	}

	private void startNavigation(DirectionsRoute directionsRoute) {
		NavigationViewOptions.Builder options =
				NavigationViewOptions.builder()
						.navigationListener(this)
						.directionsRoute(directionsRoute)
						.shouldSimulateRoute(true)
						.progressChangeListener(this);
						//.instructionListListener(this)
						//.speechAnnouncementListener(this)
					   // .bannerInstructionsListener(this);
		setBottomSheetCallback(options);
		//setupNightModeFab();

		navigationView.startNavigation(options.build());
	}

	private void fetchRoute() {
		NavigationRoute.builder(this.context)
				.accessToken(this.activity.getString(R.string.access_token))
				.origin(ORIGIN)
				.voiceUnits(DirectionsCriteria.METRIC)
				.destination(DESTINATION)
				.alternatives(true)
				.build()
				.getRoute(new Callback<DirectionsResponse>() {
					@Override
					public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
						if(response.body() == null)
						{
							Log.e("ERROR RUTA","NO RUTA ENCONTRADA");
							return;
						}else if(response.body().routes().size()==0)
						{
							Log.e("ERROR RUTA","SIN RUTA ENCONTRADA");
							return;
						}
						DirectionsRoute currentRoute = response.body().routes().get(0);

						//navigationMapRoute.addRoute(currentRoute);
						startNavigation(currentRoute);
					}

					@Override
					public void onFailure(Call<DirectionsResponse> call, Throwable t) {

					}
				});
	}
	void simpleCallBack(Call<DirectionsResponse> call, Response<DirectionsResponse> response)
	{
		DirectionsRoute directionsRoute = response.body().routes().get(0);
		startNavigation(directionsRoute);
	}

	private void setSpeedWidgetAnchor(@IdRes int res) {
		//CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) spacer.getLayoutParams();
		//layoutParams.setAnchorId(res);
		//spacer.setLayoutParams(layoutParams);
	}

	private void setBottomSheetCallback(NavigationViewOptions.Builder options) {
		options.bottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
			@Override
			public void onStateChanged(@NonNull View bottomSheet, int newState) {
				switch (newState) {
					case BottomSheetBehavior.STATE_HIDDEN:
						bottomSheetVisible = false;
						//fabNightModeToggle.hide();
						setSpeedWidgetAnchor(R.id.recenterBtn);
						break;
					case BottomSheetBehavior.STATE_EXPANDED:
						bottomSheetVisible = true;
						break;
					case BottomSheetBehavior.STATE_SETTLING:
						if (!bottomSheetVisible) {
// View needs to be anchored to the bottom sheet before it is finished expanding
// because of the animation
							//fabNightModeToggle.show();
							setSpeedWidgetAnchor(R.id.summaryBottomSheet);
						}
						break;
					default:
						return;
				}
			}

			@Override
			public void onSlide(@NonNull View bottomSheet, float slideOffset) {
			}
		});
	}

	private void setupNightModeFab() {
		//fabNightModeToggle.setOnClickListener(view -> toggleNightMode());
	}

	private void toggleNightMode() {
		int currentNightMode = getCurrentNightMode();
		alternateNightMode(currentNightMode);
	}

	private void initNightMode() {
	   // int nightMode = retrieveNightModeFromPreferences();
		//AppCompatDelegate.setDefaultNightMode(nightMode);
	}

	private int getCurrentNightMode() {
		return getResources().getConfiguration().uiMode
				& Configuration.UI_MODE_NIGHT_MASK;
	}

	private void alternateNightMode(int currentNightMode) {
		int newNightMode;
		if (currentNightMode == Configuration.UI_MODE_NIGHT_YES) {
			newNightMode = AppCompatDelegate.MODE_NIGHT_NO;
		} else {
			newNightMode = AppCompatDelegate.MODE_NIGHT_YES;
		}
		saveNightModeToPreferences(newNightMode);
		recreate();
	}


	private void saveNightModeToPreferences(int nightMode) {
		SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
		SharedPreferences.Editor editor = preferences.edit();
		//editor.putInt(getString(R.string.current_night_mode), nightMode);
		editor.apply();
	}

	private void setSpeed(Location location) {
		String string = String.format("%d\nMPH", (int) (location.getSpeed() * 2.2369));
		//int mphTextSize = getResources().getDimensionPixelSize(R.dimen.mph_text_size);
		//int speedTextSize = getResources().getDimensionPixelSize(R.dimen.speed_text_size);

		SpannableString spannableString = new SpannableString(string);
	   // spannableString.setSpan(new AbsoluteSizeSpan(mphTextSize),
		//        string.length() - 4, string.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);

	   // spannableString.setSpan(new AbsoluteSizeSpan(speedTextSize),
		 //       0, string.length() - 3, Spanned.SPAN_INCLUSIVE_INCLUSIVE);


	}
}

I used this article as reference in order to attempt to replicate this but I hit many a speed bump trying to get this to work properly: https://medium.com/flutter-community/flutter-platformview-how-to-create-flutter-widgets-from-native-views-366e378115b6

This is my flutter doctor output:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.12.13+hotfix.9, on Linux, locale en_US.UTF-8)
 
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[✓] Android Studio (version 3.6)
[✓] Connected device (1 available)

• No issues found!

Like I was saying ive been attempting to find a null value and searched high and low for questions similar to this one but Ive had no such luck as this is not something Ive seen done. I also checked if there were any plugins to create and embedded map and unfortunately there arent any at the moment.

huangapple
  • 本文由 发表于 2020年4月11日 00:30:54
  • 转载请务必保留本文链接:https://java.coder-hub.com/61144537.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定