-1

I am trying to make an app on Android, using Kotlin and Java.

My inspiration comes from this tutorial:

https://www.youtube.com/watch?v=Qg3L_B9--zY

I changed it a little bit, and now I have a beautiful error:

"Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference"

Here is the error log:

11-21 10:46:03.006 27125-27125/? E/libprocessgroup: failed to make and chown /acct/uid_10058: Read- 
only file system
11-21 10:46:03.006 27125-27125/? W/Zygote: createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?

11-21 10:46:03.006 27125-27125/? I/art: Not late-enabling -Xcheck:jni (already on)
11-21 10:46:03.079 27125-27125/com.example.budgetapp I/System.out: Util Constructor
11-21 10:46:03.143 27125-27125/com.example.budgetapp E/MainActivity: before onCreate()
11-21 10:46:03.150 27125-27125/com.example.budgetapp W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter androidx.vectordrawable.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
11-21 10:46:03.183 27125-27125/com.example.budgetapp E/MainActivity: after onCreate()

11-21 10:46:03.206 27125-27125/com.example.budgetapp I/art: Rejecting re-init on previously-failed class java.lang.Class<androidx.core.view.ViewCompat$2>
11-21 10:46:03.206 27125-27125/com.example.budgetapp I/art: Rejecting re-init on previously-failed class java.lang.Class<androidx.core.view.ViewCompat$2>
11-21 10:46:03.275 27125-27125/com.example.budgetapp E/MainActivity: after setContentView()
11-21 10:46:03.275 27125-27125/com.example.budgetapp D/AndroidRuntime: Shutting down VM


    --------- beginning of crash
11-21 10:46:03.276 27125-27125/com.example.budgetapp E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.budgetapp, PID: 27125
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.budgetapp/com.example.budgetapp.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
        at android.app.ActivityThread.access$800(ActivityThread.java:151)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5254)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference
        at android.content.ContextWrapper.getApplicationInfo(ContextWrapper.java:149)
        at android.view.ContextThemeWrapper.getTheme(ContextThemeWrapper.java:99)
        at android.content.Context.obtainStyledAttributes(Context.java:437)
        at androidx.appcompat.app.AppCompatDelegateImpl.createSubDecor(AppCompatDelegateImpl.java:692)
        at androidx.appcompat.app.AppCompatDelegateImpl.ensureSubDecor(AppCompatDelegateImpl.java:659)
        at androidx.appcompat.app.AppCompatDelegateImpl.findViewById(AppCompatDelegateImpl.java:479)
        at androidx.appcompat.app.AppCompatActivity.findViewById(AppCompatActivity.java:214)
        at Util.setupUIViews(Util.java:43)
        at com.example.budgetapp.MainActivity.onCreate(MainActivity.kt:27)
        at android.app.Activity.performCreate(Activity.java:5990)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387) 
        at android.app.ActivityThread.access$800(ActivityThread.java:151) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:135) 
        at android.app.ActivityThread.main(ActivityThread.java:5254) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:372) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 

And here are my classes:

MainActivity.kt:

package com.example.budgetapp

import Util
import android.app.DatePickerDialog
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import java.util.*

class MainActivity : AppCompatActivity() {
    private val tag = "MainActivity"
    var util = Util()


