Assets und ApplicationContext -> null object reference

  • Antworten:8
Boris82
  • Forum-Beiträge: 4

06.08.2018, 12:13:04 via Website

Hallo zusammen,

vor Kurzem habe ich begonnen, mich ein wenig mit der App Entwicklung auseinander zu setzen.

Die ersten Gehversuche haben einwandfrei geklappt.

Nun strauchel ich allerdings.

In der MainActivity wird mittels

conn = (HttpURLConnection)url.openConnection();

ein Login durchgeführt.

Klappt.

Bei Erfolg lade ich mittels

Intent intent = new Intent(MainActivity.this,SuccessActivity.class);
                startActivity(intent);
                MainActivity.this.finish();

die SuccessActivity, auf der sich ein WebView Control befindet.

Klappt auch.

Die dort geladene Seite ruft mittels JavaScriptInterface ein paar Funktionen auf.

scripts.innerHTML = window.android.getFileContents('js/js-all.src.js');

Diese JS Datei befindet sich im Assets Folder, was zuvor (als sich vie WebView noch auf der MainActivity befand) auch wunderbar klappte.

Die Zeile

InputStream is = getApplicationContext().getAssets().open(name);

wirft nun allerdings die folgende Exception:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference

Auch die folgende Zeile brachte keinen Erfolg:

InputStream is = MainActivity.getContext().getAssets().open(name);

Daher nun meine Frage(n):

Stehen die Assets in anderen Activities als der Main nicht zur Verfügung?
Oder greife ich nur falsch darauf zu?

Vielen Dank für Hinweise, die mich zur Lösung führen.

Boris

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

06.08.2018, 12:15:24 via App

Hallo Boris82,

Herzlich willkommen hier im Forum :)

du musst mit dem Activity Context (innerhalb einer Activity mit 'this' durch die Vererbung) arbeiten. Der ApplicationContext ist hier zu allgemein.

d.h. this.getAssets()...

— geändert am 06.08.2018, 12:16:07

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

Hilfreich?
swa00
Kommentieren
swa00
  • Forum-Beiträge: 3.704

06.08.2018, 12:18:14 via Website

Zumal ich zusätzlich mir jetzt nicht zu 100% sicher bin , aber der Asset-Inhalt müsste in diesem Beispiel vorher ausgelagert werden.

— geändert am 06.08.2018, 12:18:39

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Kommentieren
Boris82
  • Forum-Beiträge: 4

06.08.2018, 14:52:28 via Website

Hallo zusammen,

vielen Dank für eure Rückmeldungen.

Sollte ein

public class MainActivity extends AppCompatActivity {
....

    //Initialize Application Context
    public static Context appContext;

    //Get Application Context (for use in external functions)
    public  static Context getContext() {
      return appContext;
    }

in Verbindung mit einem

class JavaScriptInterface extends AppCompatActivity {

...
            InputStream is = MainActivity.appContext.getAssets().open(name);

nicht einem this. gleichkommen?

Oder habe ich das nun falsch verstanden?

Hilfreich?
Kommentieren
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

06.08.2018, 14:56:50 via Website

Das hast du falsch verstanden.

Jeder Activity hat ihren eigenen Context, da diese ja von Context erbt. Daher ist es ratsam, in jeder Activity den eigenen Context zu nehmen und nicht den von anderen Activities.

Zudem: Bei deiner Konstruktion kann der appContext im getter null sein oder vom GarbageCollector schon verworfen, da die Activity zu ist.
Einen Context bitte nie statisch speichern und abrufen. Das kann spätestens bei Views zu kuriosem Verhalten führen.

Zu deiner eigentlichen Frage eine Contextinstanz ist Activityübergreifend nicht vohanden, jede Activity hat einen Individuellen Context daher ist das mit dem Getter in der Main nicht so gut.

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

Hilfreich?
swa00
Kommentieren
Boris82
  • Forum-Beiträge: 4

06.08.2018, 15:13:07 via Website

Ok, wenn ich also nun die finish Methode der MainActivity nicht aufrufe und in der class JavaScriptInterface mit InputStream is = this.getAssets().open(name); an die Assets herankommen möchte, dann sollte das doch funktionieren, oder? (Was nicht der Fall ist).

Hilfreich?
Kommentieren
swa00
  • Forum-Beiträge: 3.704

06.08.2018, 15:20:37 via Website

@Pascal : Sorry für meinen "Zwischensenf" :-)

@Boris

Ok, wenn ich also nun die finish Methode der MainActivity nicht aufrufe

Du hast Pascal leider nicht verstanden - weil - und nimm es mir nicht übel - Dir die Grundlagen über den Aufbau für die Programmierung fehlen. (e.g. Was ist z.b. ein Context, was macht der GC etc)

Und dennoch wiederhole ich meinen Einwand von oben : Das Script muss in dem Falle als File vorliegen und nicht aus den Assets direkt.

— geändert am 06.08.2018, 15:26:49

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Pascal P.
Kommentieren
Boris82
  • Forum-Beiträge: 4

06.08.2018, 15:25:12 via Website

und nimm es mir nicht übel

Tu ich nicht, hast ja Recht ;-)

Ich glaube schon, dass ich verstanden habe, was Pascal mitteilen wollte. Ich habe vermutlich nur die falschen Schlüsse daraus gezogen.

Das Script muss in dem Falle als File vorliegen und nicht aus den Assets direkt.

Das Script liegt doch als Datei vor - wobei ich zugeben muss, dass ich deinen Satz nicht so wirklich verstanden habe.

Es hat ja vorher auch funktioniert, wenn ich das WebView Control in der Main verwende.

Hilfreich?
Kommentieren
swa00
  • Forum-Beiträge: 3.704

06.08.2018, 15:33:10 via Website

Das Script liegt doch als Datei vor - wobei ich zugeben muss, dass ich deinen Satz nicht so wirklich verstanden habe.

In deinem Projektordner unter den Assets vielleicht, aber nicht zur Runtime.

Teste mal Folgendes : Erstelle in deinem Installationspfad auf dem Zieldevice einen weiteren Ordner und
kopiere dort mal manuell deine js hin , Dann rufst du dieses Script in dem Pfad auf.
Wenn es dann einwandfrei funktioniert , muss die Datei physisch vorliegen.

Grund :
Nun , in die Assets werden die Daten gepackt in der APK mitgeliefert und bei Bedarf zur Runtime entpackt (z.b. ein Soundfile im Memory)

Allerdings : Erst wenn dein Script physisch auf dem Filesystem vorliegt ,dann kannst du es auch ausführen.
Dazu benötigt es von Dir eine SynchronRoutine , die bei der Erstbenutzung die Assets entpackt und installiert .

Es hat ja vorher auch funktioniert, wenn ich das WebView Control in der Main verwende.

Dann bastel Dir dazu einen Construktor/Setter, dem Du den richtigen Context übergeben kannst.
(Dein Aufbau ansich ist uns ja insofern unbekannt)

— geändert am 06.08.2018, 16:03:19

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Pascal P.
Kommentieren