2

Ok, I was working on a Android app that can show you a few things like TV schedule, News, Wather Forecast and Horoscope using RSS. The app works as it should on Android 2.1 or 2.3.X, but when I start it on 4.0 or 4.1 it stops working after I chose any option from main.

The structure of app is:

-Main

-Activity for specific thing (like just News) that has a view

-XML Parser class that is called by previous class

-Activity for Signle View (like just one information from whole bunch of news) with it's view

Here I provide the Manifest, Log and few classes:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mtel.vodic"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="7"
    android:targetSdkVersion="14" />

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name=".Vodic"
        android:label="@string/title_activity_pocetna" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <activity
        android:name=".Pomoc"
        android:label="@string/m_tel_vodi_za_odlu_ne"
        ></activity>
    <activity
        android:name=".Pomocna"
        android:label="@string/m_tel_vodi_za_odlu_ne"
        ></activity>
    <activity
        android:name=".SingleMenuItemActivity"
        android:label="@string/m_tel_vodi_za_odlu_ne"
        ></activity>
   .
   .
   .

</application>

<uses-permission android:name="android.permission.INTERNET" />

<!-- Needed to check when the network connection changes -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

</manifest>

Error Log:

10-18 20:35:05.457: E/Trace(730): error opening trace file: No such file or directory     (2)
10-18 20:35:06.197: I/Choreographer(730): Skipped 30 frames!  The application may be doing too much work on its main thread.
10-18 20:35:06.257: D/gralloc_goldfish(730): Emulator without GPU emulation detected.
10-18 20:35:11.316: D/AndroidRuntime(730): Shutting down VM
10-18 20:35:11.316: W/dalvikvm(730): threadid=1: thread exiting with uncaught exception (group=0x40a13300)
10-18 20:35:11.347: E/AndroidRuntime(730): FATAL EXCEPTION: main
10-18 20:35:11.347: E/AndroidRuntime(730): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mtel.vodic/com.mtel.vodic.Vijesti}: java.lang.NullPointerException
10-18 20:35:11.347: E/AndroidRuntime(730):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
10-18 20:35:11.347: E/AndroidRuntime(730):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
10-18 20:35:11.347: E/AndroidRuntime(730):  at android.app.ActivityThread.access$600(ActivityThread.java:130)
10-18 20:35:11.347: E/AndroidRuntime(730):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
10-18 20:35:11.347: E/AndroidRuntime(730):  at android.os.Handler.dispatchMessage(Handler.java:99)
10-18 20:35:11.347: E/AndroidRuntime(730):  at android.os.Looper.loop(Looper.java:137)
10-18 20:35:11.347: E/AndroidRuntime(730):  at android.app.ActivityThread.main(ActivityThread.java:4745)
10-18 20:35:11.347: E/AndroidRuntime(730):  at java.lang.reflect.Method.invokeNative(Native Method)
10-18 20:35:11.347: E/AndroidRuntime(730):  at java.lang.reflect.Method.invoke(Method.java:511)
10-18 20:35:11.347: E/AndroidRuntime(730):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
10-18 20:35:11.347: E/AndroidRuntime(730):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
10-18 20:35:11.347: E/AndroidRuntime(730):  at dalvik.system.NativeStart.main(Native Method)
10-18 20:35:11.347: E/AndroidRuntime(730): Caused by: java.lang.NullPointerException
10-18 20:35:11.347: E/AndroidRuntime(730):  at com.mtel.vodic.Vijesti.onCreate(Vijesti.java:61)
10-18 20:35:11.347: E/AndroidRuntime(730):  at android.app.Activity.performCreate(Activity.java:5008)
10-18 20:35:11.347: E/AndroidRuntime(730):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
10-18 20:35:11.347: E/AndroidRuntime(730):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
10-18 20:35:11.347: E/AndroidRuntime(730):  ... 11 more
10-18 20:35:13.926: I/Process(730): Sending signal. PID: 730 SIG: 9

Main:

public class Vodic extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_pocetna);
    Button tv = (Button)findViewById(R.id.tv);
    Button vijesti = (Button)findViewById(R.id.vijesti);
    Button horoskop = (Button)findViewById(R.id.horoskop);
    Button vremenska_prognoza = (Button)findViewById(R.id.vremenska_prognoza);
    Button o_aplikaciji = (Button)findViewById(R.id.o_aplikaciji);
    Button pomoc = (Button)findViewById(R.id.pomoc);

   .
   .
   .

    vijesti.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View arg0) {
            Intent xw = new Intent(getApplicationContext(), Vijesti.class );
            //xw.putExtra("A", "http://bih-x.info/feed/");
            xw.putExtra("A", "http://klix.ba/rss/naslovnica");
            if(!isOnline()) {
                Toast.makeText(getApplicationContext(), "Niste povezani sa internetom!", Toast.LENGTH_SHORT).show();
            } else {
                startActivity(xw);
            }
        }
    });

   .
   .
   .

