Fehler bei Service,welcher Camera API nutzt

  • Antworten:15
anamollo
  • Forum-Beiträge: 24

31.01.2014, 17:36:21 via Website

Hallo zusammen.

Ich schreibe derzeit eine App, die folgendes machen soll:

Wenn das Entsperrmuster des Smartphones korrekt eingegeben wird, soll ein Service ein Foto machen und dieses auf der SD-Karte speichern.

Somit habe ich derzeit 4 Javadateien:
- MainActivity: beinhaltet die "sichtbare" Activity, in der der Benutzer die Funktion über einen Start und Stop-Button generell scharfschalten kann.
- photo_service: beinhaltet die Instanziierung eines IntentFilters und des Broadcastreceivers, sobald Service gestartet werden soll
- PhotoHandler: beinhaltet alles, was zum Speichern des gecaptureten Fotos notwendig ist (basierend auf Vogellas Erklärung zur Camera API)
- receiverScreen: BroadcastReceiver: soll die "Entsperraktion" erkennen und entsprechend ein Foto auslösen.

Im Android-Virtual-Device hat alles einwandfrei geklappt.
Möchte ich das Ganze aber auf meinem Galaxy SIII mini ausprobieren, bekomme ich immer den Fehler "IntentReceiverLeaked...are you missing a call to unregisterReceiver()". Woran liegt das?
Vorallem: warum gehts auf dem Emulator und in echt nicht?


Hier nun der Code von MainActivity:
1package com.jk.unlock;
2
3
4
5
6import android.os.Bundle;
7import android.app.Activity;
8import android.content.Intent;
9import android.view.Menu;
10import android.view.View;
11import android.widget.Button;
12
13
14
15public class MainActivity extends Activity
16{
17 @Override
18 protected void onCreate(Bundle savedInstanceState)
19 {
20 super.onCreate(savedInstanceState);
21 setContentView(R.layout.activity_main);
22
23 Button buttonStart= (Button)findViewById(R.id.btn_start);
24 Button buttonStop = (Button)findViewById(R.id.btn_stop);
25
26 buttonStart.setOnClickListener(btnStart);
27 buttonStop.setOnClickListener(btnStop);
28 }
29
30
31
32
33 //Intent serviceIntent = new Intent(MainActivity.this, photo_service.class);
34
35 Button.OnClickListener btnStart = new Button.OnClickListener() //
36 {
37 @Override
38 public void onClick(View v)
39 {/*
40 Intent serviceIntent = new Intent(getApplicationContext(), photo_service.class);
41 startService(serviceIntent);
42 */
43 startService(new Intent(getBaseContext(), photo_service.class));
44
45 }
46 };
47
48
49
50 Button.OnClickListener btnStop = new Button.OnClickListener() //
51 {
52 @Override
53 public void onClick(View v)
54 {
55
56 Intent serviceIntent = new Intent(getApplicationContext(), photo_service.class);
57 stopService(serviceIntent);
58 }
59 };
60
61
62
63 @Override
64 public boolean onCreateOptionsMenu(Menu menu)
65 {
66 // Inflate the menu; this adds items to the action bar if it is present.
67 getMenuInflater().inflate(R.menu.main, menu);
68 return true;
69 }
70
71}

Hier von photo_service:

