二进制 XML 文件第 13 行:在扩展 VideoView 的类上膨胀类时出错

Posted

技术标签:

【中文标题】二进制 XML 文件第 13 行:在扩展 VideoView 的类上膨胀类时出错【英文标题】:Binary XML file line #13: Error inflating class on a class that extends VideoView 【发布时间】:2016-02-14 22:47:23 【问题描述】:

我创建了一个自定义 VideoView 类,它扩展了 VideoView 并声明了三个构造函数:

package com.tibo.webtv;

import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import org.apache.http.conn.ConnectTimeoutException;
import com.framework.utilityframe.log.log;
import com.framework.utilityframe.utility.utility;
import com.tibo.webtv.activities.PlayerActivity;
import com.tibo.webtv.database.objects.ServerResponseObject;
import com.tibo.webtv.database.objects.TVChannelObject;
import com.tibo.webtv.global.Global;
import com.tibo.webtv.util.TiboCacheKey;
import com.tibo.webtv.util.Util;
import com.tibo.webtv.web.TiboLog;
import com.tibo.webtv.web.WebHelper3;
import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnInfoListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.AttributeSet;
import android.widget.Toast;
import android.widget.VideoView;

public class CustomVideoView extends VideoView implements OnPreparedListener,OnErrorListener,OnInfoListener,OnCompletionListener

    private long buffer_start_time;
    private long buffer_end_time;
    private String token;
    private Handler handler = new Handler();

    public CustomVideoView(Context context) 
    
        super(context); 
    
    public CustomVideoView(Context context, AttributeSet attrs) 
    
        super(context, attrs);
        setOnPreparedListener(this);
        setOnErrorListener(this);
        setOnInfoListener(this);
    

    public CustomVideoView(Context context, AttributeSet attrs, int defStyle) 
    
        super(context, attrs, defStyle);
    

    public TVChannelObject getCurrentPlayingChannel() 
    
        return current_playing_channel;
    
    public void setCurrentPlayingChannel(TVChannelObject current_playing_channel) 
    
        this.current_playing_channel = current_playing_channel;
    
    public TVChannelObject getPreviousPlayingChannel() 
    
        return previous_playing_channel;
    
    public void setPreviousPlayingChannel(TVChannelObject previous_playing_channel)
    
        this.previous_playing_channel = previous_playing_channel;
    

    private TVChannelObject current_playing_channel;
    private TVChannelObject previous_playing_channel;
    private String access_way;
    private Date stream_started_time;
    private long stream_play_time;
    private boolean FLAG_STREAM_STARTED;
    private String error_code;



    @Override
    public void stopPlayback()
    
        new WatchingTime().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        super.stopPlayback();
    
    @Override
    public void onPrepared(MediaPlayer mp) 
    
        log.i("on Prepared");
        FLAG_STREAM_STARTED = true;
        stream_started_time = Calendar.getInstance().getTime();
        mp.start();
    

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) 
    
        log.i("on onError");
        error_code = what + "";

        Toast.makeText(getContext(),getContext().getString(R.string.videoerror) + " " + error_code, Toast.LENGTH_LONG).show();
        new BlackScreenError().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

        if(what == MediaPlayer.MEDIA_ERROR_SERVER_DIED)
            mp.reset();

        else if(what == MediaPlayer.MEDIA_ERROR_UNKNOWN)
            mp.reset();

        return true;
    ;

    @Override
    public boolean onInfo(MediaPlayer mp, int what, int extra) 
    
        log.i("on onInfo");
        if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START) 
        
            buffer_start_time = System.currentTimeMillis();
        
        else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END) 
           
            buffer_end_time = System.currentTimeMillis();                           
            new Buffering_Problem().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
            FLAG_STREAM_STARTED = false;
        
        return true;
    

    @Override
    public void onCompletion(MediaPlayer mp) 
    
        super.setOnCompletionListener(this);
        new WatchingTime().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    

    public void start(TVChannelObject channel)
    
        super.start();
        if(current_playing_channel == null)
        
            current_playing_channel =  channel;
        
        else
        
            previous_playing_channel = current_playing_channel;
            current_playing_channel = channel;
            Global.shared_preference.setValue(TiboCacheKey.PLAYING_CHANNEL, current_playing_channel.number);
            Global.shared_preference.setValue(TiboCacheKey.LAST_CHANNEL_VIEWED, previous_playing_channel.number);
        
        this.access_way = "-1";
    

    public synchronized void start(TVChannelObject channel,String access_way)
    
        super.start();

        if(isPlaying())
        
            this.stopPlayback();
        
        if(current_playing_channel == null)
        
            current_playing_channel =  channel;
        
        else
        
            previous_playing_channel = current_playing_channel;
            current_playing_channel = channel;

            Global.shared_preference.setValue(TiboCacheKey.PLAYING_CHANNEL, current_playing_channel.number);
            if(!utility.stringCompareIgnoreCase(current_playing_channel.videotype, "2"))
            
                Global.shared_preference.setValue(TiboCacheKey.LAST_CHANNEL_VIEWED, current_playing_channel.number);
            
        
        this.access_way = access_way;

        if (current_playing_channel.token.trim().toLowerCase(Locale.getDefault()).toCharArray()[0] == '1') 
        
            log.i("Channel with token!!!");
            new PlayStreamWithToken().execute("");
         
        else 
        
            log.i("Channel without token!!!");
            token = "";     
            setVideoURI(Uri.parse(current_playing_channel.url));
            start();
            closePlayerActivityAfterSpecificTime(1000 * 60 * 120);
        
        new ChannelHits().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    

    private void closePlayerActivityAfterSpecificTime(int milliseconds) 
    
        handler.removeCallbacks(ClosePlayerActivity);
        handler.postDelayed(ClosePlayerActivity, milliseconds);
    

    private Runnable ClosePlayerActivity = new Runnable() 
        public void run() 
            new ClosePlayerActivityAfterInActivity().execute(0);
        
    ;

    private class PlayStreamWithToken extends AsyncTask<String, String, String> 
    
        ServerResponseObject<String> token_response = null;
        @Override
        protected void onPreExecute()
        
            super.onPreExecute();
        

        @Override
        protected String doInBackground(String... params)
        
            Thread.currentThread().setName("get token");
            log.i("Channel with token!!!");
            log.i("token url",current_playing_channel.TokenUrl);
            try 
            
                token_response = WebHelper3.getToken(current_playing_channel.TokenUrl);

                if(token_response != null)
                
                    if(token_response.status_code < 300)
                    
                        if(!utility.stringCompareIgnoreCase(token_response.extra_data, ""))
                        
                            token = token_response.extra_data;
                            log.i("token",token);
                            return Util.RESPONSE_OK;
                        
                    
                    else
                    
                        //TODO handle error
                        return Util.RESPONSE_ERROR;
                    
                
                else
                
                    //TODO hanlde
                    token = "";
                    return Util.RESPONSE_NULL;
                
             
            catch (ConnectTimeoutException e) 
            
                // TODO Auto-generated catch block
                e.printStackTrace();
                return Util.RESPONSE_TIME_OUT;
            
            return "";
        

        protected void onPostExecute(String response) 
        
            if(utility.stringCompareIgnoreCase(response, Util.RESPONSE_OK))
            
                String channel_url_to_play = current_playing_channel.url;
                channel_url_to_play += token.trim();
                log.i("url to play with token :", channel_url_to_play);
                setVideoURI(Uri.parse(channel_url_to_play));
                start();
                closePlayerActivityAfterSpecificTime(1000 * 60 * 120);
            
            else if(utility.stringCompareIgnoreCase(response, Util.RESPONSE_TIME_OUT))
            
                //TODO handle timout and null
            
        
    
    private class ClosePlayerActivityAfterInActivity extends AsyncTask<Integer, Integer, Integer> 
    
        @Override
        protected Integer doInBackground(Integer... params) 
        
            Thread.currentThread().setName("SleepTask");
            return 0;
        
        @Override
        protected void onPostExecute(Integer result) 
                   
            if (isPlaying()) 
            
                stopPlayback();
            
            PlayerActivity.this_activity.finish();
        
    
    private class Buffering_Problem extends AsyncTask<Integer, Integer, Integer> 
    
        @Override
        protected void onPreExecute()
        
            super.onPreExecute();
        

        @Override
        protected Integer doInBackground(Integer... params)
        
            Thread.currentThread().setName("Buffering problem Custom VideoView");

            if (FLAG_STREAM_STARTED)
            
                TiboLog.logBufferingError(TiboLog.LIVE_TV_BUFFER_ERRORS,current_playing_channel.number, buffer_end_time - buffer_start_time, "Warning");
            
            else
            
                TiboLog.logBufferingError(TiboLog.LIVE_TV_BUFFER_ERRORS,current_playing_channel.number, buffer_end_time - buffer_start_time, "Error");
            
            buffer_end_time = 0;
            buffer_start_time = 0;
            return 0;
        
    

    private class BlackScreenError extends AsyncTask<Integer, Integer, Integer> 
    
        @Override
        protected void onPreExecute() 
        
            super.onPreExecute();
        

        @Override
        protected Integer doInBackground(Integer... params) 
        
            Thread.currentThread().setName("Black Screen Error");
            try 
            
                TiboLog.logSendError(TiboLog.LOGTYPE_ERROR,current_playing_channel.number, "Error Black Screen " + error_code);

            
            catch (Exception e) 
            
                e.printStackTrace();
            
            return 0;
        
    

    private class ChannelHits extends AsyncTask<Integer, Integer, Integer> 
    
        @Override
        protected void onPreExecute()
        
            super.onPreExecute();
        

        @Override
        protected Integer doInBackground(Integer... params)
        
            Thread.currentThread().setName("Channel Hit log");
            TiboLog.logChannelHit(TiboLog.LIVE_TV_HITS,current_playing_channel.number, access_way, previous_playing_channel.number);
            return 0;
        
    

    private class WatchingTime extends AsyncTask<Integer, Integer, Integer> 
    
        @Override
        protected void onPreExecute()
        
            super.onPreExecute();
        

        @Override
        protected Integer doInBackground(Integer... params)
        
            Thread.currentThread().setName("Watching Time Log");
            if(stream_started_time != null)
            
                long stream_ended_time = Calendar.getInstance().getTime().getTime();
                stream_play_time = stream_ended_time - stream_started_time.getTime();

                int playtime_in_seconds = (int) (stream_play_time)/1000;
                log.i("playtime_in_seconds",playtime_in_seconds+"");
                if (playtime_in_seconds >= 15 && playtime_in_seconds < 108000)
                
                    TiboLog.sendWatchingTime(TiboLog.LIVE_TV_WATCHING_TIME, current_playing_channel.number, playtime_in_seconds + "");
                
            
            return 0;
        
    


