代码改变世界

记一笔自己的sb行为---工作中修改第一个bug

2012-08-15 15:27  ...平..淡...  阅读(438)  评论(0编辑  收藏  举报

问题1:文件管理器与图库中队同一张图片的删除操作未同步,导致文件管理器以蓝牙分享图片是报错!

描述:

【操作步骤】

1.文件管理器打开某张图片-home返回idle

2.图库中删除文件管理器中的图片->home->文件管理器->仍进入图片预览缓存界面->分享选择蓝牙发送

【实际结果】蓝牙进程意外停止

【预期结果】未知文件(因为实际已删除,只是缓存)不能发送

【log文件】

根据报错的情况在源码中找到insertShare方法:

View Code
  1  519     private void insertShare(Cursor cursor, int arrayPos) {
  2  520         BluetoothOppShareInfo info = new BluetoothOppShareInfo(
  3  521                 cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare._ID)),
  4  522                 cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare.URI)),
  5  523                 cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare.FILENAME_HINT)),
  6  524                 cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare._DATA)),
  7  525                 cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare.MIMETYPE)),
  8  526                 cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.DIRECTION)),
  9  527                 cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare.DESTINATION)),
 10  528                 cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.VISIBILITY)),
 11  529                 cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.USER_CONFIRMATION)),
 12  530                 cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.STATUS)),
 13  531                 cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TOTAL_BYTES)),
 14  532                 cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.CURRENT_BYTES)),
 15  533                 cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP)),
 16  534                 cursor.getInt(cursor.getColumnIndexOrThrow(Constants.MEDIA_SCANNED)) != Constants.MEDIA_SCANNED_NOT_SCANNED);
 17  535 
 18  536         if (V) {
 19  537             Log.v(TAG, "Service adding new entry");
 20  538             Log.v(TAG, "ID      : " + info.mId);
 21  539             // Log.v(TAG, "URI     : " + ((info.mUri != null) ? "yes" : "no"));
 22  540             Log.v(TAG, "URI     : " + info.mUri);
 23  541             Log.v(TAG, "HINT    : " + info.mHint);
 24  542             Log.v(TAG, "FILENAME: " + info.mFilename);
 25  543             Log.v(TAG, "MIMETYPE: " + info.mMimetype);
 26  544             Log.v(TAG, "DIRECTION: " + info.mDirection);
 27  545             Log.v(TAG, "DESTINAT: " + info.mDestination);
 28  546             Log.v(TAG, "VISIBILI: " + info.mVisibility);
 29  547             Log.v(TAG, "CONFIRM : " + info.mConfirm);
 30  548             Log.v(TAG, "STATUS  : " + info.mStatus);
 31  549             Log.v(TAG, "TOTAL   : " + info.mTotalBytes);
 32  550             Log.v(TAG, "CURRENT : " + info.mCurrentBytes);
 33  551             Log.v(TAG, "TIMESTAMP : " + info.mTimestamp);
 34  552             Log.v(TAG, "SCANNED : " + info.mMediaScanned);
 35  553         }
 36  554 
 37  555         mShares.add(arrayPos, info);
 38  556 
 39  557         /* Mark the info as failed if it's in invalid status */
 40  558         if (info.isObsolete()) {
 41  559             Constants.updateShareStatus(this, info.mId, BluetoothShare.STATUS_UNKNOWN_ERROR);
 42  560         }
 43  561         /*
 44  562          * Add info into a batch. The logic is
 45  563          * 1) Only add valid and readyToStart info
 46  564          * 2) If there is no batch, create a batch and insert this transfer into batch,
 47  565          * then run the batch
 48  566          * 3) If there is existing batch and timestamp match, insert transfer into batch
 49  567          * 4) If there is existing batch and timestamp does not match, create a new batch and
 50  568          * put in queue
 51  569          */
 52  570 
 53  571         if (info.isReadyToStart()) {
 54  572             if (info.mDirection == BluetoothShare.DIRECTION_OUTBOUND) {
 55  573                 /* check if the file exists */
 56  574                 try {
 57  575                     InputStream i = getContentResolver().openInputStream(Uri.parse(info.mUri));
 58  576                     //i.close();
 59  577                 } catch (FileNotFoundException e) {
 60  578                     Log.e(TAG, "Can't open file for OUTBOUND info " + info.mId);
 61  579                     Constants.updateShareStatus(this, info.mId, BluetoothShare.STATUS_BAD_REQUEST);
 62  580                     return;
 63  581                 } catch (IOException ex) {
 64  582                     Log.e(TAG, "IO error when close file for OUTBOUND info " + info.mId);
 65  583                     return;
 66  584                 }
 67  585             }
 68  586             if (mBatchs.size() == 0) {
 69  587                 BluetoothOppBatch newBatch = new BluetoothOppBatch(this, info);
 70  588                 newBatch.mId = mBatchId;
 71  589                 mBatchId++;
 72  590                 mBatchs.add(newBatch);
 73  591                 if (info.mDirection == BluetoothShare.DIRECTION_OUTBOUND) {
 74  592                     if (V) Log.v(TAG, "Service create new Batch " + newBatch.mId
 75  593                                 + " for OUTBOUND info " + info.mId);
 76  594                     mTransfer = new BluetoothOppTransfer(this, mPowerManager, newBatch);
 77  595                 } else if (info.mDirection == BluetoothShare.DIRECTION_INBOUND) {
 78  596                     if (V) Log.v(TAG, "Service create new Batch " + newBatch.mId
 79  597                                 + " for INBOUND info " + info.mId);
 80  598                     mServerTransfer = new BluetoothOppTransfer(this, mPowerManager, newBatch,
 81  599                             mServerSession);
 82  600                 }
 83  601 
 84  602                 if (info.mDirection == BluetoothShare.DIRECTION_OUTBOUND && mTransfer != null) {
 85  603                     if (V) Log.v(TAG, "Service start transfer new Batch " + newBatch.mId
 86  604                                 + " for info " + info.mId);
 87  605                     mTransfer.start();
 88  606                 } else if (info.mDirection == BluetoothShare.DIRECTION_INBOUND
 89  607                         && mServerTransfer != null) {
 90  608                     if (V) Log.v(TAG, "Service start server transfer new Batch " + newBatch.mId
 91  609                                 + " for info " + info.mId);
 92  610                     mServerTransfer.start();
 93  611                 }
 94  612 
 95  613             } else {
 96  614                 int i = findBatchWithTimeStamp(info.mTimestamp);
 97  615                 if (i != -1) {
 98  616                     if (V) Log.v(TAG, "Service add info " + info.mId + " to existing batch "
 99  617                                 + mBatchs.get(i).mId);
100  618                     mBatchs.get(i).addShare(info);
101  619                 } else {
102  620                     // There is ongoing batch
103  621                     BluetoothOppBatch newBatch = new BluetoothOppBatch(this, info);
104  622                     newBatch.mId = mBatchId;
105  623                     mBatchId++;
106  624                     mBatchs.add(newBatch);
107  625                     if (V) Log.v(TAG, "Service add new Batch " + newBatch.mId + " for info " +
108  626                             info.mId);
109  627                     if (Constants.USE_TCP_DEBUG && !Constants.USE_TCP_SIMPLE_SERVER) {
110  628                         // only allow  concurrent serverTransfer in debug mode
111  629                         if (info.mDirection == BluetoothShare.DIRECTION_INBOUND) {
112  630                             if (V) Log.v(TAG, "TCP_DEBUG start server transfer new Batch " +
113  631                                     newBatch.mId + " for info " + info.mId);
114  632                             mServerTransfer = new BluetoothOppTransfer(this, mPowerManager,
115  633                                     newBatch, mServerSession);
116  634                             mServerTransfer.start();
117  635                         }
118  636                     }
119  637                 }
120  638             }
121  639         }
122  640     }

 

