Message with Exception Trace (MET)

ECn Categories > Non-informative Message (NIM) > Message with Exception Trace (MET)

The displayed messages include explicit exception traces or error codes, i.e., there is no textual description of the error.

Amount of Issues App List
15 (A7) AnntenaPod, (A12) XOWA, (A19) K-9 Mail, (A34) c:geo, (A44) Materialistic - Hacker News, (A46) Open Food, (A48) Tram Hunter, (A49) PocketHub for GitHub,

Examples

AntennaPod

Category:
Video Players and Editors
v 4.6
Scenario: To add a podcast without internet connection
This video shows an example of an inconsistent message, at 12th second, the user clicks on subscribe to a new podcast, once the user has done this a new notification is shown saying that there are 0 from 1 downloads succesfully executed. This is an example of an Inconsistent message due to the user is performing a subscription task and the message talks about downloads.

The following code snippets show the classes and files that are involved in the generation of the previuos issue.

To start reviewing this example we can see in the following snippet the assignment of the layout buttons to local variables. At line 53 we can see what happen when the “Browse gpodder.net” button is selected.

src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java

43. Button butBrowserGpoddernet = (Button) root.findViewById(R.id.butBrowseGpoddernet);
    Button butSearchFyyd = (Button) root.findViewById(R.id.butSearchFyyd);
    Button butOpmlImport = (Button) root.findViewById(R.id.butOpmlImport);
    Button butConfirm = (Button) root.findViewById(R.id.butConfirm);
    
    final MainActivity activity = (MainActivity) getActivity();
    activity.getSupportActionBar().setTitle(R.string.add_feed_label);
    
    butSearchITunes.setOnClickListener(v -> activity.loadChildFragment(new ItunesSearchFragment()));
    
53. butBrowserGpoddernet.setOnClickListener(v -> activity.loadChildFragment(new GpodnetMainFragment()));

From the previous snippet we land on “GpodnetMainFragment” that in “onCreateMethod” creates an instance of the adapter that will populate the Podcasts listview

src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java

    View root = inflater.inflate(R.layout.pager_fragment, container, false);

    viewPager = (ViewPager)root.findViewById(R.id.viewpager);
35. GpodnetPagerAdapter pagerAdapter = new GpodnetPagerAdapter(getChildFragmentManager(), getResources());
    viewPager.setAdapter(pagerAdapter);

In the following snippet, we can see the definition of the adapter used in the previous snippet. The most important line in the following snippet belongs to “getItem” method in charge of react depending on the id received by parameter that belongs to the selected tab. In specific as we can see in the video at 13th second, the selected tab is “Top Podcasts”.

src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java

76. public GpodnetPagerAdapter(FragmentManager fm, Resources resources) {
        super(fm);
        this.resources = resources;
    }
    
    @Override
    public Fragment getItem(int i) {
        switch (i) {
            case POS_TAGS:
                return new TagListFragment();
            case POS_TOPLIST:
87.             return new PodcastTopListFragment();
            case POS_SUGGESTIONS:
                return new SuggestionListFragment();
            default:
                return null;
        }
    }

Now that we land on the method called in the previous snippet, we can see that this method calls the method “getPodcastToplist” from a service. this service is “GpodnetService”.

src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastTopListFragment.java

    public class PodcastTopListFragment extends PodcastListFragment {
        private static final String TAG = "PodcastTopListFragment";
        private static final int PODCAST_COUNT = 50;

        @Override
        protected List<GpodnetPodcast> loadPodcastData(GpodnetService service) throws GpodnetServiceException {
18.         return service.getPodcastToplist(PODCAST_COUNT);
        }
    }

src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java

    /**
     * Returns the toplist of podcast.
     *
     * @param count of elements that should be returned. Must be in range 1..100.
     * @throws IllegalArgumentException if count is out of range.
     */
    public List<GpodnetPodcast> getPodcastToplist(int count)
            throws GpodnetServiceException {
        if(count < 1 || count > 100) {
            throw new IllegalArgumentException("Count must be in range 1..100");
        }

        try {
            URL url = new URI(BASE_SCHEME, BASE_HOST, String.format(
                    "/toplist/%d.json", count), null).toURL();
            Request.Builder request = new Request.Builder().url(url);
            String response = executeRequest(request);

            JSONArray jsonArray = new JSONArray(response);
            return readPodcastListFromJSONArray(jsonArray);

        } catch (JSONException | MalformedURLException | URISyntaxException e) {
            e.printStackTrace();
            throw new GpodnetServiceException(e);
        }
    }

Text view where the exception message message will be shown.

src/main/res/layout/gpodnet_podcast_list.xml

    <TextView
31.     android:id="@+id/txtvError"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_margin="16dp"
        android:textAlignment="center"
        android:textSize="@dimen/text_size_small"
        android:visibility="gone"
        tools:visibility="visible"
        tools:text="Error message"
        tools:background="@android:color/holo_red_light" />

From the previous snippet we can see that the “gpodnet_podcast_list” layout defines the view where the error is shown.

src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java

79. View root = inflater.inflate(R.layout.gpodnet_podcast_list, container, false);

    gridView = (GridView) root.findViewById(R.id.gridView);
    progressBar = (ProgressBar) root.findViewById(R.id.progressBar);
83. txtvError = (TextView) root.findViewById(R.id.txtvError);

In this snippet the information is retrieved and loaded using the adapter, nevertheless as we already see in the previous files when the loadData method is called it tries to call “loadPodcastData” method that is implemented in the “PodcastTopListFragment”, that method ends throwing an exception that is catch in this method and the message is saved into “exception” variable.

src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java

    protected abstract List<GpodnetPodcast> loadPodcastData(GpodnetService service) throws GpodnetServiceException;

    protected final void loadData() {
        AsyncTask<Void, Void, List<GpodnetPodcast>> loaderTask = new AsyncTask<Void, Void, List<GpodnetPodcast>>() {
            volatile Exception exception = null;

            @Override
            protected List<GpodnetPodcast> doInBackground(Void... params) {
                GpodnetService service = null;
                try {
                    service = new GpodnetService();
                    return loadPodcastData(service);
                } catch (GpodnetServiceException e) {
115.                exception = e;
                    e.printStackTrace();
                    return null;
                } finally {
                    if (service != null) {
                        service.shutdown();
                    }
                }
            }

Finally if the “exception” variable is not null, the textView will be filled with the exception message.

src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java

147. txtvError.setText(getString(R.string.error_msg_prefix) + exception.getMessage());