This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Unable to call the MainActivity of Android-nRF-Mesh-Library from my Activity in Android for my version of nRF Mesh Provisioner app

I have some working knowledge of Android but I'm new to Fragments, Injection, Binding, ButterKnife .etc. I have gone through some videos and tutorials but can't catch where the problem is.

What I want to do:

There is this activity and Code (MeshInteractionActivity.java) which I've got from a GitHub repository. I want to make another activity which is MainActivity.java and connect to this Mesh Activity on button press. I thought it would be just straightforward to do an Intent from MainActivity to MeshInteractionActivity. But it didn't work. I felt maybe it needs a fragment on MainActivity which Intents to 2nd Activity and so I created MainFragment.java. I get the 2 buttons on my MainFragment but when I press Mesh button i.e. mesh() method in MainFragment I get an app crash.

I tried learning ButterKnife and seeing some videos but they were too basic and I didn't understand how they will fit into my use case. Since my code has a section like this:

@Inject
DispatchingAndroidInjector<Fragment> mDispatchingAndroidInjector;

@Inject
ViewModelProvider.Factory mViewModelFactory;

Things which I've still not got the meaning of.

The error I get:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mrinq.mesh_ha_v01/com.mrinq.mesh_ha_v01.MeshInteractionActivity}: java.lang.IllegalArgumentException: No injector factory bound for Class<com.mrinq.mesh_ha_v01.MeshInteractionActivity>
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2426)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2490)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1354)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5443)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
Caused by: java.lang.IllegalArgumentException: No injector factory bound for Class<com.mrinq.mesh_ha_v01.MeshInteractionActivity>
at dagger.android.DispatchingAndroidInjector.inject(DispatchingAndroidInjector.java:106)
at dagger.android.AndroidInjection.inject(AndroidInjection.java:61)
at com.mrinq.mesh_ha_v01.di.AppInjector.handleActivity(AppInjector.java:88)
at com.mrinq.mesh_ha_v01.di.AppInjector.access$000(AppInjector.java:39)
at com.mrinq.mesh_ha_v01.di.AppInjector$1.onActivityCreated(AppInjector.java:51)
at android.app.Application.dispatchActivityCreated(Application.java:195)
at android.app.Activity.onCreate(Activity.java:926)
at android.support.v4.app.SupportActivity.onCreate(SupportActivity.java:66)
at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:321)
at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:84)
at com.mrinq.mesh_ha_v01.MeshInteractionActivity.onCreate(MeshInteractionActivity.java:87)
at android.app.Activity.performCreate(Activity.java:6259)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1130)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2379)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2490) 
at android.app.ActivityThread.-wrap11(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1354) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5443) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)

My source Activity is MainActivity.java:

public class MainActivity extends AppCompatActivity implements Injectable,
HasSupportFragmentInjector,
BottomNavigationView.OnNavigationItemSelectedListener,
BottomNavigationView.OnNavigationItemReselectedListener,
ScannerFragment.ScannerFragmentListener, FragmentManager.OnBackStackChangedListener,
NetworkFragment.NetworkFragmentListener,
MainFragment.MainFragmentListener,
DialogFragmentResetNetwork.DialogFragmentResetNetworkListener {

private static final String TAG = MainActivity.class.getSimpleName();
private static final String CURRENT_FRAGMENT = "CURRENT_FRAGMENT";

@Inject
DispatchingAndroidInjector<Fragment> mDispatchingAndroidInjector;

@Inject
ViewModelProvider.Factory mViewModelFactory;

@BindView(R.id.state_scanning)
View mScanningView;

private SharedViewModel mViewModel;
private BottomNavigationView mBottomNavigationView;

private NetworkFragment mNetworkFragment;
private ScannerFragment mScannerFragment;
private MainFragment mMainFragment;
private Fragment mSettingsFragment;

@Override
protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);

final Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setTitle(R.string.app_name);

mViewModel = ViewModelProviders.of(this, mViewModelFactory).get(SharedViewModel.class);

mNetworkFragment = (NetworkFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_network);
mScannerFragment = (ScannerFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_scanner);
mSettingsFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_settings);
mMainFragment = (MainFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_main);
mBottomNavigationView = findViewById(R.id.bottom_navigation_view);

mBottomNavigationView.setOnNavigationItemSelectedListener(this);
mBottomNavigationView.setOnNavigationItemReselectedListener(this);

mViewModel.getProvisionedNodesLiveData().observe(this, provisionedNodesLiveData -> {
invalidateOptionsMenu();
});

mViewModel.isConnected().observe(this, isConnected -> {
if(isConnected != null) {
invalidateOptionsMenu();
}
});

if(savedInstanceState == null) {
onNavigationItemSelected(mBottomNavigationView.getMenu().findItem(R.id.action_network));
} else {
mBottomNavigationView.setSelectedItemId(savedInstanceState.getInt(CURRENT_FRAGMENT));
}

}

