在片段之间切换时如何处理相机?
Posted
技术标签:
【中文标题】在片段之间切换时如何处理相机?【英文标题】:How to handle camera while switching between fragments? 【发布时间】:2017-10-16 16:35:53 【问题描述】:我正在使用 2 个按钮在 2 个不同的片段之间切换。一个片段有一个相机视图并且第一次打开得很好,但是当从第二个片段再次返回到同一个片段时会出现一个空白屏幕。尽管相机硬件是免费的,但看不到相机预览。我没有使用 camera2 api,但需要解决这个错误。我添加了完整的代码和图像以寻求帮助。
MANifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.root.meeransunday" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"
android:screenOrientation="portrait"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<supports-screens android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"
android:anyDensity="true"
android:resizeable="true"/>
</application>
<activity android:name="meeranSunday"
android:configChanges="orientation|keyboardHidden"
/>
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.CAMERA">
</uses-permission>
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera" />
</manifest>
片段java类
public class scan extends Fragment implements ZXingScannerView.ResultHandler
private ZXingScannerView zXingScannerView;
private SurfaceView mySurfaceView;
private Camera mCamera;
private CameraPreview mPreview;
private String m_Text = "";
private String number = "";
private OnFragmentInteractionListener mListener;
public scan()
@Override
public void handleResult(Result rawResult)
// Do something with the result here
Log.e("handler", rawResult.getText()); // Prints scan results
Log.e("handler", rawResult.getBarcodeFormat().toString()); // Prints the scan format (qrcode)
// show the scanner result into dialog box.
AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity());
builder.setTitle("Scan Result");
builder.setMessage(rawResult.getText());
number = rawResult.getText().substring(rawResult.getText().length() - 13);
//
final EditText input = new EditText(this.getActivity());
// Specify the type of input expected; this, for example, sets the input as a password, and will mask the text
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
builder.setView(input);
// Set up the buttons
builder.setPositiveButton("OK", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
m_Text = input.getText().toString();
try
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(number, null, m_Text + " Transferred To Your Account From MTM Account", null, null);
catch (Exception e)
e.printStackTrace();
);
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
dialog.cancel();
);
builder.setNegativeButton("NO",
new DialogInterface.OnClickListener()
public void onClick(DialogInterface dialog, int which)
dialog.cancel();
);
//
AlertDialog alert1 = builder.create();
alert1.show();
// If you would like to resume scanning, call this method below:
zXingScannerView.resumeCameraPreview(this);
// TODO: Rename and change types and number of parameters
public static scan newInstance()
scan fragment = new scan();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
View view = inflater.inflate(R.layout.fragment_scan, container, false);
if (checkCameraHardware(getActivity().getApplicationContext()))
Toast.makeText(this.getActivity(), "camera hardware is free", Toast.LENGTH_SHORT).show();
zXingScannerView = new ZXingScannerView(this.getActivity().getApplicationContext());
zXingScannerView.setResultHandler(this);
zXingScannerView.startCamera(0);
else
Toast.makeText(this.getActivity(), "camera hardware is NOT free", Toast.LENGTH_SHORT).show();
FrameLayout preview = (FrameLayout) view.findViewById(R.id.camera_preview);
preview.addView(zXingScannerView);
return view;
@Override
public void onPause()
super.onPause();
try
mCamera = Camera.open();
catch (RuntimeException e)
Log.d("camera opening attempt:", e.getMessage());
finally
if (mCamera != null)
Log.d("camera opening attempt:", "yups ");
mCamera.release();
zXingScannerView.stopCamera();
zXingScannerView.stopCameraPreview();
@Override
public void onResume()
super.onResume();
zXingScannerView.setResultHandler(this); // Register ourselves as a handler for scan results.
zXingScannerView.startCamera(0); // Start camera on resume
public boolean checkCameraHardware(Context context)
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA))
return true;
else
return false;
public void onButtonPressed(Uri uri)
if (mListener != null)
mListener.onFragmentInteraction(uri);
@Override
public void onAttach(Context context)
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener)
mListener = (OnFragmentInteractionListener) context;
else
throw new RuntimeException(context.toString() +
" must implement OnFragmentInteractionListener");
@Override
public void onDetach()
Log.d("aa", "sdsdssdsddssssd");
try
mCamera = Camera.open();
catch (RuntimeException e)
Log.d("camera opening attempt:", e.getMessage());
finally
if (mCamera != null)
mCamera.release();
zXingScannerView.stopCamera();
zXingScannerView.stopCameraPreview();
super.onDetach();
mListener = null;
public interface OnFragmentInteractionListener
// TODO: Update argument type and name\
void onFragmentInteraction(Uri uri);
MAinactivity
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener
public int check = 0;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
message frags = new message();
fragmentTransaction.add(R.id.content_main, frags, "text");
fragmentTransaction.commit();
check += 1;
public void message(View v)
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
message sms = new message();
fragmentTransaction.replace(R.id.content_main, sms, "text");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
public void scan(View v)
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
scan scan = new scan();
fragmentTransaction.replace(R.id.content_main, scan, "scan");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
public void loadooncreate()
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
message frags = new message();
fragmentTransaction.add(R.id.content_main, frags, "text");
fragmentTransaction.commit();
check += 1;
@Override
public boolean onCreateOptionsMenu(Menu menu)
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
Toolbar toolbar2 = (Toolbar) findViewById(R.id.toolbar1);
toolbar2.inflateMenu(R.menu.notify);
toolbar2.getMenu().findItem(R.id.notifications).setIcon(buildCounterDrawable(2, R.drawable.notification));
toolbar2.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener()
@Override
public boolean onMenuItemClick(MenuItem arg0)
if (arg0.getItemId() == R.id.notifications)
arg0.setIcon(buildCounterDrawable(0, R.drawable.notification));
((RelativeLayout) findViewById(R.id.content_main)).removeAllViews();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
BlankFragment frag = new BlankFragment();
fragmentTransaction.add(R.id.content_main, frag, "first");
fragmentTransaction.commit();
return false;
);
check = 1;
return true;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
if (keyCode == KeyEvent.KEYCODE_BACK)
//code to reset view
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (fragmentManager.findFragmentByTag("first") != null)
fragmentTransaction.remove(fragmentManager.findFragmentByTag("first"));
fragmentTransaction.commit();
loadooncreate();
else
finish();
return true;
return super.onKeyDown(keyCode, event);
private Drawable buildCounterDrawable(int count, int backgroundImageId)
LayoutInflater inflater = LayoutInflater.from(this);
View view = inflater.inflate(R.layout.counter_menuitem_layout, null);
view.setBackgroundResource(backgroundImageId);
if (count == 0)
View counterTextPanel = view.findViewById(R.id.counterValuePanel);
counterTextPanel.setVisibility(View.GONE);
else
// TextView textView = (TextView) view.findViewById(count);
// textView.setText("1");
view.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
view.setDrawingCacheEnabled(true);
view.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
return new BitmapDrawable(getResources(), bitmap);
@Override
public boolean onPrepareOptionsMenu(Menu menu)
if (check > 3)
Toast.makeText(this.getApplicationContext(), "sdsdsdfdsfsd", Toast.LENGTH_SHORT).show();
MenuItem item = menu.getItem(R.id.notifications);
item.setIcon(buildCounterDrawable(2, R.drawable.notification));
//MenuItem item = (MenuItem)findViewById(R.id.notifications);
// item.setIcon(buildCounterDrawable(2, R.drawable.notification));
return true;
@Override
public boolean onOptionsItemSelected(MenuItem item)
if (item.getItemId() == R.id.Home)
//close current fragment;
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (fragmentManager.findFragmentByTag("first") != null)
fragmentTransaction.remove(fragmentManager.findFragmentByTag("first"));
fragmentTransaction.commit();
loadooncreate();
return super.onOptionsItemSelected(item);
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item)
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camera)
// Handle the camera action
else if (id == R.id.nav_gallery)
else if (id == R.id.nav_slideshow)
else if (id == R.id.nav_manage)
else if (id == R.id.nav_share)
else if (id == R.id.nav_send)
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
最后一个堆栈错误
W/MessageQueue: Handler (android.hardware.Camera$EventHandler) 428e2000 sending message to a Handler on a dead thread
java.lang.RuntimeException: Handler (android.hardware.Camera$EventHandler) 428e2000 sending message to a Handler on a dead thread
at android.os.MessageQueue.enqueueMessage(MessageQueue.java:294)
at android.os.Handler.sendMessageAtTime(Handler.java:473)
at android.os.Handler.sendMessageDelayed(Handler.java:446)
at android.os.Handler.sendMessage(Handler.java:383)
at android.hardware.Camera.postEventFromNative(Camera.java:852)
at dalvik.system.NativeStart.run(Native Method)
【问题讨论】:
为什么要在 detach() 中再次打开相机? .这个问题可能是因为你没有正确释放相机。 如何以及在何处准确释放相机??加上分离没有被调用,因为我正在替换片段。不删除。 另外我正在打开检查相机是否免费?我终于在释放相机但问题是分离在哪里调用?它不叫 sunil。 相机必须在 onPause 中释放并在 onResume 中重新开始。我认为 zXingScannerView 是您的 cameraView,它可以正确处理大多数情况。我不知道您为什么要创建另一个 mCamera 对象。 现在看看我的暂停代码...广告仍然是完全相同的问题:(@sunil Sunny 【参考方案1】:你可以试试这个,删除onAttach
和onDetach
。还要在 onCreate 中替换这段代码
if (checkCameraHardware(getActivity().getApplicationContext()))
Toast.makeText(this.getActivity(), "camera hardware is free", Toast.LENGTH_SHORT).show();
zXingScannerView = new ZXingScannerView(this.getActivity().getApplicationContext());
zXingScannerView.setResultHandler(this);
zXingScannerView.startCamera(0);
else
Toast.makeText(this.getActivity(), "camera hardware is NOT free", Toast.LENGTH_SHORT).show();
有了这个。
zXingScannerView = new ZXingScannerView(this.getActivity().getApplicationContext());
然后像这样更改 onPause 和 onResume。
@Override
public void onPause()
super.onPause();
if (zXingScannerView != null)
zXingScannerView.stopCamera();
zXingScannerView.stopCameraPreview();
@Override
public void onResume()
super.onResume();
if (checkCameraHardware(getActivity().getApplicationContext()))
Toast.makeText(this.getActivity(), "camera hardware is free", Toast.LENGTH_SHORT).show();
zXingScannerView.setResultHandler(this); // Register ourselves as a
zXingScannerView.startCamera(0); // Start camera on resume
同时删除所有这些对象
private SurfaceView mySurfaceView;
private Camera mCamera;
private CameraPreview mPreview;
不需要它们,它在您的 zXingScannerView 中。
【讨论】:
【参考方案2】:实际上,当切换到其他片段时,您并没有释放对象,首先释放 onPause() 方法中的所有对象,然后 onResume() 重新连接相机。试试这个:
@Override
public void onResume()
super.onResume();
if (zXingScannerView!= null)
zXingScannerView.stopCameraPreview();
zXingScannerView.resumeCameraPreview(this);
【讨论】:
以上是关于在片段之间切换时如何处理相机?的主要内容,如果未能解决你的问题,请参考以下文章
在 monorepo 中的多个应用程序之间共享组件时如何处理共享依赖项