    override fun onCreate(savedInstanceState: Bundle?) {
        Log.e(tag, "before onCreate()")

        super.onCreate(savedInstanceState)
        Log.e(tag, "after onCreate()")

        setContentView(R.layout.activity_main)
        Log.e(tag, "after setContentView()")



        util.setupUIViews()
        Log.e(tag, "after setupUIView()")

        util.initToolbar()
        Log.e(tag, "after initToolbar()")

        util.setupListView()
        Log.e(tag, "after setupListView()")



        //Calendars:
        val c = Calendar.getInstance()
        val year = c.get(Calendar.YEAR)
        val month = c.get(Calendar.MONTH)
        val day = c.get(Calendar.DAY_OF_MONTH)

        val c2 = Calendar.getInstance()
        val year2 = c2.get(Calendar.YEAR)
        val month2 = c2.get(Calendar.MONTH)
        val day2 = c2.get(Calendar.DAY_OF_MONTH)

        Log.e(tag, "year1: $year")
        Log.e(tag, "month1: $month")
        Log.e(tag, "month2: $month2")
        Log.e(tag, "day1: $day")

        //button click to show DatePickerDialog
        pickDateBtn.setOnClickListener {
            val dpd = DatePickerDialog(
                this,
                DatePickerDialog.OnDateSetListener {_, mYear, mMonth, mDay ->
                    var monthSel=mMonth+1
                    dateTv2.text = "$mDay/$monthSel/$mYear"
                },
                year,
                month,
                day
            )
            dpd.show()

            val dpd2 = DatePickerDialog(
                this,
                DatePickerDialog.OnDateSetListener {_, mYear2, mMonth2, mDay2 ->
                    var monthSel2=mMonth2+1
                    dateTv.text = "$mDay2/$monthSel2/$mYear2"
                },
                year2,
                month2,
                day2
            )
            dpd2.show()
        }
    }
}

SimpleAdapter.java:

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.budgetapp.R;

public class SimpleAdapter extends BaseAdapter {
    public Context mContext;
    private LayoutInflater layoutInflater;
    private TextView title, description;
    private String[] titleArray, descriptionArray;
    private ImageView imageView;


   public SimpleAdapter(Context context, String[] title, String [] description){
            mContext= context;
            titleArray=title;
            descriptionArray= description;
            layoutInflater= LayoutInflater.from(context);
        }



    @Override
    public int getCount(){
        return titleArray.length;
    }

    @Override
    public Object getItem(int position) {
        return  titleArray[position];
    }

    @Override
    public long getItemId(int position){
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(convertView == null) {
            layoutInflater.inflate(R.layout.main_activity_single_item, null);
        }
        title= convertView.findViewById(R.id.tvMain);
        description = convertView.findViewById(R.id.tvDescription);
        imageView = convertView.findViewById(R.id.ivMain);

        title.setText(titleArray[position]);
        description.setText(descriptionArray[position]);

        if(titleArray[position].equalsIgnoreCase("Timetable")){
            imageView.setImageResource(R.drawable.timetable);
        }else if(titleArray[position].equalsIgnoreCase("Subjects")){
            imageView.setImageResource(R.drawable.book);
        }else if(titleArray[position].equalsIgnoreCase("Faculty")) {
            imageView.setImageResource(R.drawable.play);
        }else{
             imageView.setImageResource(R.drawable.settings);
            }
    return convertView;
    }
}

and Util.java:

import android.widget.ListView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.example.budgetapp.R;

import java.util.logging.Logger;

public class Util extends AppCompatActivity {

   public Util(){
       System.out.println("Util Constructor");
   }

    public Toolbar getToolbar() {
        return toolbar;
    }

    public void setToolbar(Toolbar toolbar) {
        this.toolbar = toolbar;
    }

    public ListView getListView() {
        return listView;
    }

    public void setListView(ListView listView) {
        this.listView = listView;
    }

    @Override
    public String toString() {
        return "Util{" +
                "toolbar=" + toolbar +
                ", listView=" + listView +
                '}';
    }

    private Toolbar toolbar;
    private ListView listView;
    Logger logger;

        public void setupUIViews(){
            toolbar = findViewById(R.id.ToolbarMain);
            logger.info("inside Util class, setupUiViews, before findViewById(lvMain)");
            listView = findViewById(R.id.lvMain);
        }

        public void initToolbar(){
            setSupportActionBar(toolbar);
            getSupportActionBar().setTitle(" App");
        }

        public void setupListView(){
            String[] title = getResources().getStringArray(R.array.Main);
            String[] description=getResources().getStringArray(R.array.Description);

            SimpleAdapter simpleAdapter = new SimpleAdapter(this, title, description);
            listView.setAdapter(simpleAdapter);
        }
}

The code crushes before entering into setupUIViews() method from Util class.

Can you please, please take a look and tell me how can I resolve the issue ?

I debugged, but did not understand where the problem comes from.