public boolean isOnline() {
    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo netInfo = cm.getActiveNetworkInfo();
    if(netInfo != null && netInfo.isConnected()) {
        return true;
    }
    return false;
}
}

Activity:

public class Vijesti extends ListActivity {

static String url =null;

// XML node keys
static final String KEY_ITEM = "item"; // parent node
static final String KEY_TITLE = "title";
static final String KEY_DATE = "pubDate";
static final String KEY_DESC = "encoded";
static final String UVOD = "uvod";
static final String CLANAK = "clanak";

@Override
protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.vijesti_m);
    Intent in = getIntent();

    // Get XML values from previous intent
    url = in.getStringExtra("A");
    final ArrayList<HashMap<String,String>> menuItems = new ArrayList<HashMap<String,String>>();
    ArrayList<String> xqw = new ArrayList<String>();

    ParserVijesti parser=null;
    Document doc=null;
    try {
        parser = new ParserVijesti();
        String xml = parser.getXmlFromUrl(url); //get XML
        doc = parser.getDomElement(xml);
    } catch (Exception e1) {
        finish();
    }

    NodeList nl = doc.getElementsByTagName(KEY_ITEM);
    //loop
    for (int i=0; i< nl.getLength(); i++){
        HashMap<String, String> map = new HashMap<String, String>();
        HashMap<String, String> mapq = new HashMap<String, String>();

        Element e = (Element) nl.item(i);

        //add to map
        map.put(KEY_TITLE, parser.getValue(e, KEY_TITLE));
        map.put(KEY_DATE, parser.getValue(e, KEY_DATE));
        map.put(UVOD, parser.getValue(e,UVOD));
        map.put(CLANAK, parser.getValue(e,CLANAK));


        menuItems.add(map);

        xqw.add(parser.getValue(e,KEY_TITLE));
    }

    for(int gf=0; gf<xqw.size(); gf++){
        Log.w("ISPISI: ", xqw.get(gf));
    }
    ArrayAdapter adapterx = new ArrayAdapter(this, R.layout.vijesti_m,R.id.tetkica, xqw);


    setListAdapter(adapterx);

    //singleView
    ListView lv = getListView();

    lv.setOnItemClickListener(new OnItemClickListener(){
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id){

            int hg = position;
            HashMap<String, String> kaktus = menuItems.get(hg);
            String uvod1 = kaktus.get(UVOD);
            String clanak1 = kaktus.get(CLANAK);
            String dat1 = kaktus.get(KEY_DATE);
            String tit1 = kaktus.get(KEY_TITLE);



            //intent
            Intent inx = new Intent(getApplicationContext(), VijestiSingle.class);
            inx.putExtra(KEY_TITLE, tit1);
            inx.putExtra(KEY_DATE, dat1);
            inx.putExtra(UVOD, uvod1);
            inx.putExtra(CLANAK, clanak1);
            startActivity(inx);
        }
    });


}   

}

XML Parsing Class:

public class ParserVijesti {




// constructor
public ParserVijesti() {

}

/**
 * Getting XML from URL making HTTP request
 * @param url string
 * */
public String getXmlFromUrl(String url) {
    String xml = null;

    try {
        // defaultHttpClient
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);

        HttpResponse httpResponse = httpClient.execute(httpPost);
        HttpEntity httpEntity = httpResponse.getEntity();
        xml = EntityUtils.toString(httpEntity, "UTF-8");

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    // return XML
    return xml;
}
/**
 * Getting XML DOM element
 * @param XML string
 * */

public Document getDomElement(String xml){
    Document doc = null;
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setCoalescing(true);
    dbf.setNamespaceAware(true);
    try {
        DocumentBuilder db = dbf.newDocumentBuilder();

        InputSource is = new InputSource();
        is.setByteStream(new ByteArrayInputStream(xml.getBytes("UTF-8")));
            doc = db.parse(is); 

        } catch (ParserConfigurationException e) {
            Log.e("Error: ", e.getMessage());
            return null;
        } catch (SAXException e) {
            Log.e("Error: ", e.getMessage());
            return null;
        } catch (IOException e) {
            Log.e("Error: ", e.getMessage());
            return null;
        }

        return doc;
}

/** Getting node value
  * @param elem element
  */
 public final String getElementValue( Node elem ) {
     Node child;
     if( elem != null){
         if (elem.hasChildNodes()){
             for( child = elem.getFirstChild(); child != null; child = child.getNextSibling() ){
                 if(child.getNodeType() == Node.TEXT_NODE || child.getNodeType() == Node.CDATA_SECTION_NODE){
                     return child.getNodeValue();
                 }
             }
         }
     }
     return "";
 }

 public final String getElementValue2( Node elem ) {
     Node child;
     if( elem != null){
         if (elem.hasChildNodes()){
             for( child = elem.getFirstChild(); child != null; child = child.getNextSibling() ){
                 if(child.getNodeType() == Node.CDATA_SECTION_NODE){
                     return child.getNodeValue();
                 }
             }
         }
     }
     return "SRANJE";
 }

