【问题标题】:Widget for turning on/off camera flashlight in android用于在android中打开/关闭相机手电筒的小部件
【发布时间】:2011-11-22 20:08:04
【问题描述】:

我正在开发一个用于打开/关闭手机摄像头的小部件。

我制作了一个可以像切换按钮(开/关)一样工作的小部件。

行为如下:当我启用小部件时,有时 LED 灯仍然亮着。 但它不会打开/关闭摄像头指示灯,但会更改图标。

我无法弄清楚实际问题是什么。

同样的事情在 Activity(Torch Light 应用程序)中也能正常工作。

谁能解释一下我该如何解决我的问题?

我哪里出错了?

你可以看看下面我到目前为止所做的代码

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;
    }
}

【问题讨论】:

  • 请参考这篇文章以获得有效的解决方案:stackoverflow.com/questions/3878294/…
  • @HandlerExploit :这对我没有帮助,伙计。我之前已经多次引用过它。我要问的是完全不同的。
  • 如果我正在阅读您正在正确执行的操作...您似乎正在尝试从应用小部件提供商控制 LED,这是正确的吗?如果是这样,您需要提取该代码并将其放入自己的类中,然后从您的应用小部件提供程序调用该类
  • @DDoSAttack:是的,你是对的。我正在尝试控制来自应用小部件提供商的 LED。但我认为我在 AppWidgetProvider 中实现了错误的东西。我认为在 onReceive 方法中处理点击事件是不合适的!
  • 没错。 AppWidgetProvider 的功能非常有限。您可以通过 RemoteViews developer.android.com/reference/android/widget/RemoteViews.html 访问布局小部件,因此我建议创建一个单独的类来处理所有 AppWidget UI 更新...这是我今天发布的一个简单示例:stackoverflow.com/questions/7560265/…

标签: android android-widget widget android-camera android-appwidget


【解决方案1】:

过了好久,终于有空来解决这个问题了。

这就是我所做的。

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);

        }
}

和 FlashlightWidgetReceiver 的 BroadcastReceiver :

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 和 2.3.3 中进行了测试。代码不工作,因为该设备没有 FLASH_MODE_TORCH。

在 HTC Salsa、Wildfire 中运行良好..

如果有人可以在这里测试并发布结果,那将是最好的。

【讨论】:

  • 这也有助于检查闪存是否打开,只需执行以下操作:String x = params.getFlashMode();... 如果 x 是 torch 那么它是 on 如果 x 是 off 那么它是 @987654333 @.
  • 小部件在几个小时后停止工作.. 或者如果我更改日期立即停止工作。你能帮我解决这个问题吗?
【解决方案2】:

处理来自RemoteViews 的点击的最佳技术是创建一个调用服务的PendingIntent,并在服务中执行您想要的“东西”,包括任何额外的@987654324 @ 为您的小部件更新。您可以在 Intent Extras 中发送相关数据。服务最后会调用stopSelf(),所以它会关闭。

您不能在BroadcastReceiver 中维护任何状态;系统在任何可用线程上运行它们,并且在调用onReceive() 后不维护对您的实例的任何引用。您的mCamera 变量不能保证在您的BroadcastReceiver 调用之间保持不变。

如果你真的需要维护状态,你必须在服务中进行,并且不要使用stopSelf()(直到适当的时间)。

您不需要 UI 线程来使用 Camera 类,除非您正在执行图像预览,这需要 SurfaceHolder(并暗示 UI)。但是,您必须激活事件循环,否则Camera 不会向您发布回调,这是一个问题,因为Camera 主要是异步的。您可以在服务中执行此操作(请参阅HandlerThread)并保持您的服务运行,直到需要release() 一切。无论哪个线程调用Camera.open(),都会收到回调。

是否每个人都真正阅读了关于应用小部件的部分? http://developer.android.com/guide/topics/appwidgets/index.html

使用 AppWidgetProvider 类部分说明了我在这里所说的内容。

【讨论】:

    【解决方案3】:

    我遇到过类似的情况,我需要在 UI 线程上运行某些 android 代码……这仅在 Activity 中可用。我的解决方案 - 具有完全透明布局的活动。因此,您在完成操作时只会看到主屏幕(尽管没有响应),在您的情况下应该很快。

    【讨论】:

    • 您解释的内容与上述答案相同。我不想执行这样的任务。有没有合适的解决办法?
    • 我想你误会了。你试图做的事情是行不通的。 Widget 的上下文的生命周期非常短,所以我相信您的代码可能会在中途被杀死。您可以在 Widget 的上下文中实际执行的操作很少。其他一切都必须由 Intent 触发。
    【解决方案4】:

    我有一个不是很好但有效的解决方案。让小部件调用一个 Activity,然后在 Activity 中打开闪光灯,然后关闭 Activity。关掉也是一样。如果这在活动中有效,那么此解决方案将有效。它不优雅但有效。我试过了。

    【讨论】:

    • 感谢您的回答。但我不想以这种方式拥有小部件。
    • 看我上面的回答!这就是应用小部件系统的用途。我已经编写了很多小部件,所有这些小部件都以这种方式工作。你越早接受它,你就能越早完成!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-26
    相关资源
    最近更新 更多