1package com.jk.unlock;
2
3import android.app.Activity;
4import android.app.Activity;
5import android.content.pm.PackageManager;
6import android.hardware.Camera;
7import android.hardware.Camera.CameraInfo;
8import android.os.Bundle;
9import android.util.Log;
10import android.view.View;
11import android.widget.Toast;
12import android.app.Service;
13import android.content.BroadcastReceiver;
14import android.content.Intent;
15import android.content.IntentFilter;
16import android.os.IBinder;
17import android.widget.Toast;
18
19public class photo_service extends Service
20{
21 BroadcastReceiver mReceiver;
22 private final static String DEBUG_TAG = "MakePhotoActivity";
23 private Camera camera;
24 private int cameraId = 0;
25
26 @Override
27 public int onStartCommand(Intent intent, int flags, int startId) // Nach Start des Services...
28 {
29 try
30 {
31 IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON); // Instanz von "Intentfilter" anlegen
32 filter.addAction(Intent.ACTION_SCREEN_OFF);
33 filter.addAction(Intent.ACTION_USER_PRESENT);
34 mReceiver = new receiverScreen(); // Screenreceiver instanziieren -> überwacht das Geschehen des Users auf dem Screen
35 registerReceiver(mReceiver, filter);
36
37 }
38
39 catch (Exception e)
40 {
41
42 }
43
44 return Service.START_STICKY; // erst bei explizitem Beenden den Service abschließen
45 }
46
47
48 private int findFrontFacingCamera()
49 {
50 int cameraId = -1;
51 // Search for the front facing camera
52 int numberOfCameras = Camera.getNumberOfCameras();
53 for (int i = 0; i < numberOfCameras; i++) //counts the quantity of the available cameras
54 {
55 CameraInfo info = new CameraInfo();
56 Camera.getCameraInfo(i, info);
57
58 Toast.makeText(this, Integer.toString(numberOfCameras), Toast.LENGTH_LONG).show();
59 if (info.facing == CameraInfo.CAMERA_FACING_FRONT)
60 {
61 Log.d(DEBUG_TAG, "Camera found");
62 cameraId = i;
63 break;
64 }
65 }
66
67 return cameraId;
68 }
69
70
71 protected void onPause()
72 {
73 if (camera != null)
74 {
75 camera.release();
76 camera = null;
77 }
78 onPause();
79 }
80
81
82
83
84
85
86
87
88
89 @Override
90 public void onDestroy()
91 {
92 super.onDestroy();
93 super.unregisterReceiver(mReceiver);
94 Toast.makeText(this,"Service stopped",Toast.LENGTH_LONG).show();
95 }
96
97
98
99 @Override
100 public IBinder onBind(Intent intent)
101 {
102 //TODO for communication return IBinder implementation
103 return null;
104 }
105}


...hier von PhotoHandler:

1package com.jk.unlock;
2
3import java.io.File;
4import java.io.FileOutputStream;
5import java.text.SimpleDateFormat;
6import java.util.Date;
7
8import android.content.Context;
9import android.hardware.Camera;
10import android.hardware.Camera.PictureCallback;
11import android.os.Environment;
12import android.util.Log;
13import android.widget.Toast;
14
15public class PhotoHandler implements PictureCallback
16{
17
18 private final Context context;
19
20 public PhotoHandler(Context context)
21 {
22 this.context = context;
23 }
24
25 @Override
26 public void onPictureTaken(byte[] data, Camera camera) // after the picture was captured...
27 {
28 File pictureFileDir = getDir();
29 if (!pictureFileDir.exists() && !pictureFileDir.mkdirs())
30 {
31 //Toast.makeText(context, "Can't create directory to save image.",Toast.LENGTH_LONG).show();
32 return;
33
34 }
35
36 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmss"); // name the captured picture like the current date
37 String date = dateFormat.format(new Date());
38 String photoFile = "Picture_" + date + ".jpg";
39
40 String filename = pictureFileDir.getPath() + File.separator + photoFile; // get path of image-directory
41
42 File pictureFile = new File(filename);
43
44 try
45 {
46 FileOutputStream fos = new FileOutputStream(pictureFile); // try to save it
47 fos.write(data);
48 fos.close();
49 Toast.makeText(context, "New Image saved:" + photoFile,Toast.LENGTH_LONG).show(); // should be commented ;-)
50 }
51
52 catch (Exception error)
53 {
54
55 // Toast.makeText(context, "Image could not be saved.",Toast.LENGTH_LONG).show(); // should be commented ;-)
56 }
57 }
58
59 private File getDir() // returns the current directory to the external storage device
60 {
61 File sdDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
62 return new File(sdDir, "Unlock_pics"); // Directory, where the captured pictures will be stored
63 }
64}