 /**
  * Getting node value
  * @param Element node
  * @param key string
  * */



 public String getValue(Element item, String str) {     
        NodeList n = item.getElementsByTagName(str);                
        return this.getElementValue(n.item(0));
    }


 public String getValue3(Element item, String str){
     NodeList n = item.getElementsByTagNameNS("http://purl.org/rss/1.0/modules/content/", str);
     String ses = this.getElementValue2(n.item(0));

     //String mim =ses.replaceAll("(?s)\\<.*?\\>", " \n");
     String html = ses;
     Spanned strxa = Html.fromHtml(html);
     String fffx=strxa.toString();

     //return this.getElementValue2(n.item(0));
     //return ses;
     //return Promjena(ses);
     return fffx;
 }


}

To sum up: App works as it should on 2.1 or 2.3.x but stops after I chose anything from main activity on Android 4.0 or 4.1. I don't know what's up with it.. can anybody help?

Geobits
  • 22,218
  • 6
  • 59
  • 103
Igx33
  • 171
  • 1
  • 2
  • 10

2 Answers2

2

According to the logs, you're getting a null pointer on Vijesti.java:61. You said this line is:

NodeList nl = doc.getElementsByTagName(KEY_ITEM);

That means doc must be null. Since you assign that with getDomElement(), it means your problem lies in that method. The only way I see that it could be null (since DocumentBuilder.parse() can't return null) is if you're hitting one of your catch statements.

Do you get any of the catch exception messages in your logcat? The portion you've shown only lists the actual errors resulting from the null pointer. Your message would probably be a bit before that. Check for that, and you'll be able to tell which exception you're getting, and handle it accordingly.

Geobits
  • 22,218
  • 6
  • 59
  • 103
  • Aha! You've got it. The only catch statement before line 61 is the one that calls finish() on failure. OP probably thought that finish() was like exit() and would cause execution to terminate immediately. In reality, finish() still returns to the caller (the system will terminate the app shortly, but not instantly.) This code should also execute Log.e() and return; after calling finish(). – Edward Falk Oct 19 '12 at 00:39
  • Are you sure that's what's happening? It's possible, but it seems more likely that one of the `catch` blocks in `getDomElement()` is firing, since those all `return null`(which gets assigned to `doc`) and *don't* finish, which explains a null pointer quite nicely. – Geobits Oct 19 '12 at 00:43
  • I agree. OP should definitely be checking for null here. – Edward Falk Oct 19 '12 at 02:44
  • Ok, I've put Log.w(message) in that catch statement before NodeList thing. After that finish() method. And when I start the app and chose "Vijesti" it stops and I get that that catch statement is called via my message in log... I've also put Log.w(message) in all of my 3 getDomElement catch statements. None is called.... So, it must be something in that thing before... – Igx33 Oct 19 '12 at 06:51
  • Hmm... as one answer said... I just deleted targetSdkVersion... it works now.. how can this happen? – Igx33 Oct 19 '12 at 06:54
  • That normally means something got changed in 4.0, but either way, that's a bad way to leave it, like Teovald said. You might want to step through it with a debugger to find out what's going on more clearly. You're ending up null, and you need to find out exactly which path it's taking to figure out how to fix it. – Geobits Oct 19 '12 at 11:57
0

This will not solve your original problem, but:

I think this is another problem you are having: You are publishing your app with a targetSdkVersion higher than you have tested and confirmed your application to work against.

You have set the targetSdkVersion to 14. But if you read this:

Android Min SDK Version vs. Target SDK Version

you will understand that setting targetSdkVersion to 14 means that you are telling Android "I have tested my app on API 14 and confirm that it is working, please disable all compatibility settings for versions lower than API 14".

But this is not true, you have actually confirmed the opposite, that the app is NOT working on 4.0!

If you set targetSdkVersion to 14 it will make Android 4.0 disable compatibility settings it normally uses to ensure that apps for older APIs work (f.i. GPU rendering, JNI changes)

So for now you should just set minSdkVersion and no targetSdkVersion when you publish your app, to keep the compatibility behaviors enabled in 4.0.

Raise targetSdkVersion to 14 only after you have fixed the original bug and tested your app on against API 14, and not before.

Community
  • 1
  • 1
Raimo Ihle
  • 302
  • 1
  • 3
  • That really seams to work! I just deleted targetSdkVersion... Thank You – Igx33 Oct 19 '12 at 06:53
  • That's a terrible idea in the long run. You should always target the last version of Android (16 at the moment) when developping/maintaining an app. If you ignore this good practice recommanded by Google it will come bite you in the ass sooner or later . – Teovald Oct 19 '12 at 08:08
  • @Teovald: Yes, you are correct, of course you should ensure your apps work with the latest SDKs without compatibility settings. But until you have done so, do not raise the targetSdk version higher than you have tested when publishing the app, else you are going to let your users do the compatibility testing. – Raimo Ihle Oct 19 '12 at 10:20