我对Android有一定的了解,但是我对Fragments,Injection,Binding,ButterKnife等不熟悉。我已经看过一些视频和教程,但无法发现问题所在。
我想做什么:
我从GitHub存储库中获得了此活动和代码( MeshInteractionActivity.java )。我要创建另一个活动 MainActivity.java ,并在按下按钮时连接到此“网格活动”。我认为从MainActivity到MeshInteractionActivity做一个Intent会很简单。但这没有用。我觉得可能需要在MainActivity上添加一个片段,用于第二个活动,因此我创建了 MainFragment.java 。我在MainFragment上得到了2个按钮,但是当我按下网格按钮(即 MainFragment 中的mesh()
方法)时,应用程序崩溃了。
我尝试学习ButterKnife并看了一些视频,但是它们太基础了,我不知道它们如何适合我的用例。由于我的代码包含以下部分:
@Inject
DispatchingAndroidInjector<Fragment> mDispatchingAndroidInjector;
@Inject
ViewModelProvider.Factory mViewModelFactory;
我还不了解的东西。
我收到的错误:
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)
我的源活动是 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();
} }
由 MainActivity 夸大的源片段是 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();
}
}
MainActivity的Intent跳转到的我的目标Activity是 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();
}
}
该活动也有自己的片段,但我想问题是从第一个活动片段的意图跳到了第二个活动。
谢谢。