und letztlich von receiverScreen (BroadcastReceiver):
1package com.jk.unlock;
2
3
4import android.content.BroadcastReceiver;
5import android.content.Context;
6import android.content.Intent;
7import android.content.pm.PackageManager;
8import android.hardware.Camera;
9import android.hardware.Camera.CameraInfo;
10import android.util.Log;
11import android.widget.Toast;
12
13public class receiverScreen extends BroadcastReceiver
14{
15 private Camera camera;
16 private int cameraId=0;
17 @Override
18 public void onReceive(Context context, Intent intent)
19 {
20
21 if (intent.getAction().equals(Intent.ACTION_SCREEN_ON))
22 {
23
24 }
25
26 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
27 {
28
29 }
30
31 if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)) // wenn Benutzer Screen entsperrt...
32 {
33
34 cameraId = findFrontFacingCamera();
35 if (cameraId < 0)
36 {
37 Toast.makeText(context, "No front facing camera found.",Toast.LENGTH_LONG).show();
38 }
39
40 else
41 {
42 camera = Camera.open(cameraId);
43 Toast.makeText(context, "KLACK!",Toast.LENGTH_LONG).show();
44
45 camera.takePicture(null, null, new PhotoHandler(context));
46 camera.release();
47 }
48 }
49
50 }
51
52
53
54
55
56private int findFrontFacingCamera()
57{
58 int cameraId = -1;
59 // Search for the front facing camera
60 int numberOfCameras = Camera.getNumberOfCameras();
61 for (int i = 0; i < numberOfCameras; i++) //counts the quantity of the available cameras
62 {
63 CameraInfo info = new CameraInfo();
64 Camera.getCameraInfo(i, info);
65
66
67 if (info.facing == CameraInfo.CAMERA_FACING_FRONT)
68 {
69
70 cameraId = i;
71 break;
72 }
73 }
74
75 return cameraId;
76}
77
78}


Vielen Dank schonmal für euere Hilfe!


Gruß
Joh

Antworten
impjor
  • Forum-Beiträge: 1.793

31.01.2014, 19:25:10 via Website

1. Bitte entferne Code, den du auskommentiert hast, aus deinem Posting
2. Der Service ist ein bisschen sinnlos... Der läuft die ganze Zeit, nur um den BroadcastReceiver zu starten/stoppen?
3. Warum leere if-Struckturen?

Ich würde das ganze so angehen:
1. Broadcastreceiver im AndroidManifest.xml eintragen und dort direkt den intent-filter hinzufügen
2. Den Service komplett weglassen
3. Dann den BroadcastReceiver direkt deaktivieren/aktivieren, wenn nötig (siehe z.B. hier)

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
anamollo
  • Forum-Beiträge: 24

01.02.2014, 18:23:44 via Website

Ok, danke erstmal.

Ich werde die Kommentare hier entfernen.

Was mich eben wundert ist, dass es ja auf dem Emulator funktioniert. Nur nicht auf dem "echten" Galaxy S III mini.
Was sagt die Fehlermeldung ""IntentReceiverLeaked...are you missing a call to unregisterReceiver()?"

So "falsch" kann das Ganze ja nicht sein, wenn es unter der Emulation läuft..


Danke und Gruß
Johannes

— geändert am 01.02.2014, 18:27:10

Antworten
impjor
  • Forum-Beiträge: 1.793

02.02.2014, 00:24:37 via App

Nun, nur weil ein Code funktioniert ist er noch lange nicht gut.
Scheinbar rufst du registerReceiver auf, obwohl der Broadcastreceiver schon registriert ist.

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
anamollo
  • Forum-Beiträge: 24

03.02.2014, 10:00:51 via Website

Hallo!

Das registerReceiver(mReceiver, filter); wird aber auch nur einmal ausgeführt. Wie kann es sein, dass bereits vorher der Receiver registriert ist?

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

03.02.2014, 16:52:14 via Website

ist er in der Manifest Registriert?
Dann ist es klar warum er früher ausgeführt wird.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
anamollo
  • Forum-Beiträge: 24

03.02.2014, 17:10:20 via Website

Nein ist er nicht.

Hier das Manifest:

1<?xml version="1.0" encoding="utf-8"?>
2<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 package="com.jk.unlock"
4 android:versionCode="1"
5 android:versionName="1.0" >
6
7
8 <uses-permission android:name="android.permission.CAMERA" />
9 <uses-feature android:name="android.hardware.camera" />
10 <uses-feature android:name="android.hardware.camera.front" android:required="true" />
11 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
12
13
14 <uses-sdk
15 android:minSdkVersion="15" />
16
17 <application
18 android:allowBackup="true"
19 android:icon="@drawable/ic_launcher"
20 android:label="@string/app_name"
21 android:theme="@style/AppTheme" >
22
23
24
25
26 <activity
27 android:name="com.jk.unlock.MainActivity"
28 android:label="@string/app_name" >
29 <intent-filter>
30 <action android:name="android.intent.action.MAIN" />
31
32 <category android:name="android.intent.category.LAUNCHER" />
33 </intent-filter>
34
35
36
37
38 </activity>
39 <service android:name="photo_service"></service>
40
41
42 </application>
43
44</manifest>

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

03.02.2014, 17:14:05 via Website

Aber der Service und dieser Startet den Receiver..

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
anamollo
  • Forum-Beiträge: 24

03.02.2014, 19:02:47 via Website

Hallo nochmal.

Ich habe jetzt wie man mir sagte den Service gänzlich weggelassen.


Nun sieht meine MainActivity so aus:

1package com.jk.unlock;
2
3
4import android.os.Bundle;
5import android.app.Activity;
6import android.content.BroadcastReceiver;
7import android.content.Intent;
8import android.content.IntentFilter;
9import android.view.Menu;
10import android.view.View;
11import android.widget.Button;
12
13
14
15public class MainActivity extends Activity
16{
17 BroadcastReceiver mReceiver;
18
19 @Override
20 protected void onCreate(Bundle savedInstanceState)
21 {
22 super.onCreate(savedInstanceState);
23 setContentView(R.layout.activity_main);
24
25 Button buttonStart= (Button)findViewById(R.id.btn_start);
26 Button buttonStop = (Button)findViewById(R.id.btn_stop);
27
28 buttonStart.setOnClickListener(btnStart);
29 buttonStop.setOnClickListener(btnStop);
30 }
31
32
33 Button.OnClickListener btnStart = new Button.OnClickListener()
34 {
35 @Override
36 public void onClick(View v)
37 {
38 IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
39 mReceiver = new receiverScreen();
40 registerReceiver(mReceiver, filter);
41 }
42 };
43
44
45
46 Button.OnClickListener btnStop = new Button.OnClickListener()
47 {
48 @Override
49 public void onClick(View v)
50 {
51 //unregisterReceiver(mReceiver);
52
53 }
54 };
55
56@Override
57 protected void onDestroy()
58 {
59 super.onPause();
60 unregisterReceiver(mReceiver);
61 }
62
63}



und mein Receiver so:

1package com.jk.unlock;
2
3
4
5
6import android.content.BroadcastReceiver;
7import android.content.Context;
8import android.content.Intent;
9import android.content.pm.PackageManager;
10import android.hardware.Camera;
11import android.hardware.Camera.CameraInfo;
12import android.util.Log;
13import android.widget.Toast;
14
15public class receiverScreen extends BroadcastReceiver
16{
17 @Override
18 public void onReceive(Context context, Intent intent)
19 {
20 //Intent service = new Intent(context, photo_service.class);
21 Toast.makeText(context, "Jetzt wurde Entsperrung erkannt!", Toast.LENGTH_LONG).show();
22 // Kamerazeug....
23
24 }
25}



Ich möchte sobald ich auf den Button ""btnStart" klicke, den Receiver "scharfschalten".
Ist dieser dann scharfgeschaltet, soll (wie in reciever steht) nach dem Entsperren die Toast-Meldung: "Jetzt wurde Entsperrung erkannt!" ausgegeben werden.

Und das funktioniert schon nicht.
Ich weiß leider nicht warum. Könnt ihr mir helfen?

— geändert am 03.02.2014, 19:11:48

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

03.02.2014, 19:13:32 via Website

Sind alle manifest Berechtigungen für das mitbekommen des ScreenOn Events und den Receiver gesetzt?

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
impjor
  • Forum-Beiträge: 1.793

03.02.2014, 20:27:01 via App

Du rufst super.onPause() in onDestroy() auf!

