androidandroid-studioandroid-anr-dialog

android project compiles but doesn't run correctly


this is the main activity file That I have:

package de.project.packagelist;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

import de.project.packagelist.models.Pkg;

public class MainActivity extends AppCompatActivity {

    public static MainActivity instance;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        instance = this;
        setContentView(R.layout.activity_main);

        populatePackages();
    }

    public void onPackageUninstalled(String pkgName) {
        Toast.makeText(this, pkgName + " is uninstalled", Toast.LENGTH_SHORT).show();
        populatePackages();
    }

    public void onPackageInstalled(String pkgName) {
        Toast.makeText(this, pkgName + " is installed", Toast.LENGTH_SHORT).show();
        populatePackages();
    }

    public void onPackageChanged(String pkgName) {
        Toast.makeText(this, pkgName + " is changed", Toast.LENGTH_SHORT).show();
        populatePackages();
    }

    public void populatePackages() {
        ArrayList<Pkg> pkgList = new ArrayList<>();
        PackageListAdapter packageListAdapter = new PackageListAdapter(this, pkgList);
        ListView listView = (ListView) findViewById(R.id.package_list);
        listView.setAdapter(packageListAdapter);
        pkgList.clear();
        PackageManager pm = getPackageManager();
        List<PackageInfo> packages = pm.getInstalledPackages(PackageManager.GET_META_DATA);

        for (PackageInfo packageInfo : packages) {
            pkgList.add(new Pkg(packageInfo.packageName, packageInfo.packageName, packageInfo.versionName, packageInfo.versionCode));
        }
    }

    class PackageListAdapter extends ArrayAdapter<Pkg> {

        public PackageListAdapter(Context context, List<Pkg> packages) {
            super(context, R.layout.list_item_package, packages);
        }

        @NonNull
        @Override
        public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
            View v = convertView;

            if (v == null) {
                LayoutInflater vi;
                vi = LayoutInflater.from(getContext());
                v = vi.inflate(R.layout.list_item_package, null);
            }
            final Pkg p = getItem(position);
            if (p != null) {
                TextView tt1 = (TextView)v.findViewById(R.id.pkg_label);
                tt1.setText(p.getLabel());
                TextView tt2 = (TextView)v.findViewById(R.id.pkg_name);
                tt2.setText(p.getName());
                TextView tt3 = (TextView)v.findViewById(R.id.pkg_version);
                tt3.setText(p.getVersionName());
                Button btn1 = (Button)v.findViewById(R.id.pkg_uninstall);
                btn1.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Toast.makeText(getApplicationContext(), "Uninstalling package: " + p.getName(), Toast.LENGTH_SHORT).show();
                    }
                });

                Button btn2 = (Button)v.findViewById(R.id.pkg_launch);
                btn2.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Toast.makeText(getApplicationContext(), "Launching package: " + p.getName(), Toast.LENGTH_SHORT).show();
                    }
                });

                ImageView imageView = (ImageView)v.findViewById(R.id.pkg_icon);
//                imageView.setImageDrawable(p.get);

            }

            return v;
        }
    }

}

and this is the receiver's code:

import android.net.Uri;

import de.project.packagelist.MainActivity;


public class PackageChangedBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //triggered whenever any change happens to any package
        //should inform activity
        Uri data = intent.getData();
        String pkgName = data.toString().substring(data.getScheme().length() + 1); //remove 'package:'
        if(MainActivity.instance != null) {
            if(intent.getAction() == "android.intent.action.PACKAGE_ADDED") {
                MainActivity.instance.onPackageInstalled(pkgName);
            } else if(intent.getAction() == "android.intent.action.PACKAGE_REMOVED") {
                MainActivity.instance.onPackageUninstalled(pkgName);
            } else if(intent.getAction() == "android.intent.action.PACKAGE_CHANGED") {
                MainActivity.instance.onPackageChanged(pkgName);
            }
        }
    }
}

MY code compiles without errors but when I run it, it takes too long to launch and the buttons are irresponsive. I know I am using older versions and libraries but do you see anything I can improve within my code. in my XML files(manifest and layouts, I have the launch icon and 2 buttons one to launch the package and the other one is to uninstall it.

What am I doing wrong?


Solution

  • I think you have to change your populatePackages function. You create your adapter and set your list view again and again on each brodcast process.

    I think you should create a function which is initAdapter

    InitAdapter function :

    public void initAdapter(){
      //not set list here and PackageListAdapter define as global
      packageListAdapter = new PackageListAdapter(this);
      ListView listView = (ListView) findViewById(R.id.package_list);
      listView.setAdapter(packageListAdapter);
    }
    

    change the constructor of adapter class and create a setItems function

    public PackageListAdapter(Context context) {
                super(context, R.layout.list_item_package);
            }
    public setItems(List<Pkg> packages) {
      this.packages = packages
    }
    

    and in your populatePackages function:

    public void populatePackages() {
            ArrayList<Pkg> pkgList = new ArrayList<>();
            PackageManager pm = getPackageManager();
            List<PackageInfo> packages = pm.getInstalledPackages(PackageManager.GET_META_DATA);
    
            for (PackageInfo packageInfo : packages) {
                pkgList.add(new Pkg(packageInfo.packageName, packageInfo.packageName, packageInfo.versionName, packageInfo.versionCode));
            }
            packageListAdapter.setItems(pkgList); 
        }