而问题则产生于下面这个if 语句中,摘录如下:

 572             if (info.mDirection == BluetoothShare.DIRECTION_OUTBOUND) {
 573                 /* check if the file exists */
 574                 try {
 575                     InputStream i = getContentResolver().openInputStream(Uri.parse(info.mUri));  //问题出在这句
 576                     //i.close();
 577                 } catch (FileNotFoundException e) {
 578                     Log.e(TAG, "Can't open file for OUTBOUND info " + info.mId);
 579                     Constants.updateShareStatus(this, info.mId, BluetoothShare.STATUS_BAD_REQUEST);
 580                     return;
 581                 } catch (IOException ex) {
 582                     Log.e(TAG, "IO error when close file for OUTBOUND info " + info.mId);
 583                     return;
 584                 }
 585             }

教训:我天真地以为在catch里面找,结果找了不知道多少天了,后来老大果断说try里,我就惊呆了,我笨死啦笨死啦!!!以后要记住这次严峻的教训了....

cb改正方案(初步未fixed):

在try中对uri进行判断,判断是否存在相应 IContentProvider 对象与其关联。

1   Uri u = Uri.parse(info.mFileUri);
2   if(context.getContentResolver().acquireExistingProvider(u) == null){
3        Looper.prepare();
4        Toast.makeText(getApplicationContext(), "Unknown file, cannot be send", Toast.LENGTH_SHORT).show();
5        Looper.loop();
6        info.mFileType = null;
7   }
8   else
9        info.mFileType = context.getContentResolver().getType(u);

 

我以为结果没有报错了~~!!!(当时,我进行的操作只有上面写的操作步骤,没有进行重新打开蓝牙等操作)

但是,后来重新打开蓝牙,发现直接弹出"Unknown file, cannot be send",说明打开蓝牙时,也运行BluetoothOppService类的insertShare方法中的if语句。说明打开蓝牙时,也不存在与其关联的IContentProvider对象。

我查看了源码里BluetoothOppService类中对insertShare方法的调用,发现有传递cursor对象。因此我认为,刚开始打开蓝牙时,获取到的cursor值肯定是null,所以我添加了对cursor对象的判断,结果成功fixed.

fixed Bug 如下所示:


1
Uri u = Uri.parse(info.mFileUri); 2 if(cursor != null && context.getContentResolver().acquireExistingProvider(u) == null){ 3 Looper.prepare(); 4 Toast.makeText(getApplicationContext(), "Unknown file, cannot be send", Toast.LENGTH_SHORT).show(); 5 Looper.loop(); 6 info.mFileType = null; 7 } 8 else 9 info.mFileType = context.getContentResolver().getType(u);

知识点:Android:在Service中使用Toast

在Service中使用Toast,我原本以为和在Activity中一样,可以直接用,但发现没有反应。

解决方法1:通过Handler处理。

 1 public class TestService extends  Service {
 2      private Handler handler;
 3      @Override
 4      public IBinder onBind(Intent intent){
 5          return null;
 6      }
 7      
 8      @Override
 9      public void onCreate(){
10          handler = new Handler(Looper.getMainLooper());                        
11          handler.post(new Runnable() {  
12               @Override  
13               public void run() {  
14                  Toast.makeText(getApplicationContext(), "Test",Toast.LENGTH_SHORT).show();  
15               }  
16          });
17      }
18  }

 解决方法2:通过Looper.prepare()和Looper.loop()处理,如fixed Bug中所示。

 

关于原理,可以查阅

1.深入理解之 Android Handler(相当好!!!)

2.android的消息处理机制(图+源码分析)——Looper,Handler,Message