xml文件如下:

<RelativeLayout
    android:id="@+id/media_player_view"
    android:layout_
    android:layout_ >

    <com.tibo.webtv.CustomVideoView    --line 13
        android:id="@+id/surface_view"
        android:layout_
        android:layout_
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_gravity="center" />
</RelativeLayout>

当我在 android 4.1 上运行这个 apk 时,活动崩溃并且日志消息是:

       11-13 11:36:27.962: E/AndroidRuntime(1040): FATAL EXCEPTION: main
11-13 11:36:27.962: E/AndroidRuntime(1040): java.lang.RuntimeException: Unable to start activity ComponentInfocom.tibo.webtv/com.tibo.webtv.activities.PlayerActivity: android.view.InflateException: Binary XML file line #13: Error inflating class com.webtv.CustomVideoView
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.ActivityThread.access$600(ActivityThread.java:130)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.os.Handler.dispatchMessage(Handler.java:99)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.os.Looper.loop(Looper.java:137)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.ActivityThread.main(ActivityThread.java:4745)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at java.lang.reflect.Method.invokeNative(Native Method)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at java.lang.reflect.Method.invoke(Method.java:511)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at dalvik.system.NativeStart.main(Native Method)
11-13 11:36:27.962: E/AndroidRuntime(1040): Caused by: android.view.InflateException: Binary XML file line #13: Error inflating class com.webtv.CustomVideoView
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:698)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:749)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:256)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.Activity.setContentView(Activity.java:1867)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at com.tibo.webtv.activities.PlayerActivity.onCreate(PlayerActivity.java:188)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.Activity.performCreate(Activity.java:5008)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
11-13 11:36:27.962: E/AndroidRuntime(1040):     ... 11 more
11-13 11:36:27.962: E/AndroidRuntime(1040): Caused by: java.lang.ClassNotFoundException: com.webtv.CustomVideoView
11-13 11:36:27.962: E/AndroidRuntime(1040):     at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:61)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.createView(LayoutInflater.java:552)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:687)
11-13 11:36:27.962: E/AndroidRuntime(1040):     ... 22 more

我猜问题出在 OnInfoListener 上,因为当我删除它时一切正常。

【问题讨论】:

请发布完整的堆栈跟踪和CustomVideoView 类。 @MikeM。我更新了我的问题 ClassNotFoundException: com.webtv.CustomVideoView。你确定它不应该是com.tibo.webtv.CustomVideoView 我用xxxx隐藏包名 是的,我收集到了,但你的堆栈跟踪显示com.webtv.CustomVideoView。如果您最近更改了它(清理并)重建您的项目。 【参考方案1】:

问题在于包名。将您在 xml 中使用的完整限定类名称与您的类定义进行交叉检查。 简而言之,当您按下 ctrl+鼠标左键时,您应该被重定向到类定义。 应该是com.packagename.yourCustomclassName

【讨论】:

当我按下 CTRL+鼠标左键时,它会将我重定向到类定义,所以包名是正确的【参考方案2】:

就我而言,我已经删除了该属性 android:background,从那时起我没有收到任何 inflate 异常。

【讨论】:

以上是关于二进制 XML 文件第 13 行:在扩展 VideoView 的类上膨胀类时出错的主要内容,如果未能解决你的问题,请参考以下文章

无法启动活动 ComponentInfo 二进制 XML 文件第 13 行:膨胀类 com.google.android.material.appbar.MaterialToolbar 时出错

获取二进制 XML 文件第 141 行:尝试在空对象引用上调用虚拟方法“boolean java.lang.String.equals(java.lang.Object)”

二进制 XML 文件第 28 行:二进制 XML 文件第 28 行:膨胀类 <unknown> 时出错

android.view.InflateException:二进制 XML 文件第 15 行:二进制 XML 文件第 19 行:膨胀类片段时出错

Google Map API 问题:android.view.InflateException:二进制 XML 文件第 2 行:二进制 XML 文件第 2 行:膨胀类片段时出错

当我切换到包含片段的活动时应用程序崩溃(二进制 XML 文件第 10 行:二进制 XML 文件第 10 行:膨胀类片段时出错)