我正在开发一个用于打开/关闭手机摄像头的小部件。
我制作了一个可以像切换按钮一样工作的小部件(开/关)。
行为如下:当我启用小部件时,有时候led灯仍然亮着。 但它不会打开/关闭相机,但它会改变图标。
我无法弄清楚实际问题是什么。
在Activity(火炬之光应用程序)中也能正常工作。
任何人都可以解释我如何解决我的问题?
我哪里出错了?
你可以查看我到目前为止所做的代码
onUpdate
方法
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
//super.onUpdate(context, appWidgetManager, appWidgetIds);
remoteViews = new RemoteViews( context.getPackageName(), R.layout.widgetlayout);
watchWidget = new ComponentName( context, FlashLightWidget.class );
Intent intentClick = new Intent(context,FlashLightWidget.class);
intentClick.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, ""+appWidgetIds[0]);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetIds[0],intentClick, 0);
remoteViews.setOnClickPendingIntent(R.id.myToggleWidget, pendingIntent);
appWidgetManager.updateAppWidget( watchWidget, remoteViews );
ctx=context;
}
onReceive
方法如下:
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
remoteViews = new RemoteViews( context.getPackageName(), R.layout.widgetlayout);
if (intent.getAction()==null) {
Bundle extras = intent.getExtras();
if(extras!=null) {
if(status)
{
status=false;
remoteViews.setImageViewResource(R.id.myToggleWidget, R.drawable.shutdown1);
processOnClick();
Toast.makeText(context,"Status==false-onclick",Toast.LENGTH_SHORT).show();
}
else
{
status = true;
remoteViews.setImageViewResource(R.id.myToggleWidget, R.drawable.shutdown2);
processOffClick();
Toast.makeText(context,"Status==true--Ofclick",Toast.LENGTH_SHORT).show();
}
}
watchWidget = new ComponentName( context, FlashLightWidget.class );
(AppWidgetManager.getInstance(context)).updateAppWidget( watchWidget, remoteViews );
}
}
}
processOffClick
方法
private void processOffClick() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
processOnClick
方法
private void processOnClick() {
if(mCamera==null)
{
try {
mCamera = Camera.open();
} catch (Exception e) {
e.printStackTrace();
}
}
if (mCamera != null) {
Parameters params = mCamera.getParameters();
List<String> flashModes = params.getSupportedFlashModes();
if (flashModes == null) {
return;
} else {
params.setFlashMode(Parameters.FLASH_MODE_OFF);
mCamera.setParameters(params);
mCamera.startPreview();
String flashMode = params.getFlashMode();
if (!Parameters.FLASH_MODE_TORCH.equals(flashMode)) {
if (flashModes.contains(Parameters.FLASH_MODE_TORCH)) {
params.setFlashMode(Parameters.FLASH_MODE_TORCH);
mCamera.setParameters(params);
}
}
}
} else if (mCamera == null) {
//Toast.makeText(ctx, "Camera not found", Toast.LENGTH_LONG).show();
return;
}
}
答案 0 :(得分:40)
经过很长一段时间,我可以自由地解决这个问题。
这就是我所做的。
FlashlightWidgetProvider
上课:
public class FlashlightWidgetProvider extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
Intent receiver = new Intent(context, FlashlightWidgetReceiver.class);
receiver.setAction("COM_FLASHLIGHT");
receiver.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, receiver, 0);
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.widget_layout);
views.setOnClickPendingIntent(R.id.button, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, views);
}
}
和BroadcastReceiver for FlashlightWidgetReceiver:
public class FlashlightWidgetReceiver extends BroadcastReceiver {
private static boolean isLightOn = false;
private static Camera camera;
@Override
public void onReceive(Context context, Intent intent) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
if(isLightOn) {
views.setImageViewResource(R.id.button, R.drawable.off);
} else {
views.setImageViewResource(R.id.button, R.drawable.on);
}
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
appWidgetManager.updateAppWidget(new ComponentName(context, FlashlightWidgetProvider.class),
views);
if (isLightOn) {
if (camera != null) {
camera.stopPreview();
camera.release();
camera = null;
isLightOn = false;
}
} else {
// Open the default i.e. the first rear facing camera.
camera = Camera.open();
if(camera == null) {
Toast.makeText(context, R.string.no_camera, Toast.LENGTH_SHORT).show();
} else {
// Set the torch flash mode
Parameters param = camera.getParameters();
param.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
try {
camera.setParameters(param);
camera.startPreview();
isLightOn = true;
} catch (Exception e) {
Toast.makeText(context, R.string.no_flash, Toast.LENGTH_SHORT).show();
}
}
}
}
}
Manifest.xml
文件中所需的权限:
<uses-permission android:name="android.permission.CAMERA"></uses-permission>
还在Manifest.xml
文件中注册接收者:
<receiver android:name=".FlashlightWidgetProvider" android:icon="@drawable/on" android:label="@string/app_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/flashlight_appwidget_info" />
</receiver>
<receiver android:name="FlashlightWidgetReceiver">
<intent-filter>
<action android:name="COM_FLASHLIGHT"></action>
</intent-filter>
</receiver>
重要提示:如果您的手机支持FLASH_MODE_TORCH
,此代码非常有用。
我已经在三星Galaxy Ace 2.2.1&amp; 2.3.3。代码无效,因为该设备没有FLASH_MODE_TORCH。
在HTC Salsa,Wildfire中工作良好..
如果有人可以在这里测试和发布结果,那将是最好的。
答案 1 :(得分:6)
处理RemoteViews
点击的最佳技术是创建一个调用服务的PendingIntent
,并在服务中执行您想要的“内容”,包括您的小部件的任何其他RemoteViews
更新。您可以在意图附加内容中发送相关数据。该服务最后调用stopSelf()
,因此它会关闭。
您无法维持BroadcastReceiver
中的任何状态;系统在任何可用线程上运行那些,并且在调用onReceive()
后不保留对您的实例的任何引用。您mCamera
的调用之间无法保证BroadcastReceiver
变量。
如果您确实需要维护状态,则必须在服务中执行此操作,并且不要使用stopSelf()
(直到适当的时间)。
您不需要UI线程来使用Camera
类,除非您正在进行图像预览,这需要SurfaceHolder
(并暗示UI)。但是,您必须激活一个事件循环,否则Camera
将不会向您发回回调,这是一个问题,因为Camera
主要是异步的。您可以在服务中执行此操作(请参阅HandlerThread
)并保持服务正常运行,直到release()
所有内容为止。无论哪个线程调用Camera.open()
都会收到回调。
每个人都真的阅读了关于App Widgets的部分吗? http://developer.android.com/guide/topics/appwidgets/index.html
使用AppWidgetProvider类部分说明了我在这里所说的内容。
答案 2 :(得分:2)
我有类似的情况,我需要在UI线程上运行某些Android代码...这只在一个Activity中可用。我的解决方案 - 具有完全透明布局的活动。因此,当您完成操作时,您只能看到主屏幕(尽管没有响应),在您的情况下应该非常快。
答案 3 :(得分:1)
我有一个不太好但有效的解决方案。让小部件调用一个Activity,并在Activity中打开flash,然后关闭Activity。同样关掉它。如果这在Activity中有效,则此解决方案将起作用。它不优雅但有效。我试过了。