Hast du mal ein Log.d() gesetzt, um zu schauen, ob der Receiver überhaupt aufgerufen wird?

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
anamollo
  • Forum-Beiträge: 24

03.02.2014, 22:17:37 via Website

Hallo!

Sind alle manifest Berechtigungen für das mitbekommen des ScreenOn Events und den Receiver gesetzt?
Ich habe leider nichts darüber gefunden, ob man für einen Receiver bzw. ein Screen_On-Event eine spezielle Berechtigung im Manifest benötigt.

Hast du mal ein Log.d() gesetzt, um zu schauen, ob der Receiver überhaupt aufgerufen wird?
Nein bisher nicht.

Es kommt mit folgendem Code in der Main zu der gleichen Meldung "that was originally registered here. Are you missing a call to unregisterReceiver()?"

1package com.jk.unlock;
2
3
4import android.os.Bundle;
5import android.app.Activity;
6import android.content.BroadcastReceiver;
7import android.content.Intent;
8import android.content.IntentFilter;
9import android.hardware.Camera;
10import android.view.Menu;
11import android.view.View;
12import android.widget.Button;
13
14
15
16public class MainActivity extends Activity
17{
18 BroadcastReceiver mReceiver;
19
20
21 @Override
22 protected void onCreate(Bundle savedInstanceState)
23 {
24 super.onCreate(savedInstanceState);
25 setContentView(R.layout.activity_main);
26
27 Button buttonStart= (Button)findViewById(R.id.btn_start);
28 Button buttonStop = (Button)findViewById(R.id.btn_stop);
29
30 buttonStart.setOnClickListener(btnStart);
31 buttonStop.setOnClickListener(btnStop);
32 }
33
34
35 Button.OnClickListener btnStart = new Button.OnClickListener()
36 {
37 @Override
38 public void onClick(View v)
39 {
40 IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON); // Instanz von "Intentfilter" anlegen
41 mReceiver = new receiverScreen(); // Screenreceiver instanziieren -> überwacht das Geschehen des Users auf dem Screen
42 registerReceiver(mReceiver, filter);
43
44 }
45 };
46
47
48
49 Button.OnClickListener btnStop = new Button.OnClickListener()
50 {
51 @Override
52 public void onClick(View v)
53 {
54 unregisterReceiver(mReceiver);
55 }
56 };
57
58 @Override
59 public void onBackPressed() // Wenn auf den "ZURÜCK"-Button gedrückt wird wird...
60 {
61 //unregisterReceiver(mReceiver);
62 finish(); // aktuelle Activity schließen. Es folgt die Mutter-Activity (dei Mudder!) ;)
63 }

Das kann doch wohl nicht sein.... :angry:

— geändert am 03.02.2014, 22:18:09

Antworten
anamollo
  • Forum-Beiträge: 24

04.02.2014, 10:01:04 via Website

Habt ihr noch Ideen?


Danke u. Gruß

Antworten
anamollo
  • Forum-Beiträge: 24

04.02.2014, 17:39:12 via Website

Hi!

Die Fehlermeldung wird geschmissen, wenn:
- ich auf den Zurückbutton meines Smartphones innerhalb der Activity drücke. Dann erscheint der "are you missing a call to unregister Receiver()"-Fehler.
Liegt das daran, dass ich in der "onBackPressed()" kein "unregisterReceiver()" habe?
Schließlich soll der Receiver ja auch weiterhin aktiv sein, da ich ja im Hintergrund auf das Ereignis weiterlauern will, obwohl die Activity geschlossen ist -> deshalb auch mein erster Versuch mit dem Service, den ich mittlerweile (auf Anraten) komplett weggelassen habe.

Also: Wie kann ich den Broadcastreceiver unabhängig von der Activity weiterlaufen lassen?

— geändert am 04.02.2014, 17:39:45

Antworten
impjor
  • Forum-Beiträge: 1.793

04.02.2014, 22:24:23 via App

Registriere den Broadcastreceiver in deinem AndroidManifest, dann musst du nicht Context#registerReceiver() benutzen.

Oben habe ich ja erwähnt, wie du den Broadcastreceiver trotzdem deaktivieren kannst.

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten