安卓开发问题汇总(一)

54 阅读4分钟

安卓开发问题汇总

Unexpected lock protocol found in lock file. Expected 3, found 37.

错误描述 在项目构建时报错:Unexpected lock protocol found in lock file. Expected 3, found 37.

原因 通常是Android Studio或电脑意外关闭引起的,具体原理未知。

解决方法 删除C盘用户目录下的.gradle文件,重启Android Studio。

TextView解决中英文混排自动换行

解决办法:自定义TextView解决中英文混排自动换行

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.widget.TextView;

/**
 *  
 */
public class JustifyTextView extends TextView {

    private int mLineY;
    private int mViewWidth;
    public static final String TWO_CHINESE_BLANK = "  ";

    public JustifyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
            int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        TextPaint paint = getPaint();
        paint.setColor(getCurrentTextColor());
        paint.drawableState = getDrawableState();
        mViewWidth = getMeasuredWidth();
        String text = getText().toString();
        mLineY = 0;
        mLineY += getTextSize();
        Layout layout = getLayout();

        // layout.getLayout()在4.4.3出现NullPointerException
        if (layout == null) {
            return;
        }

        Paint.FontMetrics fm = paint.getFontMetrics();

        int textHeight = (int) (Math.ceil(fm.descent - fm.ascent));
        textHeight = (int) (textHeight * layout.getSpacingMultiplier() + layout
                .getSpacingAdd());
        //解决了最后一行文字间距过大的问题
        for (int i = 0; i < layout.getLineCount(); i++) {
            int lineStart = layout.getLineStart(i);
            int lineEnd = layout.getLineEnd(i);
            float width = StaticLayout.getDesiredWidth(text, lineStart,
                    lineEnd, getPaint());
            String line = text.substring(lineStart, lineEnd);

            if(i < layout.getLineCount() - 1) {
                if (needScale(line)) {
                    drawScaledText(canvas, lineStart, line, width);
                } else {
                    canvas.drawText(line, 0, mLineY, paint);
                }
            } else {
                canvas.drawText(line, 0, mLineY, paint);
            }
            mLineY += textHeight;
        }
    }

    private void drawScaledText(Canvas canvas, int lineStart, String line,
            float lineWidth) {
        float x = 0;
        if (isFirstLineOfParagraph(lineStart, line)) {
            String blanks = "  ";
            canvas.drawText(blanks, x, mLineY, getPaint());
            float bw = StaticLayout.getDesiredWidth(blanks, getPaint());
            x += bw;

            line = line.substring(3);
        }

        int gapCount = line.length() - 1;
        int i = 0;
        if (line.length() > 2 && line.charAt(0) == 12288
                && line.charAt(1) == 12288) {
            String substring = line.substring(0, 2);
            float cw = StaticLayout.getDesiredWidth(substring, getPaint());
            canvas.drawText(substring, x, mLineY, getPaint());
            x += cw;
            i += 2;
        }

        float d = (mViewWidth - lineWidth) / gapCount;
        for (; i < line.length(); i++) {
            String c = String.valueOf(line.charAt(i));
            float cw = StaticLayout.getDesiredWidth(c, getPaint());
            canvas.drawText(c, x, mLineY, getPaint());
            x += cw + d;
        }
    }

    private boolean isFirstLineOfParagraph(int lineStart, String line) {
        return line.length() > 3 && line.charAt(0) == ' '
                && line.charAt(1) == ' ';
    }

    private boolean needScale(String line) {
        if (line == null || line.length() == 0) {
            return false;
        } else {
            return line.charAt(line.length() - 1) != '\n';
        }
    }

}

使用

<com.hxtx.august.tools.JustifyTextView  
android:id="@+id/tv_fm_ftp_path"  
android:layout_width="wrap_content"  
android:layout_height="wrap_content"  
android:gravity="center_vertical"  
android:layout_marginStart="15dp"  
android:layout_marginEnd="15dp"  
android:text="路径:"  
android:textSize="15sp"  
tools:ignore="RtlSymmetry" />

listview的item的点击事件与checkbox点击时间冲突

设置checkbox属性

android:focusable="false" //因为checkBox的点击事件优先级高于listview的点击事件

<CheckBox  
    android:id="@+id/cb_folder_content_checkBox"  
    android:button="@null"  
    android:layout_width="24dp"  
    android:layout_height="24dp"  
    android:focusable="false"  
    android:background="@drawable/check_style"  
/>

APP本地下载文件出错

image.png

java.lang.RuntimeException: java.nio.file.NoSuchFileException: /data/user/0/com.hxtx.august/files/FTPData/README.md

这是因为没有找到这个路径和文件,应该判断一下有没有这个文件夹

File localFolder = new File(androidAppUrl + "/FTPData");  
if (!localFolder.exists()) {  
    localFolder.mkdirs();  
}

开子线程

// 需要执行一个方法
private void FtpDown(){
    // 开启一个子线程,进行网络操作,等待有返回结果,使用handler通知UI
    new Thread(networkTask).start();
}

// 在线程中写逻辑
Runnable networkTask = new Runnable() {
    @Override
    public void run() {
        try {
            String download = FileUtils.GetFtpPath(FtpActivity.this);
            downloadTv.setText("下载中...");
            // 回调成功
            Message msg = Message.obtain();
            msg.what = 1;
            msg.obj = e;
            handler.sendMessage(msg);
            // 如果传递数据可以这么写,result 是一个数据(对象或者列表)
            Message message = handler.obtainMessage(0x001, fileContent);
            handler.sendMessage(message);
        }catch (Exception e){
            // 回调失败
            Log.e(TAG,"出现异常----->>"+e.getMessage());
            Message msg = Message.obtain();
            msg.what = 1;
            msg.obj = e.getMessage();
            handler.sendMessage(msg);
            // 也可以这么写
            handler.sendEmptyMessage(0x002);
        }
    }
}

//用来接收子线程回调的结果
Handler handler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        // 如果传递的是数据,则需要这么解析
        List<String> fileContent = (List<String>) msg.obj;
        
        switch (msg.what) {
            case 1://异常
                String error = (String) msg.obj;
                downloadTv.setText("出现异常-->"+error);
                break;
            case 2://成功
                String result = (String) msg.obj;
                downloadTv.setText(result);
                break;
        }
    }
};

页面跳转并传递数据

传递字符串

发送页面

Intent TestWifiIntent = new Intent(FtpManageAction.this, SinglePageAction.class);  
TestWifiIntent.putExtra("UrlData","file:///storage/emulated/0/Download/sample.csv");  
startActivity(TestWifiIntent);

接受页面

Intent intent = getIntent();//获取intent对象
String csvFilePath = intent.getStringExtra("UrlData");

当路径包含中文时,FTP读取FTP服务器列表出问题

解决办法:将路径转换为ISO-8859-1编码

String isoPath = new String(path.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);  
FTPFile[] files = ftpClient.listFiles(isoPath);

读取FTP内容,带进度

// 进度  
long step = ftpFile.getSize() / 100;  
long process = 0;  
long currentSize = 0;  
byte[] b = new byte[1024];  
int length;  
InputStream inputStream = ftpClient.retrieveFileStream(currentPath);  
if(inputStream!=null){  
    while ((length = inputStream.read(b)) != -1) {  
        // 下载文件  
        buffOut.write(b, 0, length);  
        currentSize = currentSize + length;  
        if (currentSize / step != process) {  
            process = currentSize / step;  
            //每隔%5的进度返回一次  
            if (process % 5 == 0) {  
                Log.d("IVESTAG", "ftp文件正在下载: "+process);  
            }  
        }  
    }  
    Message msg = Message.obtain();  
    msg.what = 1;  
    msg.obj = localFolder;  
    handlerFTPDownloadSingleData.sendMessage(msg);  
    // 关闭文件流  
    buffOut.close();  
    inputStream.close();  
    // 此方法是来确保流处理完毕,如果没有此方法,可能会造成现程序死掉  
    // if (ftpClient.completePendingCommand()) {  
    // Log.d("IVESTAG", "1ftp文件下载成功: "+ new File(localPath));  
    // } else {  
    // Log.d("IVESTAG", "2ftp文件下载失败: ");  
    // }
} else {  
    Message msg = Message.obtain();  
    msg.what = 0;  
    msg.obj = "文件空,未读到数据";  
    handlerFTPDownloadSingleData.sendMessage(msg);  
}

问题记录

open failed: EISDIR (Is a directory)

操作错误,这是一个文件夹而不是一个文件。

open failed: EEXIST (File exists)

安卓Android的Textview显示问题:一行没显示满就换行

设置Textview的属性android:breakStrategy为simple

<TextView  
    android:id="@+id/tv_folder_content_item_name"  
    android:layout_width="match_parent"  
    android:layout_height="wrap_content"  
    android:gravity="center_vertical"  
    android:breakStrategy="simple"  
    android:text="文本框"  
    android:textSize="15sp"
/>

预览CSV文件

// 浏览器预览
Intent TestWifiIntent = new Intent(FtpManageAction.this, SinglePageAction.class);  
TestWifiIntent.putExtra("UrlData",localFile);  
startActivity(TestWifiIntent);  

// WPS预览
Uri file = FileProvider.getUriForFile(FtpManageAction.this, "com.hxtx.august.fileprovider", localFile);  
Intent intent = new Intent();  
List<ResolveInfo> resInfoList = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);  
for (ResolveInfo resolveInfo : resInfoList) {  
    String packageName = resolveInfo.activityInfo.packageName;  
    grantUriPermission(packageName, file, Intent.FLAG_GRANT_READ_URI_PERMISSION);  
}  
intent.setAction(Intent.ACTION_VIEW);  
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(file.toString()));  
intent.setDataAndType(file, mimeType);  
startActivity(intent);

数据类型转换

// 字符串转换为长整型(long)
String str = "12345";
long num = Long.parseLong(str);
System.out.println(num);
 
 // 字符串转换为长整型(long)
String str = "12345";
long num = Long.parseLong(str);
System.out.println(num);

// 字符串分割
String str = "apple/banana/cherry";
String[] parts = str.split("/");
for (String part : parts){
    System.out.println(part);
}