@Override
public boolean onCreateOptionsMenu(final Menu menu) {
if(!mViewModel.getProvisionedNodesLiveData().getProvisionedNodes().isEmpty()){
if(mNetworkFragment.isVisible()) {
if (!mViewModel.isConenctedToMesh()) {
getMenuInflater().inflate(R.menu.connect, menu);
} else {
getMenuInflater().inflate(R.menu.disconnect, menu);
}
} else if(mSettingsFragment.isVisible()){
getMenuInflater().inflate(R.menu.reset_network, menu);
} else {
return false;
}
} else {
return false;
}
return true;
}

@Override
public boolean onOptionsItemSelected(final MenuItem item) {
final int id = item.getItemId();
switch (id) {
case R.id.action_connect:
final Intent scannerActivity = new Intent(this, ProvisionedNodesScannerActivity.class);
scannerActivity.putExtra(ProvisionedNodesScannerActivity.NETWORK_ID, mViewModel.getNetworkId());
startActivity(scannerActivity);
return true;
case R.id.action_disconnect:
mViewModel.disconnect();
return true;
case R.id.action_reset_network:
final DialogFragmentResetNetwork dialogFragmentResetNetwork = DialogFragmentResetNetwork.
newInstance(getString(R.string.title_reset_network), getString(R.string.message_reset_network));
dialogFragmentResetNetwork.show(getSupportFragmentManager(), null);
return true;
}
return false;
}

@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == Utils.PROVISIONING_SUCCESS){
if(resultCode == RESULT_OK){
final boolean result = data.getBooleanExtra("result", false);
if(result){
mBottomNavigationView.setSelectedItemId(R.id.action_network);
}
}
}
}

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
final int id = item.getItemId();
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
switch (id) {
case R.id.action_network:
ft.hide(mNetworkFragment).hide(mScannerFragment).hide(mSettingsFragment).show(mMainFragment);
break;
case R.id.action_scanner:
ft.hide(mNetworkFragment).hide(mScannerFragment).hide(mSettingsFragment).show(mMainFragment);
break;
case R.id.action_settings:
ft.hide(mNetworkFragment).hide(mScannerFragment).hide(mSettingsFragment).show(mMainFragment);
break;
}
ft.commit();
invalidateOptionsMenu();
return true;
}

@Override
public void onNavigationItemReselected(@NonNull MenuItem item) {
}

@Override
public void showProgressBar() {
mScanningView.setVisibility(View.INVISIBLE);
}

@Override
public void hideProgressBar() {
mScanningView.setVisibility(View.INVISIBLE);
}

@Override
public void onBackStackChanged() {

}

@Override
public AndroidInjector<Fragment> supportFragmentInjector() {
return mDispatchingAndroidInjector;
}

@Override
public void onProvisionedMeshNodeSelected() {

}

@Override
public void onNetworkReset() {
mViewModel.resetMeshNetwork();
} }

My source fragment which is inflated by MainActivity is MainFragment.java:

/**
* A simple {@link Fragment} subclass.
* Activities that contain this fragment must implement the
* {@link MainFragment.OnFragmentInteractionListener} interface
* to handle interaction events.
* Use the {@link MainFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class MainFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";

// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;

/*private OnFragmentInteractionListener mListener;*/
private MainFragmentListener mMainFragmentListener;

BleMeshManager instBleMeshManager;

@BindView(R.id.send) Button sendButton;
@BindView(R.id.mesh) Button meshButton;
private Unbinder unbinder;

@OnClick(R.id.send)
public void send() {
instBleMeshManager.sendPdu(new byte[] {0x01, 0x02, 0x03, 0x04});
}

@OnClick(R.id.mesh)
public void mesh() {
Intent meshActivityIntent = new Intent(getActivity(), MeshInteractionActivity.class);
startActivity(meshActivityIntent);
}

public MainFragment() {
// Required empty public constructor
}

/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment MainFragment.
*/
// TODO: Rename and change types and number of parameters
public static MainFragment newInstance(String param1, String param2) {
MainFragment fragment = new MainFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}

instBleMeshManager = new BleMeshManager(getActivity());

//onButtonPressed();

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_main, container, false);
ButterKnife.bind(this, view);

// Inflate the layout for this fragment
return view;
}

// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(/*Uri uri*/) {
if (mMainFragmentListener != null) {
mMainFragmentListener.hideProgressBar(/*uri*/);
}
}

@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof MainFragmentListener) {
mMainFragmentListener = (MainFragmentListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}

@Override
public void onDetach() {
super.onDetach();
mMainFragmentListener = null;
}

/*@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}*/

/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
/*public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(*//*Uri uri*//*);
}*/
public interface MainFragmentListener {
void showProgressBar();
void hideProgressBar();
}
}

My destination Activity to which an Intent in my fragment of MainActivity jumps to is MeshInteractionActivity:

