У меня была такая же проблема, и я исправил ее с помощью android:contentInset
Попробуйте с этим кодом:
<android.support.design.widget.CoordinatorLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
android:contentInsetEnd="50dp"
android:contentInsetLeft="50dp"
android:contentInsetRight="50dp"
android:contentInsetStart="50dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:contentInsetEnd="50dp"
app:contentInsetLeft="50dp"
app:contentInsetRight="50dp"
app:contentInsetStart="50dp"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_centerInParent="true"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dp"
android:text="@string/app_name_short"
android:textColor="#fff"
android:textSize="20dp" />
</LinearLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="@+id/main_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/app_bar_layout" />
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
Вы можете использовать org.apache.commons.io.IOUtils.copy
, чтобы скопировать содержимое InputStream в массив байтов, а затем повторно прочитать из массива байтов с помощью ByteArrayInputStream. Например ::
ByteArrayOutputStream baos = new ByteArrayOutputStream();
org.apache.commons.io.IOUtils.copy(in, baos);
byte[] bytes = baos.toByteArray();
// either
while (needToReadAgain) {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
yourReadMethodHere(bais);
}
// or
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
while (needToReadAgain) {
bais.reset();
yourReadMethodHere(bais);
}
Если вы используете реализацию InputStream
, вы можете проверить результат InputStream#markSupported()
, который говорит вам, можете ли вы использовать метод mark()
/ reset()
.
Если вы можете пометить поток во время чтения, а затем вызвать reset()
, чтобы вернуться к началу.
Если вы не можете, вам придется снова открыть поток.
Другим решением было бы преобразовать InputStream в массив байтов, а затем перебрать по массиву столько раз, сколько вам нужно. Вы можете найти несколько решений в этой статье Преобразование InputStream в байтовый массив в Java с использованием сторонних библиотек или нет. Предупреждение: если прочитанный контент слишком велик, вы можете столкнуться с некоторыми проблемами памяти.
Наконец, если вам нужно прочитать изображение, используйте:
BufferedImage image = ImageIO.read(new URL("http://www.example.com/images/toto.jpg"));
Используя ImageIO#read(java.net.URL)
также позволяет использовать кеш.
ImageIO#read(java.net.URL)
: некоторые веб-серверы и CDN могут отклонять голые вызовы (т. е. без агента пользователя, который заставляет сервер полагать, что вызов поступает из веб-браузера), сделанный с помощью ImageIO#read
. В этом случае, используя URLConnection.openConnection()
, устанавливая агент пользователя для этого соединения +, используя `ImageIO.read (InputStream), большую часть времени будет делать трюк.
– Clint Eastwood
10 August 2017 в 19:12
Как насчет:
if (stream.markSupported() == false) {
// lets replace the stream object
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(stream, baos);
stream.close();
stream = new ByteArrayInputStream(baos.toByteArray());
// now the stream should support 'mark' and 'reset'
}
В зависимости от того, откуда приходит InputStream, вы не сможете его сбросить. Вы можете проверить, поддерживаются ли mark()
и reset()
с помощью markSupported()
.
Если это так, вы можете вызвать reset()
в InputStream, чтобы вернуться к началу. Если нет, вам нужно снова прочитать InputStream из источника.
Преобразуйте входной поток в байты, а затем передайте его в функцию savefile, где вы собираете то же самое во входной поток. Также в исходной функции используйте байты для использования для других задач
Вы можете обернуть поток ввода с помощью PushbackInputStream. PushbackInputStream позволяет непрочитанным (« записать назад ») байты, которые уже были прочитаны, поэтому вы можете сделать это следующим образом:
public class StreamTest {
public static void main(String[] args) throws IOException {
byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
InputStream originalStream = new ByteArrayInputStream(bytes);
byte[] readBytes = getBytes(originalStream, 3);
printBytes(readBytes); // prints: 1 2 3
readBytes = getBytes(originalStream, 3);
printBytes(readBytes); // prints: 4 5 6
// now let's wrap it with PushBackInputStream
originalStream = new ByteArrayInputStream(bytes);
InputStream wrappedStream = new PushbackInputStream(originalStream, 10); // 10 means that maximnum 10 characters can be "written back" to the stream
readBytes = getBytes(wrappedStream, 3);
printBytes(readBytes); // prints 1 2 3
((PushbackInputStream) wrappedStream).unread(readBytes, 0, readBytes.length);
readBytes = getBytes(wrappedStream, 3);
printBytes(readBytes); // prints 1 2 3
}
private static byte[] getBytes(InputStream is, int howManyBytes) throws IOException {
System.out.print("Reading stream: ");
byte[] buf = new byte[howManyBytes];
int next = 0;
for (int i = 0; i < howManyBytes; i++) {
next = is.read();
if (next > 0) {
buf[i] = (byte) next;
}
}
return buf;
}
private static void printBytes(byte[] buffer) throws IOException {
System.out.print("Reading stream: ");
for (int i = 0; i < buffer.length; i++) {
System.out.print(buffer[i] + " ");
}
System.out.println();
}
}
Обратите внимание, что PushbackInputStream хранит внутренний буфер байтов, поэтому он действительно создает буфер в памяти, который содержит байты «записаны».
Зная этот подход, мы можем пойти дальше и объединить его с FilterInputStream. FilterInputStream хранит исходный входной поток в качестве делегата. Это позволяет создать новое определение класса, которое автоматически позволяет « непрочитанных » исходных данных. Определение этого класса следующее:
public class TryReadInputStream extends FilterInputStream {
private final int maxPushbackBufferSize;
/**
* Creates a <code>FilterInputStream</code>
* by assigning the argument <code>in</code>
* to the field <code>this.in</code> so as
* to remember it for later use.
*
* @param in the underlying input stream, or <code>null</code> if
* this instance is to be created without an underlying stream.
*/
public TryReadInputStream(InputStream in, int maxPushbackBufferSize) {
super(new PushbackInputStream(in, maxPushbackBufferSize));
this.maxPushbackBufferSize = maxPushbackBufferSize;
}
/**
* Reads from input stream the <code>length</code> of bytes to given buffer. The read bytes are still avilable
* in the stream
*
* @param buffer the destination buffer to which read the data
* @param offset the start offset in the destination <code>buffer</code>
* @aram length how many bytes to read from the stream to buff. Length needs to be less than
* <code>maxPushbackBufferSize</code> or IOException will be thrown
*
* @return number of bytes read
* @throws java.io.IOException in case length is
*/
public int tryRead(byte[] buffer, int offset, int length) throws IOException {
validateMaxLength(length);
// NOTE: below reading byte by byte instead of "int bytesRead = is.read(firstBytes, 0, maxBytesOfResponseToLog);"
// because read() guarantees to read a byte
int bytesRead = 0;
int nextByte = 0;
for (int i = 0; (i < length) && (nextByte >= 0); i++) {
nextByte = read();
if (nextByte >= 0) {
buffer[offset + bytesRead++] = (byte) nextByte;
}
}
if (bytesRead > 0) {
((PushbackInputStream) in).unread(buffer, offset, bytesRead);
}
return bytesRead;
}
public byte[] tryRead(int maxBytesToRead) throws IOException {
validateMaxLength(maxBytesToRead);
ByteArrayOutputStream baos = new ByteArrayOutputStream(); // as ByteArrayOutputStream to dynamically allocate internal bytes array instead of allocating possibly large buffer (if maxBytesToRead is large)
// NOTE: below reading byte by byte instead of "int bytesRead = is.read(firstBytes, 0, maxBytesOfResponseToLog);"
// because read() guarantees to read a byte
int nextByte = 0;
for (int i = 0; (i < maxBytesToRead) && (nextByte >= 0); i++) {
nextByte = read();
if (nextByte >= 0) {
baos.write((byte) nextByte);
}
}
byte[] buffer = baos.toByteArray();
if (buffer.length > 0) {
((PushbackInputStream) in).unread(buffer, 0, buffer.length);
}
return buffer;
}
private void validateMaxLength(int length) throws IOException {
if (length > maxPushbackBufferSize) {
throw new IOException(
"Trying to read more bytes than maxBytesToRead. Max bytes: " + maxPushbackBufferSize + ". Trying to read: " +
length);
}
}
}
Этот класс имеет два метода. Один для чтения в существующий буфер (defintion аналогичен вызову public int read(byte b[], int off, int len)
класса InputStream). Второй, который возвращает новый буфер (это может быть более эффективным, если размер буфера для чтения неизвестен).
Теперь посмотрим наш класс в действии:
public class StreamTest2 {
public static void main(String[] args) throws IOException {
byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
InputStream originalStream = new ByteArrayInputStream(bytes);
byte[] readBytes = getBytes(originalStream, 3);
printBytes(readBytes); // prints: 1 2 3
readBytes = getBytes(originalStream, 3);
printBytes(readBytes); // prints: 4 5 6
// now let's use our TryReadInputStream
originalStream = new ByteArrayInputStream(bytes);
InputStream wrappedStream = new TryReadInputStream(originalStream, 10);
readBytes = ((TryReadInputStream) wrappedStream).tryRead(3); // NOTE: no manual call to "unread"(!) because TryReadInputStream handles this internally
printBytes(readBytes); // prints 1 2 3
readBytes = ((TryReadInputStream) wrappedStream).tryRead(3);
printBytes(readBytes); // prints 1 2 3
readBytes = ((TryReadInputStream) wrappedStream).tryRead(3);
printBytes(readBytes); // prints 1 2 3
// we can also call normal read which will actually read the bytes without "writing them back"
readBytes = getBytes(wrappedStream, 3);
printBytes(readBytes); // prints 1 2 3
readBytes = getBytes(wrappedStream, 3);
printBytes(readBytes); // prints 4 5 6
readBytes = ((TryReadInputStream) wrappedStream).tryRead(3); // now we can try read next bytes
printBytes(readBytes); // prints 7 8 9
readBytes = ((TryReadInputStream) wrappedStream).tryRead(3);
printBytes(readBytes); // prints 7 8 9
}
}
, если ваша InputStream
поддерживает использование метки, вы можете mark()
использовать ваш входной поток, а затем reset()
. если ваш InputStrem
не поддерживает отметку, вы можете использовать класс java.io.BufferedInputStream
, чтобы вы могли встраивать свой поток внутри BufferedInputStream
, например
InputStream bufferdInputStream = new BufferedInputStream(yourInputStream);
bufferdInputStream.mark(some_value);
//read your bufferdInputStream
bufferdInputStream.reset();
//read it again
InputStream
(он читается внутренне, как вы упоминаете), тогда вам может быть не повезло. У вас есть доступ кInputStream
до «внутреннего» чтения? Я думаю, что пункт @Ankit был другим и касался API. – Paul Grime 29 May 2014 в 15:18