Also, looked to other similar questions, but each exemple is specific, so I cannot extrapolate to my situation.

Thank you very much for your time and help!

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Léa
  • 51
  • 5

2 Answers2

0

The util class is extending from AppCompatActivity but is not properly initialized. You can't use AppCompatActivity in that way. Instead you need to do something like:

class MainActivity : AppCompatActivity() {
    private val tag = "MainActivity"
    lateinit var util: Util

    override fun onCreate(savedInstanceState: Bundle?) {
        util  = Util(this)
    }
}

And the Util (in kotlin) class:

class Util(private delegate:MainActivity) {
    public void setupUIViews(){
        toolbar = delegate.findViewById(R.id.ToolbarMain);
        listView = delegate.findViewById(R.id.lvMain);
    }
}

Also, I think that using this pattern and move all view-related stuff to a "Util" class is not the best. You will have better results using other patterns like MVP or MVVM.

  • Thank you Ricardo Markiewicz, I agree that having a separate Util class is not the best idea. Even after using the suggestions that you gave, the program does not compile, even if the code is correct (as what I know about Kotlin, which is not a lot). I will change methods from Util, in the MainActivity, as mentioned in the tutorial, and as you imply. Thank you for your reply, sir! Great suggestions – Léa Nov 21 '19 at 13:28
0

you call util. setupUIViews(), in the inner method,it called findViewById(R.id.ToolbarMain). this method is belonged to Activity, we look at the source code

return getWindow().findViewById(id);

//in the window, (PhoneWindow)
@Nullable
    public <T extends View> T findViewById(@IdRes int id) {
        return getDecorView().findViewById(id);
    }
// the DecorView is the basic view, it set when you call setContentView
public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }
//PhoneWindow setContentView
@Override
    public void setContentView(View view) {
        setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    }
@Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
  // decor, when theme attributes and the like are crystalized. Do not 
  // check the feature
        // before this happens.
        if (mContentParent == null) {
            installDecor(); // this method init DecorView
       } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }
...
}

but you do not call util setContenView to set its view. so it reports the error.

and your code writes way is wrong. we set view in activity or fragment own class; we cannot use another activity to set other activities.

In android, every activity has its own window. try to move the Utils method into MainActiviy.

Lenoarod
  • 3,441
  • 14
  • 25
  • Hi Lenoarod, "In android, every activity has its own window. try to move the Utils method into MainActiviy.". Very well pointed! I understand my problem now. Well, I used a shortcut, because I did not succed to convert from Java code to Kotlin code. So I created a new class, in order to be able to use there the Java code I had. Not working! Maybe you could help me find a way around ? Here is the Java code, my problem is with declaring and initializing the lists. I looked through documentation, but still my code was not compilying, after doing the changes – Léa Nov 21 '19 at 13:36
  • Here is the Java code: public void setupListView(){ String[] title = getResources().getStringArray(R.array.Main); String[] description=getResources().getStringArray(R.array.Description); SimpleAdapter simpleAdapter = new SimpleAdapter(this, title, description); listView.setAdapter(simpleAdapter); } It would really help me a lot! Thank you – Léa Nov 21 '19 at 13:36
  • @Léa, if your meaning is the list does not show. the reason is in the adapter getView. `if(convertView == null) { layoutInflater.inflate(R.layout.main_activity_single_item, null); }`, you did not return a view. you can see this answer(https://stackoverflow.com/a/8693597/5705408) for more details – Lenoarod Nov 21 '19 at 13:52
  • @Léa, At the same time, today, we often use recyclerView. it is better for the list. – Lenoarod Nov 21 '19 at 13:54
  • Ok, I'll take a close look to the link and reference you gave me. You were right about having every activity in it's own window. I'll accept your answer, it was really helpful! In the meanteam, I succeded to transform from Java to Kotlin (for those who will have the same issue as myself), here is what worked for me : private fun setupListView(){ val title = resources.getStringArray(R.array.Main) val description=resources.getStringArray(R.array.Description) var simpleAdapter= SimpleAdapter(this, title, description) listView.setAdapter(simpleAdapter);} – Léa Nov 21 '19 at 14:28