public class MeshInteractionActivity extends AppCompatActivity implements Injectable, HasSupportFragmentInjector, BottomNavigationView.OnNavigationItemSelectedListener,
BottomNavigationView.OnNavigationItemReselectedListener,
ScannerFragment.ScannerFragmentListener, FragmentManager.OnBackStackChangedListener,
NetworkFragment.NetworkFragmentListener,
DialogFragmentResetNetwork.DialogFragmentResetNetworkListener {

private static final String TAG = MeshInteractionActivity.class.getSimpleName();
private static final String CURRENT_FRAGMENT = "CURRENT_FRAGMENT";

@Inject
DispatchingAndroidInjector<Fragment> mDispatchingAndroidInjector;

@Inject
ViewModelProvider.Factory mViewModelFactory;

@BindView(R.id.state_scanning)
View mScanningView;

private SharedViewModel mViewModel;
private BottomNavigationView mBottomNavigationView;

private NetworkFragment mNetworkFragment;
private ScannerFragment mScannerFragment;
private Fragment mSettingsFragment;

@Override
protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mesh_interaction);
ButterKnife.bind(this);

final Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setTitle(R.string.app_name);

mViewModel = ViewModelProviders.of(this, mViewModelFactory).get(SharedViewModel.class);

mNetworkFragment = (NetworkFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_network);
mScannerFragment = (ScannerFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_scanner);
mSettingsFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_settings);
mBottomNavigationView = findViewById(R.id.bottom_navigation_view);

mBottomNavigationView.setOnNavigationItemSelectedListener(this);
mBottomNavigationView.setOnNavigationItemReselectedListener(this);

mViewModel.getProvisionedNodesLiveData().observe(this, provisionedNodesLiveData -> {
invalidateOptionsMenu();
});

mViewModel.isConnected().observe(this, isConnected -> {
if(isConnected != null) {
invalidateOptionsMenu();
}
});

if(savedInstanceState == null) {
onNavigationItemSelected(mBottomNavigationView.getMenu().findItem(R.id.action_network));
} else {
mBottomNavigationView.setSelectedItemId(savedInstanceState.getInt(CURRENT_FRAGMENT));
}

}

@Override
public void onBackPressed() {
super.onBackPressed();
Intent mainActivityIntent = new Intent(MeshInteractionActivity.this, MainActivity.class);
startActivity(mainActivityIntent);

}

@Override
public boolean onCreateOptionsMenu(final Menu menu) {
if(!mViewModel.getProvisionedNodesLiveData().getProvisionedNodes().isEmpty()){
if(mNetworkFragment.isVisible()) {
if (!mViewModel.isConenctedToMesh()) {
getMenuInflater().inflate(R.menu.connect, menu);
} else {
getMenuInflater().inflate(R.menu.disconnect, menu);
}
} else if(mSettingsFragment.isVisible()){
getMenuInflater().inflate(R.menu.reset_network, menu);
} else {
return false;
}
} else {
return false;
}
return true;
}

@Override
public boolean onOptionsItemSelected(final MenuItem item) {
final int id = item.getItemId();
switch (id) {
case R.id.action_connect:
final Intent scannerActivity = new Intent(this, ProvisionedNodesScannerActivity.class);
scannerActivity.putExtra(ProvisionedNodesScannerActivity.NETWORK_ID, mViewModel.getNetworkId());
startActivity(scannerActivity);
return true;
case R.id.action_disconnect:
mViewModel.disconnect();
return true;
case R.id.action_reset_network:
final DialogFragmentResetNetwork dialogFragmentResetNetwork = DialogFragmentResetNetwork.
newInstance(getString(R.string.title_reset_network), getString(R.string.message_reset_network));
dialogFragmentResetNetwork.show(getSupportFragmentManager(), null);
return true;
}
return false;
}

@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == Utils.PROVISIONING_SUCCESS){
if(resultCode == RESULT_OK){
final boolean result = data.getBooleanExtra("result", false);
if(result){
mBottomNavigationView.setSelectedItemId(R.id.action_network);
}
}
}
}

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
final int id = item.getItemId();
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
switch (id) {
case R.id.action_network:
ft.show(mNetworkFragment).hide(mScannerFragment).hide(mSettingsFragment);
break;
case R.id.action_scanner:
ft.hide(mNetworkFragment).show(mScannerFragment).hide(mSettingsFragment);
break;
case R.id.action_settings:
ft.hide(mNetworkFragment).hide(mScannerFragment).show(mSettingsFragment);
break;
}
ft.commit();
invalidateOptionsMenu();
return true;
}

@Override
public void onNavigationItemReselected(@NonNull MenuItem item) {
}

@Override
public void showProgressBar() {
mScanningView.setVisibility(View.VISIBLE);
}

@Override
public void hideProgressBar() {
mScanningView.setVisibility(View.INVISIBLE);
}

@Override
public void onBackStackChanged() {

}

@Override
public AndroidInjector<Fragment> supportFragmentInjector() {
return mDispatchingAndroidInjector;
}

@Override
public void onProvisionedMeshNodeSelected() {

}

@Override
public void onNetworkReset() {
mViewModel.resetMeshNetwork();
}
}

This activity too, has its own fragments but I guess the problem is where the Intent from 1st Activity fragment jumps to 2nd Activity.

Thanks in advance.

Parents Reply Children
Related